Add project docs and cleanup uv-generated files
This commit is contained in:
parent
f3bffa40cd
commit
79fde447e9
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.13
|
||||||
575
devdocs/v1/IMPLEMENTATION_PLAN.md
Normal file
575
devdocs/v1/IMPLEMENTATION_PLAN.md
Normal 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
99
devdocs/v1/PRD.md
Normal 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
|
||||||
Loading…
x
Reference in New Issue
Block a user