A professional WBS (Work Breakdown Structure) based task and progress management web application. Organize work into a clear 3-tier hierarchy of major, middle, and minor tasks while tracking planned versus actual effort in real time. Built with a modern React + TypeScript frontend and a robust Express.js + SQLite backend, the application runs entirely on your local network with zero cloud dependencies.
Screenshots coming soon -- Dashboard view, Task hierarchy, and Dark mode.
- 3-tier WBS hierarchy -- Major items, middle items, and minor items organized in a tree structure
- Schedule planning -- Set start date, end date, and planned effort (hours) for each task
- Actual effort recording -- Log daily work hours with optional notes; supports upsert per date
- Automatic progress calculation -- Progress percentage derived from actual vs. planned hours
- Delay detection -- Tasks are flagged as "at risk" or "overdue" based on schedule and progress
- Drag-and-drop reordering -- Change task display order within the same level
- Soft delete -- Safely remove tasks without losing historical data
- Project health metrics -- Total tasks, completed, in-progress, and not-started counts
- Overall progress -- Aggregated progress percentage across the entire project
- Delayed tasks panel -- At-a-glance view of overdue and at-risk items with severity indicators
- Major items overview -- Top-level task summaries with inline progress bars
- Dark mode -- Follows system preference with a manual toggle; persisted in LocalStorage
- Responsive design -- Fully functional on mobile, tablet, and desktop viewports
- Keyboard shortcuts -- Navigate and operate the app without touching the mouse
- Incremental search -- Filter tasks instantly as you type with debounced queries
- Toast notifications -- Non-intrusive feedback for create, update, and delete operations
- Modal dialogs -- Contextual forms for task creation, editing, and actual recording
- Breadcrumb navigation -- Always know where you are in the task hierarchy
- SQLite WAL mode -- Concurrent reads and writes without lock contention
- Optimized queries -- Parent-child joins eliminate N+1 patterns
- Gzip compression -- Reduced payload sizes over the network
- ETag caching -- Conditional responses for unchanged data
- LAN-accessible -- Binds to
0.0.0.0so any device on the same network can connect
The application follows an MVC (Model-View-Controller) pattern on the backend with a clear separation of concerns. The frontend uses a component-based architecture powered by React 19, with custom hooks and context providers for state management.
+------------------------------------------------------+
| Client (Browser) |
| |
| React 19 + TypeScript 5.9 + Vite 7 (Modern SPA) |
| +-----------+ +--------+ +----------+ +------+ |
| | Pages | | Hooks | | Context | | API | |
| | Dashboard | | useApi | | Theme | | tasks| |
| | TaskList | | useTask| | Modal | | dash | |
| | TaskNew | | useDash| | Toast | | actls| |
| | TaskEdit | | useKbd | | | | | |
| | TaskDetail| | useSrch| | | | | |
| +-----------+ +--------+ +----------+ +------+ |
| |
| Legacy Vanilla JS SPA (public/) -- fallback UI |
+---------------------------+---------------------------+
| HTTP / REST API
v
+---------------------------+---------------------------+
| Server (Node.js) |
| |
| Express.js 4.x + Middleware Stack |
| +----------+ +------------+ +------------------+ |
| | Helmet | | Compression| | CORS | Morgan | |
| +----------+ +------------+ +------------------+ |
| |
| Routes Controllers Services |
| +-----------+ +------------+ +--------------+ |
| | /tasks |-->| taskCtrl |-->| taskService | |
| | /actuals |-->| actualCtrl |-->| actualService| |
| | /dashboard|-->| dashCtrl |-->| dashService | |
| +-----------+ +------------+ | progressSvc | |
| +--------------+ |
| | |
| Models v |
| +-----------+ +-------------------------------+ |
| | taskModel |<--| better-sqlite3 (WAL mode) | |
| | actualMdl | | data/budget-tracker.db | |
| | db.js | +-------------------------------+ |
| +-----------+ |
+-------------------------------------------------------+
Client Request
|
v
Express Router --> Controller --> Service --> Model --> SQLite
| | | |
v v v v
Route matching Validation Business logic SQL queries
HTTP response Error handling Prepared stmts
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Node.js 18+ | Server-side JavaScript |
| Framework | Express.js 4.x | HTTP routing and middleware |
| Database | SQLite (better-sqlite3) | Embedded relational database (WAL mode) |
| Security | Helmet 7.x | HTTP security headers |
| CORS | cors 2.x | Cross-origin resource sharing |
| Compression | compression 1.x | Gzip response compression |
| Logging | Morgan 1.x | HTTP request logging |
| Layer | Technology | Purpose |
|---|---|---|
| UI Library | React 19 | Component-based UI |
| Language | TypeScript 5.9 | Static type safety |
| Build Tool | Vite 7.x | Fast HMR and bundling |
| Routing | React Router DOM 7.x | Client-side page navigation |
| Styling | CSS Variables + Custom CSS | Theming and dark mode |
| State | React Context + Custom Hooks | Application state management |
| Layer | Technology | Purpose |
|---|---|---|
| Language | Vanilla JavaScript (ES2020+) | Framework-free SPA |
| Routing | Hash-based router | Client-side navigation |
| State | Custom store + LocalStorage | Lightweight state management |
| Tool | Version | Purpose |
|---|---|---|
| Jest | 29.x | Backend test runner and assertions |
| Supertest | 6.x | HTTP integration testing |
| Vitest | 4.x | Frontend test runner (Vite-native) |
| React Testing Library | 16.x | Component behavior testing |
| Testing Library User Event | 14.x | Simulated user interactions |
- Node.js 18.0.0 or higher
- npm 8.0.0 or higher
# Clone the repository
git clone https://github.com/sohei-t/budget-tracker.git
cd budget-tracker
# Install backend dependencies
npm install
# Install frontend dependencies
cd frontend
npm install
cd ..npm startThe server starts on port 3000, serving the legacy vanilla JS frontend from public/.
In one terminal, start the backend with auto-reload:
npm run devIn another terminal, start the Vite dev server for the React frontend:
cd frontend
npm run devcd frontend
npm run buildThe production build outputs to frontend/dist/. When this directory exists, the Express server automatically serves it instead of the legacy public/ folder.
| Location | URL |
|---|---|
| Local | http://localhost:3000 |
| LAN (any device) | http://<your-ip>:3000 |
All API responses follow a consistent envelope format:
{
"success": true,
"data": { ... },
"meta": { ... }
}| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tasks |
List all top-level (Level 1) tasks |
GET |
/api/tasks/:id |
Get a single task by ID |
GET |
/api/tasks/:id/children |
Get all child tasks of a parent |
POST |
/api/tasks |
Create a new task |
PUT |
/api/tasks/:id |
Update an existing task |
DELETE |
/api/tasks/:id |
Soft-delete a task |
PUT |
/api/tasks/:id/reorder |
Update a task's sort order |
{
"name": "Design Phase",
"description": "UI/UX design tasks",
"parent_id": null,
"planned_start_date": "2025-01-01",
"planned_end_date": "2025-01-31",
"planned_effort_hours": 80,
"progress_mode": "auto",
"status": "in_progress"
}| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tasks/:id/actuals |
Get all actual entries for a task |
POST |
/api/tasks/:id/actuals |
Record a daily actual (upsert by date) |
PUT |
/api/actuals/:id |
Update an actual entry |
DELETE |
/api/actuals/:id |
Delete an actual entry |
{
"work_date": "2025-01-15",
"actual_hours": 6.5,
"notes": "Completed wireframes for dashboard"
}| Method | Endpoint | Description |
|---|---|---|
GET |
/api/dashboard |
Get overall project summary and metrics |
GET |
/api/dashboard/delays |
Get list of delayed and at-risk tasks |
{
"success": true,
"data": {
"total_tasks": 42,
"completed_tasks": 15,
"in_progress_tasks": 20,
"not_started_tasks": 7,
"overall_progress_percent": 48.5,
"overdue_count": 3,
"at_risk_count": 5,
"major_items": [ ... ]
}
}# Run all backend tests
npm test
# Run with coverage report
npm run test:coverage
# Run in watch mode during development
npm run test:watchcd frontend
# Run all frontend tests
npm test
# Run in watch mode
npm run test:watch| Metric | Coverage |
|---|---|
| Statements | 97.92% |
| Branches | 94.05% |
| Functions | 100% |
| Lines | 97.92% |
| Total Tests | 270 passing |
Test suites span unit tests (models, services, controllers, middleware, utilities) and integration tests (full API round-trips with Supertest).
| Shortcut | Action |
|---|---|
G then D |
Navigate to Dashboard |
G then T |
Navigate to Tasks |
N |
Create a new task |
Ctrl + K |
Open search |
Ctrl + D |
Toggle dark mode |
? |
Show keyboard shortcuts dialog |
All shortcuts are disabled when an input field or text area is focused to avoid interference with typing.
budget-tracker/
|-- src/ # Backend (Node.js + Express)
| |-- server.js # Application entry point
| |-- routes/
| | |-- taskRoutes.js # /api/tasks endpoints
| | |-- actualRoutes.js # /api/actuals endpoints
| | +-- dashboardRoutes.js # /api/dashboard endpoints
| |-- controllers/
| | |-- taskController.js # Task request handlers
| | |-- actualController.js # Actual request handlers
| | +-- dashboardController.js
| |-- services/
| | |-- taskService.js # Task business logic
| | |-- actualService.js # Actual business logic
| | |-- dashboardService.js # Dashboard aggregation
| | +-- progressService.js # Progress calculation engine
| |-- models/
| | |-- db.js # SQLite connection (WAL mode)
| | |-- taskModel.js # Task data access
| | +-- actualModel.js # Actual data access
| |-- middleware/
| | +-- errorHandler.js # Centralized error handling
| +-- utils/
| +-- networkUtils.js # LAN IP detection
|
|-- frontend/ # Modern React frontend
| |-- src/
| | |-- main.tsx # React entry point
| | |-- App.tsx # Root component with routing
| | |-- pages/ # Page-level components
| | | |-- DashboardPage.tsx
| | | |-- TaskListPage.tsx
| | | |-- TaskNewPage.tsx
| | | |-- TaskEditPage.tsx
| | | +-- TaskDetailPage.tsx
| | |-- components/ # Reusable UI components
| | | |-- dashboard/ # Dashboard-specific components
| | | |-- task/ # Task-specific components
| | | |-- layout/ # Header, Nav, Shortcuts dialog
| | | |-- search/ # Search bar and results
| | | +-- ui/ # Generic UI primitives
| | |-- hooks/ # Custom React hooks
| | |-- context/ # Theme, Modal, Toast providers
| | |-- api/ # API client modules
| | |-- types/ # TypeScript type definitions
| | +-- styles/ # CSS modules and variables
| |-- vite.config.ts
| +-- tsconfig.json
|
|-- public/ # Legacy vanilla JS frontend (fallback)
| |-- index.html
| |-- css/main.css
| +-- js/
| |-- app.js
| |-- router.js
| |-- store.js
| |-- api.js
| |-- components/
| +-- utils/
|
|-- tests/ # Backend test suites (Jest)
| |-- unit/
| | |-- models/
| | |-- services/
| | |-- controllers/
| | |-- middleware/
| | +-- utils/
| |-- integration/
| +-- helpers/
|
|-- data/ # SQLite database files
| +-- budget-tracker.db
|
|-- package.json
+-- README.md
| Measure | Implementation |
|---|---|
| HTTP Security Headers | Helmet.js with strict CSP directives |
| Cross-Origin Control | CORS middleware with configurable allowed origins |
| SQL Injection Prevention | Prepared statements via better-sqlite3 (parameterized queries only) |
| XSS Protection | Input sanitization and HTML entity escaping; CSP script-src 'self' |
| Input Validation | Server-side validation on all endpoints with typed error responses |
| Request Size Limits | JSON body parser limited to 256 KB |
| Content Security Policy | default-src 'self'; restricted script, style, image, and font sources |
Contributions are welcome. To get started:
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Write tests for your changes and ensure all 270 existing tests pass
- Maintain or improve the current 97.92% test coverage
- Commit your changes with descriptive messages
- Push to your fork and open a Pull Request
Please follow the existing code style:
- Backend: CommonJS modules, JSDoc comments, strict mode
- Frontend: TypeScript with strict mode, functional React components, custom hooks
This project is licensed under the MIT License.
MIT License
Copyright (c) 2024 AI Agent Development System
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.