Add project docs and cleanup uv-generated files

This commit is contained in:
Yuyao Huang 2026-05-08 12:42:50 +08:00
parent f3bffa40cd
commit 79fde447e9
3 changed files with 675 additions and 0 deletions

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.13

View File

@ -0,0 +1,575 @@
# GoalsBreakDown - Implementation Plan
## 1. Project Structure
```
GoalsBreakDown/
├── app.py # Flask application entry point
├── config.py # Configuration constants
├── database.py # TinyDB initialization and operations
├── auth.py # Authentication helpers
├── requirements.txt # Python dependencies
├── data/ # TinyDB data directory
│ └── db.json # TinyDB database file
├── static/
│ ├── css/
│ │ ├── style.css # Global styles
│ │ ├── goals.css # Goal page styles
│ │ └── tasks.css # Task page styles
│ └── js/
│ ├── api.js # API client utilities
│ ├── auth.js # Authentication logic
│ ├── goals.js # Goal page logic
│ ├── tasks.js # Task page logic
│ └── sortable.min.js # Drag-and-drop library
└── templates/
├── base.html # Base template with navigation
├── login.html # Login page
├── register.html # Registration page
├── goals.html # Goal CRUD page
└── tasks.html # Task CRUD page with scroll view
```
## 2. Dependencies & Environment Management
### 2.1 Environment Setup (uv)
```bash
# Initialize project with uv
uv init --no-readme
# Add dependencies
uv add flask tinydb bcrypt
# Run the application
uv run python app.py
```
### 2.2 requirements.txt (managed by uv)
```
flask==3.0.0
tinydb==4.8.0
bcrypt==4.1.2
```
### 2.3 pyproject.toml (auto-generated by uv)
```toml
[project]
name = "goalsbreakdown"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"flask>=3.0.0",
"tinydb>=4.8.0",
"bcrypt>=4.1.2",
]
```
## 3. Database Schema (TinyDB)
### 3.1 Collections (TinyDB Tables)
**users** table:
```json
{
"user_id": 1,
"username": "admin",
"password_hash": "$2b$12$...",
"role": "admin",
"max_goals": 10
}
```
**goals** table:
```json
{
"goal_id": 1,
"user_id": 1,
"title": "Learn Python",
"activated": true
}
```
**tasks** table:
```json
{
"task_id": 1,
"goal_id": 1,
"title": "Complete basics",
"desc": "Learn variables, loops, functions",
"status": "doing",
"start_time": "2026-05-08T10:00:00",
"finished_time": null,
"order": 1.0
}
```
### 3.2 Database Initialization
```python
# database.py responsibilities:
# - Initialize TinyDB with data/db.json
# - Create tables: users, goals, tasks
# - Seed admin user on first run (username: admin, password: admin123)
# - Provide CRUD helper functions for each table
```
## 4. API Endpoints
### 4.1 Authentication
| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| POST | `/api/auth/register` | Register new user | No |
| POST | `/api/auth/login` | Login user | No |
| POST | `/api/auth/logout` | Logout user | Yes |
| GET | `/api/auth/me` | Get current user info | Yes |
**POST /api/auth/register**
- Request: `{ "username": str, "password": str }`
- Response: `{ "success": bool, "message": str, "user_id": int }`
- Validation: username unique, password min 6 chars
- Default: role="user", max_goals=5
**POST /api/auth/login**
- Request: `{ "username": str, "password": str }`
- Response: `{ "success": bool, "message": str, "user": { user object } }`
**GET /api/auth/me**
- Response: `{ "user_id": int, "username": str, "role": str, "max_goals": int }`
### 4.2 Goals
| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/api/goals` | List all goals for current user | Yes |
| POST | `/api/goals` | Create new goal | Yes |
| PUT | `/api/goals/<goal_id>` | Update goal | Yes |
| DELETE | `/api/goals/<goal_id>` | Delete goal | Yes |
| PATCH | `/api/goals/<goal_id>/toggle` | Toggle activated status | Yes |
**GET /api/goals**
- Response: `[ { goal objects } ]`
- Note: Returns all goals (activated and deactivated)
**POST /api/goals**
- Request: `{ "title": str }`
- Response: `{ "success": bool, "goal_id": int, "message": str }`
- Validation: Check user's max_goals limit before creation
**PUT /api/goals/<goal_id>**
- Request: `{ "title": str, "activated": bool }`
- Response: `{ "success": bool, "message": str }`
- Validation: Goal must belong to current user
**DELETE /api/goals/<goal_id>**
- Response: `{ "success": bool, "message": str }`
- Cascade: Delete all tasks associated with this goal
**PATCH /api/goals/<goal_id>/toggle**
- Response: `{ "success": bool, "activated": bool }`
### 4.3 Tasks
| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/api/tasks` | List all tasks (optionally filtered by goal) | Yes |
| POST | `/api/tasks` | Create new task | Yes |
| PUT | `/api/tasks/<task_id>` | Update task | Yes |
| DELETE | `/api/tasks/<task_id>` | Delete task | Yes |
| PATCH | `/api/tasks/<task_id>/status` | Update task status | Yes |
| PATCH | `/api/tasks/<task_id>/order` | Update task order | Yes |
**GET /api/tasks**
- Query params: `?goal_id=<int>` (optional filter)
- Response: `[ { task objects } ]`
- Sorting: Unfinished by `order` ASC, finished by `finished_time` DESC
**POST /api/tasks**
- Request: `{ "goal_id": int, "title": str, "desc": str (optional) }`
- Response: `{ "success": bool, "task_id": int, "message": str }`
- Validation: goal_id must belong to current user and be activated
**PUT /api/tasks/<task_id>**
- Request: `{ "title": str, "desc": str }`
- Response: `{ "success": bool, "message": str }`
**DELETE /api/tasks/<task_id>**
- Response: `{ "success": bool, "message": str }`
**PATCH /api/tasks/<task_id>/status**
- Request: `{ "status": "todo" | "doing" | "pending" | "done" }`
- Response: `{ "success": bool, "message": str }`
- Business logic:
- If status="doing": Check no other "doing" task exists for this goal
- If status="done": Set `finished_time` to current timestamp
- If status changed from "done" to other: Set `finished_time` to null
**PATCH /api/tasks/<task_id>/order**
- Request: `{ "order": float }`
- Response: `{ "success": bool, "message": str }`
- Note: Used for drag-and-drop reordering
### 4.4 Admin
| Method | Endpoint | Description | Auth Required |
|--------|----------|-------------|---------------|
| GET | `/api/admin/users` | List all users | Yes (admin) |
| PUT | `/api/admin/users/<user_id>` | Update user settings | Yes (admin) |
**GET /api/admin/users**
- Response: `[ { user_id, username, role, max_goals } ]`
**PUT /api/admin/users/<user_id>**
- Request: `{ "max_goals": int, "role": str (optional) }`
- Response: `{ "success": bool, "message": str }`
## 5. Frontend Components
### 5.1 Page: Login (`/login`)
**Components:**
- Username input field
- Password input field
- Login button
- Link to registration page
**Flow:**
1. User enters credentials
2. POST to `/api/auth/login`
3. On success: redirect to `/goals`
4. On failure: show error message
### 5.2 Page: Register (`/register`)
**Components:**
- Username input field
- Password input field
- Confirm password input field
- Register button
- Link to login page
**Flow:**
1. User enters credentials
2. POST to `/api/auth/register`
3. On success: auto-login and redirect to `/goals`
4. On failure: show error message
### 5.3 Page: Goals (`/goals`)
**Layout:**
```
+------------------------------------------+
| Navigation: [Goals] [Tasks] [Logout] |
+------------------------------------------+
| [Create Goal Button] |
+------------------------------------------+
| Goal List: |
| +--------------------------------------+ |
| | Goal Title | [Activate/Deactivate] |
| | | [Edit] [Delete] | |
| +--------------------------------------+ |
| | Goal Title | [Activate/Deactivate] |
| | | [Edit] [Delete] | |
| +--------------------------------------+ |
+------------------------------------------+
```
**Components:**
- Goal list (table or card layout)
- Create goal modal/form
- Edit goal modal/form
- Activate/Deactivate toggle button
- Delete confirmation dialog
**Interactions:**
- Click "Create Goal" → opens modal → submit → refresh list
- Click "Edit" → opens modal with pre-filled data → submit → refresh
- Click toggle → PATCH request → update UI
- Click "Delete" → confirmation → DELETE request → refresh
### 5.4 Page: Tasks (`/tasks`)
**Layout:**
```
+--------------------------------------------------+
| Navigation: [Goals] [Tasks] [Logout] |
+--------------------------------------------------+
| Goal Selector: [Dropdown of activated goals] |
+--------------------------------------------------+
| Task Scroll View (Time Picker Style): |
| |
| +---------------------------+ |
| | Task N-2 (todo) | [faded] |
| +---------------------------+ |
| | Task N-1 (todo) | [dimmed] |
| +---------------------------+ |
| | >>> Task N (doing) <<< | [HIGHLIGHTED] |
| +---------------------------+ |
| | Task N+1 (todo) | [normal] |
| +---------------------------+ |
| | Task N+2 (todo) | [faded] |
| +---------------------------+ |
| |
| [Create Task Button] |
+--------------------------------------------------+
| Side Panel (when task selected): |
| +----------------------------------------------+ |
| | Task Title: [____________] | |
| | Description: [____________] | |
| | Status: [Dropdown: todo/doing/pending/done] | |
| | [Save] [Delete] | |
| +----------------------------------------------+ |
+--------------------------------------------------+
```
**Components:**
- Goal selector dropdown (filters tasks by selected goal)
- Scroll view container with centered focus area
- Task items (draggable for unfinished tasks)
- Create task modal/form
- Side panel for task editing
- Status change buttons
**Scroll View Implementation:**
- Container with `overflow-y: auto`
- Center item highlighted with CSS
- Scroll to center the "doing" task on load
- Use SortableJS for drag-and-drop reordering
- Only unfinished tasks are draggable
- Finished tasks shown in separate section below (ordered by finished_time)
**Drag-and-Drop Flow:**
1. User drags task item
2. SortableJS handles reordering
3. On drop: calculate new `order` value
4. PATCH `/api/tasks/<task_id>/order`
5. Update local state
**Side Panel Flow:**
1. User clicks task item
2. Side panel slides in from right
3. Panel shows editable fields
4. User modifies and clicks "Save"
5. PUT request to update task
6. Panel closes or stays open for further edits
## 6. Authentication & Session Management
### 6.1 Session Storage
- Use Flask's built-in session management
- Store `user_id` and `username` in session
- Session cookie is HTTP-only and secure
### 6.2 Password Handling
- Hash passwords with bcrypt before storage
- Verify passwords with bcrypt.checkpw()
- Never store plain text passwords
### 6.3 Middleware
- `@login_required` decorator for protected routes
- `@admin_required` decorator for admin routes
- Check user ownership on goal/task operations
## 7. Business Logic Implementation
### 7.1 Goal Limit Enforcement
```python
def can_create_goal(user_id):
user = get_user(user_id)
goal_count = count_goals_by_user(user_id)
return goal_count < user.max_goals
```
### 7.2 Focus Rule Enforcement
```python
def set_task_to_doing(task_id, goal_id):
# Check if another task is already "doing"
doing_task = find_task(goal_id, status="doing")
if doing_task and doing_task.task_id != task_id:
# Optionally auto-change old doing to todo
update_task_status(doing_task.task_id, "todo")
update_task_status(task_id, "doing")
```
### 7.3 Task Ordering
```python
# Unfinished tasks: ordered by 'order' field (ascending)
# Finished tasks: ordered by 'finished_time' (descending)
def get_tasks_for_goal(goal_id):
unfinished = query(status != "done").order_by("order")
finished = query(status == "done").order_by("finished_time", reverse=True)
return unfinished + finished
```
### 7.4 Drag-and-Drop Order Calculation
```python
def reorder_task(task_id, new_position, siblings):
# Use real numbers to avoid reordering all tasks
prev_order = siblings[new_position - 1].order if new_position > 0 else 0
next_order = siblings[new_position + 1].order if new_position < len(siblings) - 1 else prev_order + 2
new_order = (prev_order + next_order) / 2
update_task_order(task_id, new_order)
```
## 8. Development Phases
### Phase 1: Foundation (Setup & Auth)
**Setup:**
```bash
uv init --no-readme
uv add flask tinydb bcrypt
```
**Files to create:**
- `pyproject.toml` (auto-generated by uv)
- `uv.lock` (auto-generated by uv)
- `config.py`
- `database.py`
- `auth.py`
- `app.py` (basic setup)
- `templates/login.html`
- `templates/register.html`
- `static/css/style.css`
- `static/js/api.js`
- `static/js/auth.js`
**Deliverables:**
- Flask app running on localhost:5000 (`uv run python app.py`)
- User registration with validation
- User login/logout with session management
- Password hashing with bcrypt
- Admin user seeded on first run
### Phase 2: Goal CRUD
**Files to create:**
- `templates/goals.html`
- `static/css/goals.css`
- `static/js/goals.js`
**API endpoints to implement:**
- GET/POST/PUT/DELETE `/api/goals`
- PATCH `/api/goals/<goal_id>/toggle`
**Deliverables:**
- Goal list page with all CRUD operations
- Activate/deactivate toggle
- Goal limit enforcement
- Delete confirmation dialog
### Phase 3: Task CRUD (Basic)
**Files to create:**
- `templates/tasks.html`
- `static/css/tasks.css`
- `static/js/tasks.js`
**API endpoints to implement:**
- GET/POST/PUT/DELETE `/api/tasks`
- PATCH `/api/tasks/<task_id>/status`
**Deliverables:**
- Task list filtered by goal
- Task creation with goal selection
- Task editing in side panel
- Status change with focus rule enforcement
- Finished time tracking
### Phase 4: Task Ordering & Drag-Drop
**Files to modify:**
- `static/js/tasks.js` (add drag-drop logic)
- `static/css/tasks.css` (add scroll view styles)
**API endpoints to implement:**
- PATCH `/api/tasks/<task_id>/order`
**Deliverables:**
- Scroll view with centered focus
- Highlighted "doing" task
- Drag-and-drop reordering with SortableJS
- Order calculation with real numbers
- Finished tasks section (sorted by finished_time)
### Phase 5: Admin Features
**Files to create:**
- Admin section in goals.html or separate page
- `static/js/admin.js` (if needed)
**API endpoints to implement:**
- GET `/api/admin/users`
- PUT `/api/admin/users/<user_id>`
**Deliverables:**
- Admin can view all users
- Admin can modify user's max_goals
- Admin can change user role
### Phase 6: Polish & Testing
**Tasks:**
- Error handling and user feedback
- Loading states and animations
- Responsive design for mobile
- Input validation on frontend
- Edge case handling (empty states, etc.)
- Manual testing of all flows
## 9. Configuration (config.py)
```python
# Database
DB_PATH = "data/db.json"
# Default admin credentials
DEFAULT_ADMIN_USERNAME = "admin"
DEFAULT_ADMIN_PASSWORD = "admin123"
# Default user settings
DEFAULT_MAX_GOALS = 5
# Flask
SECRET_KEY = "your-secret-key-here" # Change in production
DEBUG = True
HOST = "0.0.0.0"
PORT = 5000
```
## 10. Error Handling
### API Error Responses
```json
{
"success": false,
"message": "Error description",
"error_code": "VALIDATION_ERROR | NOT_FOUND | UNAUTHORIZED | FORBIDDEN"
}
```
### HTTP Status Codes
- 200: Success
- 201: Created
- 400: Bad Request (validation error)
- 401: Unauthorized (not logged in)
- 403: Forbidden (insufficient permissions)
- 404: Not Found
- 500: Internal Server Error
## 11. Security Considerations
- Password hashing with bcrypt (cost factor 12)
- Session-based authentication with HTTP-only cookies
- CSRF protection (Flask-WTF or manual token)
- Input sanitization (prevent XSS)
- SQL injection not applicable (TinyDB), but validate all inputs
- Rate limiting on auth endpoints (optional)
- HTTPS in production
## 12. Future Enhancements (Out of Scope)
- Task categories/tags
- Task priority levels
- Task search and filtering
- Export/import data
- Email notifications
- Task templates
- Progress tracking per goal
- Mobile app

99
devdocs/v1/PRD.md Normal file
View File

@ -0,0 +1,99 @@
Task Table:
- task_id: primary key
- title: str (required, non-empty)
- desc: str (optional, can be empty)
- status: enum{todo, doing, pending, done}
- goal_id: foreign key to goal table (required, each task belongs to exactly one goal)
- start_time: timestamp or None
- finished_time: timestamp or None
- order: float (for ordering unfinished tasks)
Goal Table:
- goal_id: primary key
- title: str (required, non-empty)
- activated: bool (deactivated goals and their tasks are hidden from Task Page GUI)
User Table:
- user_id: primary key
- username: str (unique, required)
- password_hash: str (required)
- role: enum{user, admin} (admin can configure goal limits)
- max_goals: int (maximum goals this user can create, configurable by admin)
GUI:
Page 1. Goal CRUD
- List all goals with activate/deactivate toggle
- Create, edit, delete goals
- Shows goal title and activation status
Page 2. Task CRUD
- Tasks are grouped by their parent goal
- Only activated goals and their tasks are visible
- Focus Rule: Each goal highlights its single "doing" task prominently
- Scroll View: Tasks displayed in a scrollable selector (like time picker widget)
- Center/focus area shows current task
- Unfinished tasks ordered by `order` field
- Finished tasks ordered by `finished_time` (most recent first)
- Drag-and-drop reordering for unfinished tasks
- Side Panel: Clicking a task opens a side panel for editing task details
- Task status transitions:
- User manually switches task to "doing" (only one per goal)
- When "doing" task is completed, status becomes "done" (no auto-promotion)
- User must manually set next task to "doing"
Constraints:
1. **Focus Rule**: Under each goal, there should be only one "doing" task. The GUI must visually emphasize the "doing" task for each goal.
2. **Ordering Rule**:
- Finished tasks are ordered by `finished_time` (descending)
- Unfinished tasks are ordered by `order` field (ascending)
- Users can reorder unfinished tasks via drag-and-drop
3. **Scroll View**: Tasks are displayed in a linear scroll view selector (similar to HH:mm time picker). The current task is centered/focused. Users can drag-and-drop to reorder future tasks.
4. **Task-Good Relationship**: Tasks cannot exist without a goal. Each task belongs to exactly one goal.
5. **Goal Limit**: Each user can only create up to their `max_goals` limit. Admin can modify this limit per user.
6. **Visibility**: Deactivated goals and all their tasks are hidden from the Task Page.
Business Rules:
- Task title is required and cannot be empty
- Goal title is required and cannot be empty
- Tasks can be deleted (order values don't need to be continuous)
- Goals can be activated/deactivated (only affects GUI visibility)
- Only one "doing" task per goal at any time
- Users must manually set a task to "doing" status
- Simple user registration with username/password
Tech Stack:
- Backend: Python + Flask (lightweight, good for small apps)
- Frontend: Vanilla JS + HTML/CSS (simple, no build step needed)
- Database: TinyDB (single JSON file, perfect for this scale)
- Authentication: Session-based with password hashing (bcrypt)
- Drag-and-drop: HTML5 Drag and Drop API or SortableJS
Multi-User Features:
- User registration and login
- Each user has isolated goals and tasks
- Admin user can:
- Configure `max_goals_per_user` limit
- View all users (optional)
- Regular users can only see/manage their own data