suhail commited on
Commit
9eafd9f
·
1 Parent(s): 20ee17b
Files changed (46) hide show
  1. specs/001-auth-security/TESTING.md +353 -0
  2. specs/001-auth-security/checklists/requirements.md +44 -0
  3. specs/001-auth-security/contracts/auth-endpoints.yaml +345 -0
  4. specs/001-auth-security/contracts/jwt-schema.yaml +321 -0
  5. specs/001-auth-security/data-model.md +242 -0
  6. specs/001-auth-security/plan.md +166 -0
  7. specs/001-auth-security/quickstart.md +489 -0
  8. specs/001-auth-security/research.md +345 -0
  9. specs/001-auth-security/spec.md +162 -0
  10. specs/001-auth-security/tasks.md +237 -0
  11. specs/001-openai-agent-mcp-tools/checklists/requirements.md +58 -0
  12. specs/001-openai-agent-mcp-tools/contracts/add_task.json +69 -0
  13. specs/001-openai-agent-mcp-tools/contracts/complete_task.json +62 -0
  14. specs/001-openai-agent-mcp-tools/contracts/delete_task.json +40 -0
  15. specs/001-openai-agent-mcp-tools/contracts/list_tasks.json +62 -0
  16. specs/001-openai-agent-mcp-tools/contracts/update_task.json +97 -0
  17. specs/001-openai-agent-mcp-tools/data-model.md +664 -0
  18. specs/001-openai-agent-mcp-tools/plan.md +747 -0
  19. specs/001-openai-agent-mcp-tools/quickstart.md +521 -0
  20. specs/001-openai-agent-mcp-tools/research.md +758 -0
  21. specs/001-openai-agent-mcp-tools/spec.md +248 -0
  22. specs/001-openai-agent-mcp-tools/tasks.md +307 -0
  23. specs/001-task-crud/checklists/requirements.md +53 -0
  24. specs/001-task-crud/contracts/README.md +355 -0
  25. specs/001-task-crud/contracts/tasks-api.yaml +476 -0
  26. specs/001-task-crud/data-model.md +560 -0
  27. specs/001-task-crud/plan.md +515 -0
  28. specs/001-task-crud/quickstart.md +460 -0
  29. specs/001-task-crud/research.md +373 -0
  30. specs/001-task-crud/spec.md +202 -0
  31. specs/001-task-crud/tasks.md +275 -0
  32. specs/001-todo-ai-chatbot/contracts/chat-api.yaml +364 -0
  33. specs/001-todo-ai-chatbot/data-model.md +476 -0
  34. specs/001-todo-ai-chatbot/plan.md +386 -0
  35. specs/001-todo-ai-chatbot/quickstart.md +729 -0
  36. specs/001-todo-ai-chatbot/research.md +398 -0
  37. specs/001-todo-ai-chatbot/spec.md +278 -0
  38. specs/001-todo-ai-chatbot/tasks.md +298 -0
  39. specs/002-fullstack-ui-integration/checklists/requirements.md +98 -0
  40. specs/002-fullstack-ui-integration/contracts/existing-api-reference.yaml +611 -0
  41. specs/002-fullstack-ui-integration/data-model.md +280 -0
  42. specs/002-fullstack-ui-integration/plan.md +458 -0
  43. specs/002-fullstack-ui-integration/quickstart.md +458 -0
  44. specs/002-fullstack-ui-integration/research.md +392 -0
  45. specs/002-fullstack-ui-integration/spec.md +240 -0
  46. specs/002-fullstack-ui-integration/tasks.md +286 -0
specs/001-auth-security/TESTING.md ADDED
@@ -0,0 +1,353 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Authentication & API Security - Testing Guide
2
+
3
+ **Feature**: Authentication & API Security (Spec 001)
4
+ **Date**: 2026-01-09
5
+ **Status**: Ready for Testing
6
+
7
+ ## Prerequisites
8
+
9
+ Before testing, ensure:
10
+
11
+ 1. **Backend is running**:
12
+ ```bash
13
+ cd backend
14
+ python -m uvicorn src.main:app --reload
15
+ # Should be running at http://localhost:8000
16
+ ```
17
+
18
+ 2. **Database migrations applied**:
19
+ ```bash
20
+ cd backend
21
+ python -m alembic upgrade head
22
+ ```
23
+
24
+ 3. **Frontend is running**:
25
+ ```bash
26
+ cd frontend
27
+ npm run dev
28
+ # Should be running at http://localhost:3000
29
+ ```
30
+
31
+ 4. **Environment variables configured**:
32
+ - `backend/.env` has `BETTER_AUTH_SECRET`
33
+ - `frontend/.env.local` has same `BETTER_AUTH_SECRET`
34
+ - Both secrets match exactly
35
+
36
+ ## Test Suite
37
+
38
+ ### T048: Test Signup Flow End-to-End
39
+
40
+ **Objective**: Verify new users can create accounts and data is stored correctly in database
41
+
42
+ **Steps**:
43
+
44
+ 1. **Navigate to signup page**:
45
+ - Open browser to `http://localhost:3000/auth/signup`
46
+ - Verify signup form is displayed with email, password, and name fields
47
+
48
+ 2. **Test validation errors**:
49
+ - Try submitting with empty fields → Should show validation errors
50
+ - Try weak password (e.g., "pass") → Should show "Password must be at least 8 characters"
51
+ - Try invalid email (e.g., "notanemail") → Should show email format error
52
+
53
+ 3. **Create valid account**:
54
+ - Email: `test1@example.com`
55
+ - Password: `SecurePass123`
56
+ - Name: `Test User 1`
57
+ - Click "Sign Up"
58
+ - **Expected**: Success message, redirect to signin page
59
+
60
+ 4. **Verify in database**:
61
+ ```bash
62
+ # Connect to your database and run:
63
+ SELECT id, email, name, password_hash, created_at FROM users WHERE email = 'test1@example.com';
64
+ ```
65
+ - **Expected**: User record exists
66
+ - **Expected**: `password_hash` is bcrypt hash (starts with `$2b$`)
67
+ - **Expected**: `created_at` timestamp is recent
68
+
69
+ 5. **Test duplicate email**:
70
+ - Try signing up again with `test1@example.com`
71
+ - **Expected**: 409 Conflict error "Email already registered"
72
+
73
+ **Pass Criteria**:
74
+ - ✅ Form validation works correctly
75
+ - ✅ Valid signup creates user in database
76
+ - ✅ Password is hashed (not stored in plain text)
77
+ - ✅ Duplicate email is rejected with 409 error
78
+ - ✅ User is redirected to signin after successful signup
79
+
80
+ ---
81
+
82
+ ### T049: Test Signin Flow End-to-End
83
+
84
+ **Objective**: Verify users can authenticate and receive valid JWT tokens
85
+
86
+ **Steps**:
87
+
88
+ 1. **Navigate to signin page**:
89
+ - Open browser to `http://localhost:3000/auth/signin`
90
+ - Verify signin form is displayed
91
+
92
+ 2. **Test invalid credentials**:
93
+ - Email: `test1@example.com`
94
+ - Password: `WrongPassword123`
95
+ - Click "Sign In"
96
+ - **Expected**: 401 error "Invalid email or password"
97
+
98
+ 3. **Test valid credentials**:
99
+ - Email: `test1@example.com`
100
+ - Password: `SecurePass123`
101
+ - Click "Sign In"
102
+ - **Expected**: Success, redirect to home page (`/`)
103
+
104
+ 4. **Verify JWT token**:
105
+ - Open browser DevTools → Application → Local Storage → `http://localhost:3000`
106
+ - Find `auth_session` key
107
+ - **Expected**: JSON object with `token` and `user` fields
108
+ - Copy the token value
109
+
110
+ 5. **Decode JWT token** (use jwt.io or command line):
111
+ ```bash
112
+ # Using Python
113
+ python -c "import jwt; print(jwt.decode('YOUR_TOKEN_HERE', options={'verify_signature': False}))"
114
+ ```
115
+ - **Expected payload**:
116
+ ```json
117
+ {
118
+ "sub": "1", // User ID
119
+ "email": "test1@example.com",
120
+ "iat": 1704067200, // Issued at timestamp
121
+ "exp": 1704672000, // Expiration (7 days later)
122
+ "iss": "better-auth"
123
+ }
124
+ ```
125
+
126
+ 6. **Verify session persistence**:
127
+ - Refresh the page
128
+ - **Expected**: Still logged in (no redirect to signin)
129
+ - **Expected**: User name displayed in header
130
+
131
+ 7. **Test signout**:
132
+ - Click "Sign Out" button in header
133
+ - **Expected**: Redirect to signin page
134
+ - **Expected**: localStorage `auth_session` is cleared
135
+
136
+ **Pass Criteria**:
137
+ - ✅ Invalid credentials return 401 error
138
+ - ✅ Valid credentials return JWT token
139
+ - ✅ Token contains correct user_id, email, and expiration
140
+ - ✅ Token expiration is 7 days from issuance
141
+ - ✅ Session persists across page refreshes
142
+ - ✅ Signout clears session and redirects
143
+
144
+ ---
145
+
146
+ ### T050: Test Protected API Access
147
+
148
+ **Objective**: Verify API endpoints require valid JWT tokens and reject invalid tokens
149
+
150
+ **Steps**:
151
+
152
+ 1. **Test unauthenticated request**:
153
+ ```bash
154
+ # Try to fetch tasks without token
155
+ curl http://localhost:8000/api/tasks
156
+ ```
157
+ - **Expected**: 401 Unauthorized
158
+ - **Expected**: Response body: `{"detail": "Not authenticated"}`
159
+
160
+ 2. **Test with valid token**:
161
+ - Sign in to get a valid token (from T049)
162
+ - Copy token from localStorage
163
+ ```bash
164
+ # Replace YOUR_TOKEN with actual token
165
+ curl http://localhost:8000/api/tasks \
166
+ -H "Authorization: Bearer YOUR_TOKEN"
167
+ ```
168
+ - **Expected**: 200 OK
169
+ - **Expected**: Returns task list (may be empty)
170
+
171
+ 3. **Test with invalid token**:
172
+ ```bash
173
+ curl http://localhost:8000/api/tasks \
174
+ -H "Authorization: Bearer invalid_token_here"
175
+ ```
176
+ - **Expected**: 401 Unauthorized
177
+ - **Expected**: Error message about invalid token
178
+
179
+ 4. **Test with expired token**:
180
+ - Manually create an expired token or wait 7 days (not practical)
181
+ - Alternative: Temporarily change `JWT_EXPIRATION_DAYS=0` in backend/.env, restart backend, get new token, wait 1 minute
182
+ ```bash
183
+ curl http://localhost:8000/api/tasks \
184
+ -H "Authorization: Bearer EXPIRED_TOKEN"
185
+ ```
186
+ - **Expected**: 401 Unauthorized
187
+ - **Expected**: Error code `TOKEN_EXPIRED`
188
+
189
+ 5. **Test frontend automatic redirect**:
190
+ - In browser, manually edit localStorage to set invalid token
191
+ - Try to access home page (`/`)
192
+ - **Expected**: Automatic redirect to `/auth/signin`
193
+
194
+ 6. **Test all protected endpoints**:
195
+ - With valid token, test:
196
+ - `GET /api/tasks` → 200 OK
197
+ - `POST /api/tasks` → 201 Created
198
+ - `GET /api/tasks/{id}` → 200 OK
199
+ - `PATCH /api/tasks/{id}` → 200 OK
200
+ - `DELETE /api/tasks/{id}` → 204 No Content
201
+ - `GET /api/auth/me` → 200 OK
202
+
203
+ **Pass Criteria**:
204
+ - ✅ Requests without token return 401
205
+ - ✅ Requests with valid token succeed
206
+ - ✅ Requests with invalid token return 401
207
+ - ✅ Requests with expired token return 401 with TOKEN_EXPIRED
208
+ - ✅ Frontend automatically redirects on 401
209
+ - ✅ All task endpoints require authentication
210
+
211
+ ---
212
+
213
+ ### T051: Test User Data Isolation
214
+
215
+ **Objective**: Verify users can only access their own tasks, not other users' tasks
216
+
217
+ **Steps**:
218
+
219
+ 1. **Create two user accounts**:
220
+ - User A: `usera@example.com` / `PasswordA123`
221
+ - User B: `userb@example.com` / `PasswordB123`
222
+
223
+ 2. **Sign in as User A**:
224
+ - Navigate to `/auth/signin`
225
+ - Sign in with User A credentials
226
+ - Copy User A's JWT token from localStorage
227
+
228
+ 3. **Create tasks as User A**:
229
+ - Create 2-3 tasks through the UI
230
+ - Note the task IDs (check Network tab or database)
231
+
232
+ 4. **Sign out and sign in as User B**:
233
+ - Click "Sign Out"
234
+ - Sign in with User B credentials
235
+ - Copy User B's JWT token
236
+
237
+ 5. **Create tasks as User B**:
238
+ - Create 2-3 different tasks through the UI
239
+
240
+ 6. **Verify User B cannot see User A's tasks**:
241
+ - Check the task list in UI
242
+ - **Expected**: Only User B's tasks are visible
243
+ - **Expected**: User A's tasks are NOT visible
244
+
245
+ 7. **Test API-level isolation**:
246
+ ```bash
247
+ # Get User A's task ID from database
248
+ # Try to access it with User B's token
249
+ curl http://localhost:8000/api/tasks/USER_A_TASK_ID \
250
+ -H "Authorization: Bearer USER_B_TOKEN"
251
+ ```
252
+ - **Expected**: 404 Not Found (task doesn't exist for User B)
253
+
254
+ 8. **Test cross-user modification attempt**:
255
+ ```bash
256
+ # Try to update User A's task with User B's token
257
+ curl -X PATCH http://localhost:8000/api/tasks/USER_A_TASK_ID \
258
+ -H "Authorization: Bearer USER_B_TOKEN" \
259
+ -H "Content-Type: application/json" \
260
+ -d '{"completed": true}'
261
+ ```
262
+ - **Expected**: 404 Not Found
263
+
264
+ 9. **Test cross-user deletion attempt**:
265
+ ```bash
266
+ # Try to delete User A's task with User B's token
267
+ curl -X DELETE http://localhost:8000/api/tasks/USER_A_TASK_ID \
268
+ -H "Authorization: Bearer USER_B_TOKEN"
269
+ ```
270
+ - **Expected**: 404 Not Found
271
+
272
+ 10. **Verify in database**:
273
+ ```sql
274
+ -- Check that tasks are correctly associated with users
275
+ SELECT id, user_id, title FROM tasks ORDER BY user_id, id;
276
+ ```
277
+ - **Expected**: User A's tasks have `user_id = 1`
278
+ - **Expected**: User B's tasks have `user_id = 2`
279
+ - **Expected**: No cross-contamination
280
+
281
+ **Pass Criteria**:
282
+ - ✅ User A can only see their own tasks
283
+ - ✅ User B can only see their own tasks
284
+ - ✅ User B cannot access User A's tasks via API (404)
285
+ - ✅ User B cannot modify User A's tasks (404)
286
+ - ✅ User B cannot delete User A's tasks (404)
287
+ - ✅ Database correctly associates tasks with user_id
288
+ - ✅ All queries are filtered by authenticated user
289
+
290
+ ---
291
+
292
+ ## Test Results Summary
293
+
294
+ After completing all tests, fill in the results:
295
+
296
+ | Test | Status | Notes |
297
+ |------|--------|-------|
298
+ | T048: Signup Flow | ⬜ Pass / ⬜ Fail | |
299
+ | T049: Signin Flow | ⬜ Pass / ⬜ Fail | |
300
+ | T050: Protected API | ⬜ Pass / ⬜ Fail | |
301
+ | T051: User Isolation | ⬜ Pass / ⬜ Fail | |
302
+
303
+ ## Common Issues & Troubleshooting
304
+
305
+ ### Issue: "BETTER_AUTH_SECRET not found"
306
+ - **Cause**: Environment variable not set
307
+ - **Fix**: Ensure both `backend/.env` and `frontend/.env.local` have `BETTER_AUTH_SECRET`
308
+ - **Verify**: Secrets must be identical in both files
309
+
310
+ ### Issue: "Token signature verification failed"
311
+ - **Cause**: Frontend and backend have different secrets
312
+ - **Fix**: Copy exact same secret to both .env files
313
+ - **Verify**: Run `grep BETTER_AUTH_SECRET backend/.env frontend/.env.local`
314
+
315
+ ### Issue: "401 Unauthorized" on all requests
316
+ - **Cause**: Token not being sent or invalid
317
+ - **Fix**: Check localStorage has valid token, check Authorization header in Network tab
318
+
319
+ ### Issue: "User can see other users' tasks"
320
+ - **Cause**: Missing user_id filter in queries
321
+ - **Fix**: Verify `get_current_user` dependency is applied to all task endpoints
322
+ - **Check**: `backend/src/api/routes/tasks.py` should use `current_user_id = Depends(get_current_user)`
323
+
324
+ ### Issue: Database migration errors
325
+ - **Cause**: Migration not applied or database out of sync
326
+ - **Fix**: Run `python -m alembic upgrade head` in backend directory
327
+
328
+ ## Security Checklist
329
+
330
+ After testing, verify:
331
+
332
+ - [ ] Passwords are hashed (never stored in plain text)
333
+ - [ ] JWT tokens expire after 7 days
334
+ - [ ] Invalid tokens are rejected with 401
335
+ - [ ] Expired tokens are rejected with 401
336
+ - [ ] Users cannot access other users' data
337
+ - [ ] All task endpoints require authentication
338
+ - [ ] BETTER_AUTH_SECRET is not committed to git
339
+ - [ ] Error messages don't leak sensitive information
340
+ - [ ] Token signature is verified on every request
341
+
342
+ ## Next Steps
343
+
344
+ Once all tests pass:
345
+
346
+ 1. Mark tasks T048-T051 as complete in `tasks.md`
347
+ 2. Create git commit with authentication implementation
348
+ 3. Consider additional security enhancements:
349
+ - Rate limiting on auth endpoints
350
+ - Account lockout after failed attempts
351
+ - Password reset functionality
352
+ - Refresh token mechanism
353
+ - Multi-factor authentication (MFA)
specs/001-auth-security/checklists/requirements.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Specification Quality Checklist: Authentication & API Security
2
+
3
+ **Purpose**: Validate specification completeness and quality before proceeding to planning
4
+ **Created**: 2026-01-09
5
+ **Feature**: [spec.md](../spec.md)
6
+
7
+ ## Content Quality
8
+
9
+ - [x] No implementation details (languages, frameworks, APIs) - Technologies mentioned are from user-provided constraints
10
+ - [x] Focused on user value and business needs - Emphasizes secure authentication and data isolation
11
+ - [x] Written for non-technical stakeholders - User stories and requirements are clear and accessible
12
+ - [x] All mandatory sections completed - User Scenarios, Requirements, and Success Criteria all present
13
+
14
+ ## Requirement Completeness
15
+
16
+ - [x] No [NEEDS CLARIFICATION] markers remain - All requirements are concrete with informed assumptions documented
17
+ - [x] Requirements are testable and unambiguous - Each FR can be verified through testing
18
+ - [x] Success criteria are measurable - All SC items include specific metrics (time, percentage, count)
19
+ - [x] Success criteria are technology-agnostic - Focus on user outcomes and performance, not implementation
20
+ - [x] All acceptance scenarios are defined - Each user story has 2-3 acceptance scenarios
21
+ - [x] Edge cases are identified - 7 edge cases documented covering security and error scenarios
22
+ - [x] Scope is clearly bounded - Out of Scope section explicitly excludes OAuth, MFA, password reset, etc.
23
+ - [x] Dependencies and assumptions identified - Both sections present with specific details
24
+
25
+ ## Feature Readiness
26
+
27
+ - [x] All functional requirements have clear acceptance criteria - 20 FRs defined with specific capabilities
28
+ - [x] User scenarios cover primary flows - 4 prioritized user stories from sign-up to token validation
29
+ - [x] Feature meets measurable outcomes defined in Success Criteria - 8 success criteria align with requirements
30
+ - [x] No implementation details leak into specification - Spec focuses on WHAT and WHY, not HOW
31
+
32
+ ## Validation Results
33
+
34
+ **Status**: ✅ PASSED
35
+
36
+ All checklist items passed validation. The specification is complete, unambiguous, and ready for the planning phase.
37
+
38
+ ## Notes
39
+
40
+ - Technologies mentioned (Better Auth, JWT, FastAPI, Next.js) are from user-provided constraints and are acceptable
41
+ - Assumptions section documents reasonable defaults (1-hour token expiration, HS256 algorithm, password requirements)
42
+ - Success criteria are measurable and technology-agnostic, focusing on user outcomes
43
+ - Edge cases cover critical security scenarios (duplicate emails, expired tokens, missing secrets)
44
+ - Scope is well-defined with clear boundaries in Out of Scope section
specs/001-auth-security/contracts/auth-endpoints.yaml ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Authentication API
4
+ description: Authentication endpoints for user signup, signin, and token management
5
+ version: 1.0.0
6
+ contact:
7
+ name: Phase II Todo App
8
+
9
+ servers:
10
+ - url: http://localhost:8000
11
+ description: Local development server
12
+ - url: https://api.production.example.com
13
+ description: Production server
14
+
15
+ paths:
16
+ /api/auth/signup:
17
+ post:
18
+ summary: Register a new user
19
+ description: Create a new user account with email and password
20
+ operationId: signup
21
+ tags:
22
+ - Authentication
23
+ requestBody:
24
+ required: true
25
+ content:
26
+ application/json:
27
+ schema:
28
+ $ref: '#/components/schemas/SignupRequest'
29
+ examples:
30
+ valid:
31
+ summary: Valid signup request
32
+ value:
33
+ email: user@example.com
34
+ password: SecurePass123!
35
+ name: John Doe
36
+ responses:
37
+ '201':
38
+ description: User created successfully
39
+ content:
40
+ application/json:
41
+ schema:
42
+ $ref: '#/components/schemas/SignupResponse'
43
+ examples:
44
+ success:
45
+ summary: Successful signup
46
+ value:
47
+ id: 1
48
+ email: user@example.com
49
+ name: John Doe
50
+ created_at: "2026-01-09T12:00:00Z"
51
+ '400':
52
+ description: Invalid input or validation error
53
+ content:
54
+ application/json:
55
+ schema:
56
+ $ref: '#/components/schemas/ErrorResponse'
57
+ examples:
58
+ invalid_email:
59
+ summary: Invalid email format
60
+ value:
61
+ detail: Invalid email format
62
+ error_code: VALIDATION_ERROR
63
+ field_errors:
64
+ email: ["Invalid email format"]
65
+ weak_password:
66
+ summary: Weak password
67
+ value:
68
+ detail: Password does not meet requirements
69
+ error_code: VALIDATION_ERROR
70
+ field_errors:
71
+ password: ["Password must be at least 8 characters", "Password must contain uppercase letter"]
72
+ '409':
73
+ description: Email already registered
74
+ content:
75
+ application/json:
76
+ schema:
77
+ $ref: '#/components/schemas/ErrorResponse'
78
+ examples:
79
+ duplicate_email:
80
+ summary: Email already exists
81
+ value:
82
+ detail: Email already registered
83
+ error_code: EMAIL_EXISTS
84
+
85
+ /api/auth/signin:
86
+ post:
87
+ summary: Sign in with email and password
88
+ description: Authenticate user and receive JWT token
89
+ operationId: signin
90
+ tags:
91
+ - Authentication
92
+ requestBody:
93
+ required: true
94
+ content:
95
+ application/json:
96
+ schema:
97
+ $ref: '#/components/schemas/SigninRequest'
98
+ examples:
99
+ valid:
100
+ summary: Valid signin request
101
+ value:
102
+ email: user@example.com
103
+ password: SecurePass123!
104
+ responses:
105
+ '200':
106
+ description: Authentication successful
107
+ content:
108
+ application/json:
109
+ schema:
110
+ $ref: '#/components/schemas/SigninResponse'
111
+ examples:
112
+ success:
113
+ summary: Successful signin
114
+ value:
115
+ access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
116
+ token_type: bearer
117
+ expires_in: 604800
118
+ user:
119
+ id: 1
120
+ email: user@example.com
121
+ name: John Doe
122
+ '401':
123
+ description: Invalid credentials
124
+ content:
125
+ application/json:
126
+ schema:
127
+ $ref: '#/components/schemas/ErrorResponse'
128
+ examples:
129
+ invalid_credentials:
130
+ summary: Invalid email or password
131
+ value:
132
+ detail: Invalid credentials
133
+ error_code: AUTH_FAILED
134
+ '400':
135
+ description: Invalid input
136
+ content:
137
+ application/json:
138
+ schema:
139
+ $ref: '#/components/schemas/ErrorResponse'
140
+
141
+ /api/auth/me:
142
+ get:
143
+ summary: Get current user profile
144
+ description: Retrieve authenticated user's profile information
145
+ operationId: getCurrentUser
146
+ tags:
147
+ - Authentication
148
+ security:
149
+ - BearerAuth: []
150
+ responses:
151
+ '200':
152
+ description: User profile retrieved successfully
153
+ content:
154
+ application/json:
155
+ schema:
156
+ $ref: '#/components/schemas/UserProfile'
157
+ examples:
158
+ success:
159
+ summary: User profile
160
+ value:
161
+ id: 1
162
+ email: user@example.com
163
+ name: John Doe
164
+ created_at: "2026-01-09T12:00:00Z"
165
+ '401':
166
+ description: Unauthorized - invalid or missing token
167
+ content:
168
+ application/json:
169
+ schema:
170
+ $ref: '#/components/schemas/ErrorResponse'
171
+ examples:
172
+ missing_token:
173
+ summary: No token provided
174
+ value:
175
+ detail: Not authenticated
176
+ error_code: TOKEN_MISSING
177
+ expired_token:
178
+ summary: Token expired
179
+ value:
180
+ detail: Token has expired
181
+ error_code: TOKEN_EXPIRED
182
+ invalid_token:
183
+ summary: Invalid token
184
+ value:
185
+ detail: Invalid token
186
+ error_code: TOKEN_INVALID
187
+
188
+ components:
189
+ securitySchemes:
190
+ BearerAuth:
191
+ type: http
192
+ scheme: bearer
193
+ bearerFormat: JWT
194
+ description: JWT token issued by Better Auth
195
+
196
+ schemas:
197
+ SignupRequest:
198
+ type: object
199
+ required:
200
+ - email
201
+ - password
202
+ - name
203
+ properties:
204
+ email:
205
+ type: string
206
+ format: email
207
+ maxLength: 255
208
+ description: User's email address (must be unique)
209
+ example: user@example.com
210
+ password:
211
+ type: string
212
+ format: password
213
+ minLength: 8
214
+ maxLength: 100
215
+ description: User's password (min 8 chars, must contain uppercase, lowercase, and number)
216
+ example: SecurePass123!
217
+ name:
218
+ type: string
219
+ minLength: 1
220
+ maxLength: 100
221
+ description: User's display name
222
+ example: John Doe
223
+
224
+ SignupResponse:
225
+ type: object
226
+ required:
227
+ - id
228
+ - email
229
+ - name
230
+ - created_at
231
+ properties:
232
+ id:
233
+ type: integer
234
+ description: Unique user identifier
235
+ example: 1
236
+ email:
237
+ type: string
238
+ format: email
239
+ description: User's email address
240
+ example: user@example.com
241
+ name:
242
+ type: string
243
+ description: User's display name
244
+ example: John Doe
245
+ created_at:
246
+ type: string
247
+ format: date-time
248
+ description: Account creation timestamp
249
+ example: "2026-01-09T12:00:00Z"
250
+
251
+ SigninRequest:
252
+ type: object
253
+ required:
254
+ - email
255
+ - password
256
+ properties:
257
+ email:
258
+ type: string
259
+ format: email
260
+ description: User's email address
261
+ example: user@example.com
262
+ password:
263
+ type: string
264
+ format: password
265
+ description: User's password
266
+ example: SecurePass123!
267
+
268
+ SigninResponse:
269
+ type: object
270
+ required:
271
+ - access_token
272
+ - token_type
273
+ - expires_in
274
+ - user
275
+ properties:
276
+ access_token:
277
+ type: string
278
+ description: JWT access token
279
+ example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIiwiaWF0IjoxNjQwOTk1MjAwLCJleHAiOjE2NDE2MDAwMDB9.signature
280
+ token_type:
281
+ type: string
282
+ enum: [bearer]
283
+ description: Token type (always "bearer")
284
+ example: bearer
285
+ expires_in:
286
+ type: integer
287
+ description: Token expiration time in seconds (7 days = 604800)
288
+ example: 604800
289
+ user:
290
+ $ref: '#/components/schemas/UserProfile'
291
+
292
+ UserProfile:
293
+ type: object
294
+ required:
295
+ - id
296
+ - email
297
+ - name
298
+ - created_at
299
+ properties:
300
+ id:
301
+ type: integer
302
+ description: Unique user identifier
303
+ example: 1
304
+ email:
305
+ type: string
306
+ format: email
307
+ description: User's email address
308
+ example: user@example.com
309
+ name:
310
+ type: string
311
+ description: User's display name
312
+ example: John Doe
313
+ created_at:
314
+ type: string
315
+ format: date-time
316
+ description: Account creation timestamp
317
+ example: "2026-01-09T12:00:00Z"
318
+
319
+ ErrorResponse:
320
+ type: object
321
+ required:
322
+ - detail
323
+ properties:
324
+ detail:
325
+ type: string
326
+ description: Human-readable error message
327
+ example: Invalid credentials
328
+ error_code:
329
+ type: string
330
+ description: Machine-readable error code
331
+ example: AUTH_FAILED
332
+ field_errors:
333
+ type: object
334
+ additionalProperties:
335
+ type: array
336
+ items:
337
+ type: string
338
+ description: Field-specific validation errors
339
+ example:
340
+ email: ["Invalid email format"]
341
+ password: ["Password too short"]
342
+
343
+ tags:
344
+ - name: Authentication
345
+ description: User authentication and authorization endpoints
specs/001-auth-security/contracts/jwt-schema.yaml ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # JWT Token Schema
2
+
3
+ **Feature**: 001-auth-security
4
+ **Date**: 2026-01-09
5
+
6
+ ## Overview
7
+
8
+ This document defines the structure and validation rules for JWT tokens used in the authentication system. Tokens are issued by Better Auth on the frontend and verified by the FastAPI backend.
9
+
10
+ ## Token Structure
11
+
12
+ ### Header
13
+
14
+ ```json
15
+ {
16
+ "alg": "HS256",
17
+ "typ": "JWT"
18
+ }
19
+ ```
20
+
21
+ | Field | Value | Description |
22
+ |-------|-------|-------------|
23
+ | alg | HS256 | HMAC with SHA-256 algorithm |
24
+ | typ | JWT | Token type |
25
+
26
+ ### Payload (Claims)
27
+
28
+ ```json
29
+ {
30
+ "sub": "1",
31
+ "email": "user@example.com",
32
+ "iat": 1704801600,
33
+ "exp": 1705406400,
34
+ "iss": "better-auth"
35
+ }
36
+ ```
37
+
38
+ | Claim | Type | Required | Description |
39
+ |-------|------|----------|-------------|
40
+ | sub | string | Yes | Subject - User ID (primary key from users table) |
41
+ | email | string | Yes | User's email address |
42
+ | iat | integer | Yes | Issued At - Unix timestamp when token was created |
43
+ | exp | integer | Yes | Expiration - Unix timestamp when token expires (iat + 604800 seconds = 7 days) |
44
+ | iss | string | Yes | Issuer - Always "better-auth" |
45
+
46
+ ### Signature
47
+
48
+ The signature is created by:
49
+ 1. Encoding the header and payload as Base64URL
50
+ 2. Concatenating with a period: `{base64Header}.{base64Payload}`
51
+ 3. Signing with HMAC-SHA256 using BETTER_AUTH_SECRET
52
+ 4. Encoding the signature as Base64URL
53
+
54
+ **Formula**: `HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), BETTER_AUTH_SECRET)`
55
+
56
+ ## Complete Token Format
57
+
58
+ ```
59
+ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIiwiaWF0IjoxNzA0ODAxNjAwLCJleHAiOjE3MDU0MDY0MDAsImlzcyI6ImJldHRlci1hdXRoIn0.signature_here
60
+ ```
61
+
62
+ **Structure**: `{header}.{payload}.{signature}`
63
+
64
+ ## Validation Rules
65
+
66
+ ### Backend Verification Process
67
+
68
+ 1. **Extract Token**: Get token from `Authorization: Bearer {token}` header
69
+ 2. **Parse Token**: Split into header, payload, signature
70
+ 3. **Verify Signature**:
71
+ - Recompute signature using BETTER_AUTH_SECRET
72
+ - Compare with provided signature
73
+ - Reject if signatures don't match
74
+ 4. **Verify Expiration**:
75
+ - Check `exp` claim against current Unix timestamp
76
+ - Reject if `exp < current_time`
77
+ 5. **Verify Required Claims**:
78
+ - Ensure `sub`, `email`, `iat`, `exp`, `iss` are present
79
+ - Reject if any required claim is missing
80
+ 6. **Extract User ID**:
81
+ - Parse `sub` claim as integer
82
+ - Use as authenticated user ID for data filtering
83
+
84
+ ### Validation Checklist
85
+
86
+ - [ ] Token format is valid (3 parts separated by periods)
87
+ - [ ] Header contains correct algorithm (HS256)
88
+ - [ ] Signature is valid (matches recomputed signature)
89
+ - [ ] Token is not expired (exp > current_time)
90
+ - [ ] All required claims are present
91
+ - [ ] User ID (sub) is a valid integer
92
+ - [ ] Email is a valid email format
93
+
94
+ ## Error Responses
95
+
96
+ ### Missing Token
97
+
98
+ **HTTP Status**: 401 Unauthorized
99
+
100
+ ```json
101
+ {
102
+ "detail": "Not authenticated",
103
+ "error_code": "TOKEN_MISSING"
104
+ }
105
+ ```
106
+
107
+ ### Invalid Signature
108
+
109
+ **HTTP Status**: 401 Unauthorized
110
+
111
+ ```json
112
+ {
113
+ "detail": "Invalid token",
114
+ "error_code": "TOKEN_INVALID"
115
+ }
116
+ ```
117
+
118
+ ### Expired Token
119
+
120
+ **HTTP Status**: 401 Unauthorized
121
+
122
+ ```json
123
+ {
124
+ "detail": "Token has expired",
125
+ "error_code": "TOKEN_EXPIRED"
126
+ }
127
+ ```
128
+
129
+ ### Malformed Token
130
+
131
+ **HTTP Status**: 401 Unauthorized
132
+
133
+ ```json
134
+ {
135
+ "detail": "Invalid token format",
136
+ "error_code": "TOKEN_MALFORMED"
137
+ }
138
+ ```
139
+
140
+ ### Missing Claims
141
+
142
+ **HTTP Status**: 401 Unauthorized
143
+
144
+ ```json
145
+ {
146
+ "detail": "Invalid token payload",
147
+ "error_code": "TOKEN_INVALID_PAYLOAD"
148
+ }
149
+ ```
150
+
151
+ ## Security Considerations
152
+
153
+ ### Secret Management
154
+
155
+ - **BETTER_AUTH_SECRET** must be:
156
+ - At least 32 characters long
157
+ - Cryptographically random
158
+ - Identical in frontend and backend
159
+ - Stored in environment variables (never committed to git)
160
+ - Rotated periodically in production
161
+
162
+ ### Token Lifetime
163
+
164
+ - **Expiration**: 7 days (604800 seconds)
165
+ - **Rationale**: Balances security with UX (no refresh tokens in this spec)
166
+ - **Recommendation**: Implement refresh tokens in future iterations for shorter access token lifetime
167
+
168
+ ### Transport Security
169
+
170
+ - **HTTPS Required**: Tokens must only be transmitted over HTTPS in production
171
+ - **Header Only**: Tokens should never be in URL query parameters
172
+ - **httpOnly Cookies**: Frontend stores tokens in httpOnly cookies to prevent XSS
173
+
174
+ ### Attack Mitigation
175
+
176
+ | Attack | Mitigation |
177
+ |--------|------------|
178
+ | Token Theft | HTTPS only, httpOnly cookies |
179
+ | Token Replay | Short expiration (7 days), HTTPS |
180
+ | Signature Forgery | Strong secret (32+ chars), HS256 algorithm |
181
+ | XSS | httpOnly cookies, CSP headers |
182
+ | CSRF | SameSite cookie attribute, CORS configuration |
183
+
184
+ ## Implementation Examples
185
+
186
+ ### Backend Verification (Python/FastAPI)
187
+
188
+ ```python
189
+ import jwt
190
+ from datetime import datetime
191
+ from fastapi import HTTPException, status
192
+
193
+ def verify_jwt_token(token: str, secret: str) -> dict:
194
+ """
195
+ Verify JWT token and return payload.
196
+
197
+ Args:
198
+ token: JWT token string
199
+ secret: BETTER_AUTH_SECRET
200
+
201
+ Returns:
202
+ dict: Token payload with claims
203
+
204
+ Raises:
205
+ HTTPException: 401 if token is invalid or expired
206
+ """
207
+ try:
208
+ # Verify signature and decode
209
+ payload = jwt.decode(
210
+ token,
211
+ secret,
212
+ algorithms=["HS256"],
213
+ options={
214
+ "verify_signature": True,
215
+ "verify_exp": True,
216
+ "require": ["sub", "email", "iat", "exp", "iss"]
217
+ }
218
+ )
219
+
220
+ # Validate issuer
221
+ if payload.get("iss") != "better-auth":
222
+ raise HTTPException(
223
+ status_code=status.HTTP_401_UNAUTHORIZED,
224
+ detail="Invalid token issuer"
225
+ )
226
+
227
+ return payload
228
+
229
+ except jwt.ExpiredSignatureError:
230
+ raise HTTPException(
231
+ status_code=status.HTTP_401_UNAUTHORIZED,
232
+ detail="Token has expired",
233
+ headers={"WWW-Authenticate": "Bearer"}
234
+ )
235
+ except jwt.InvalidTokenError as e:
236
+ raise HTTPException(
237
+ status_code=status.HTTP_401_UNAUTHORIZED,
238
+ detail="Invalid token",
239
+ headers={"WWW-Authenticate": "Bearer"}
240
+ )
241
+ ```
242
+
243
+ ### Frontend Token Inclusion (TypeScript)
244
+
245
+ ```typescript
246
+ // Automatically include token in API requests
247
+ async function fetchAPI<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
248
+ const session = await auth() // Better Auth session
249
+ const token = session?.token
250
+
251
+ if (!token) {
252
+ throw new Error('Not authenticated')
253
+ }
254
+
255
+ const response = await fetch(`${API_BASE_URL}${endpoint}`, {
256
+ ...options,
257
+ headers: {
258
+ 'Content-Type': 'application/json',
259
+ 'Authorization': `Bearer ${token}`,
260
+ ...options.headers,
261
+ },
262
+ })
263
+
264
+ if (response.status === 401) {
265
+ // Token expired or invalid - redirect to login
266
+ window.location.href = '/auth/signin'
267
+ throw new Error('Authentication required')
268
+ }
269
+
270
+ return response.json()
271
+ }
272
+ ```
273
+
274
+ ## Testing Checklist
275
+
276
+ - [ ] Valid token with correct signature is accepted
277
+ - [ ] Expired token is rejected with 401
278
+ - [ ] Token with invalid signature is rejected with 401
279
+ - [ ] Token with missing claims is rejected with 401
280
+ - [ ] Token with wrong algorithm is rejected with 401
281
+ - [ ] Request without token is rejected with 401
282
+ - [ ] Malformed token (not 3 parts) is rejected with 401
283
+ - [ ] Token with non-integer user ID is rejected with 401
284
+
285
+ ## Token Lifecycle
286
+
287
+ ```
288
+ 1. User Sign In
289
+
290
+ 2. Better Auth validates credentials
291
+
292
+ 3. Better Auth creates JWT with user claims
293
+
294
+ 4. Better Auth signs JWT with BETTER_AUTH_SECRET
295
+
296
+ 5. Frontend receives token
297
+
298
+ 6. Frontend stores token in httpOnly cookie
299
+
300
+ 7. Frontend includes token in API requests
301
+
302
+ 8. Backend extracts token from Authorization header
303
+
304
+ 9. Backend verifies signature and expiration
305
+
306
+ 10. Backend extracts user_id from 'sub' claim
307
+
308
+ 11. Backend filters data by user_id
309
+
310
+ 12. Token expires after 7 days
311
+
312
+ 13. User must sign in again
313
+ ```
314
+
315
+ ## Future Enhancements (Out of Scope)
316
+
317
+ - Refresh tokens for shorter access token lifetime
318
+ - Token revocation/blacklist mechanism
319
+ - Multiple device session management
320
+ - Token rotation on refresh
321
+ - Asymmetric signing (RS256) for microservices
specs/001-auth-security/data-model.md ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Model: Authentication & API Security
2
+
3
+ **Feature**: 001-auth-security
4
+ **Date**: 2026-01-09
5
+ **Phase**: 1 - Design
6
+
7
+ ## Overview
8
+
9
+ This document defines the data entities and their relationships for the authentication and API security feature. The primary entity is the User, which will be extended to support password-based authentication.
10
+
11
+ ## Entities
12
+
13
+ ### User (Modified)
14
+
15
+ **Purpose**: Represents a registered user account with authentication credentials.
16
+
17
+ **Table**: `users`
18
+
19
+ **Fields**:
20
+
21
+ | Field | Type | Constraints | Description |
22
+ |-------|------|-------------|-------------|
23
+ | id | Integer | PRIMARY KEY, AUTO_INCREMENT | Unique user identifier |
24
+ | email | String(255) | UNIQUE, NOT NULL, INDEX | User's email address (used for login) |
25
+ | name | String(100) | NOT NULL | User's display name |
26
+ | password_hash | String(255) | NOT NULL | Bcrypt-hashed password (NEW) |
27
+ | created_at | DateTime | NOT NULL, DEFAULT NOW() | Account creation timestamp |
28
+ | updated_at | DateTime | NOT NULL, DEFAULT NOW() | Last update timestamp |
29
+
30
+ **Indexes**:
31
+ - PRIMARY KEY on `id`
32
+ - UNIQUE INDEX on `email`
33
+ - INDEX on `created_at` (for sorting/filtering)
34
+
35
+ **Relationships**:
36
+ - One-to-Many with Task (one user has many tasks)
37
+
38
+ **Validation Rules**:
39
+ - Email must be valid RFC 5322 format
40
+ - Email must be unique (enforced at database level)
41
+ - Password must be hashed with bcrypt before storage
42
+ - Name must be 1-100 characters
43
+ - password_hash must be exactly 60 characters (bcrypt output length)
44
+
45
+ **State Transitions**: None (users don't have state in this spec)
46
+
47
+ **Security Considerations**:
48
+ - Password is never stored in plain text
49
+ - Password hash uses bcrypt with cost factor 12
50
+ - Email is indexed for fast lookup during authentication
51
+ - created_at and updated_at track account lifecycle
52
+
53
+ ---
54
+
55
+ ### Task (Existing - No Changes)
56
+
57
+ **Purpose**: Represents a to-do item owned by a user.
58
+
59
+ **Table**: `tasks`
60
+
61
+ **Fields**:
62
+
63
+ | Field | Type | Constraints | Description |
64
+ |-------|------|-------------|-------------|
65
+ | id | Integer | PRIMARY KEY, AUTO_INCREMENT | Unique task identifier |
66
+ | user_id | Integer | FOREIGN KEY(users.id), NOT NULL, INDEX | Owner of the task |
67
+ | title | String(200) | NOT NULL | Task title |
68
+ | description | String(1000) | NULLABLE | Task description |
69
+ | completed | Boolean | NOT NULL, DEFAULT FALSE, INDEX | Completion status |
70
+ | created_at | DateTime | NOT NULL, DEFAULT NOW(), INDEX | Creation timestamp |
71
+ | updated_at | DateTime | NOT NULL, DEFAULT NOW() | Last update timestamp |
72
+
73
+ **Relationships**:
74
+ - Many-to-One with User (many tasks belong to one user)
75
+
76
+ **Security Note**: All task queries MUST filter by authenticated user_id to enforce data isolation.
77
+
78
+ ---
79
+
80
+ ### JWT Token (Virtual Entity - Not Stored)
81
+
82
+ **Purpose**: Represents an authentication token issued by Better Auth and verified by the backend.
83
+
84
+ **Storage**: Not persisted in database (stateless authentication)
85
+
86
+ **Structure** (JWT Payload):
87
+
88
+ | Claim | Type | Description |
89
+ |-------|------|-------------|
90
+ | sub | String | User ID (subject) |
91
+ | email | String | User's email address |
92
+ | iat | Integer | Issued at timestamp (Unix epoch) |
93
+ | exp | Integer | Expiration timestamp (Unix epoch, iat + 7 days) |
94
+ | iss | String | Issuer (Better Auth) |
95
+
96
+ **Validation Rules**:
97
+ - Token must be signed with BETTER_AUTH_SECRET using HS256
98
+ - Token must not be expired (exp > current time)
99
+ - Token must contain valid sub (user ID)
100
+ - Token signature must be valid
101
+
102
+ **Lifecycle**:
103
+ 1. Issued by Better Auth upon successful authentication
104
+ 2. Included in Authorization header for API requests
105
+ 3. Verified by backend on every protected endpoint
106
+ 4. Expires after 7 days (no refresh in this spec)
107
+
108
+ ---
109
+
110
+ ## Database Migrations
111
+
112
+ ### Migration 002: Add User Password Field
113
+
114
+ **File**: `backend/alembic/versions/002_add_user_password.py`
115
+
116
+ **Changes**:
117
+ - Add `password_hash` column to `users` table
118
+ - Column is NOT NULL (existing users will need password set)
119
+
120
+ **Upgrade**:
121
+ ```sql
122
+ ALTER TABLE users ADD COLUMN password_hash VARCHAR(255) NOT NULL;
123
+ ```
124
+
125
+ **Downgrade**:
126
+ ```sql
127
+ ALTER TABLE users DROP COLUMN password_hash;
128
+ ```
129
+
130
+ **Data Migration Note**: If existing users exist without passwords, they will need to be handled separately (e.g., force password reset on first login, or seed with temporary passwords).
131
+
132
+ ---
133
+
134
+ ## Entity Relationships Diagram
135
+
136
+ ```
137
+ ┌─────────────────────────────────────┐
138
+ │ User │
139
+ ├─────────────────────────────────────┤
140
+ │ id (PK) │
141
+ │ email (UNIQUE) │
142
+ │ name │
143
+ │ password_hash (NEW) │
144
+ │ created_at │
145
+ │ updated_at │
146
+ └────────────────────────────────────��┘
147
+
148
+ │ 1:N
149
+
150
+
151
+ ┌─────────────────────────────────────┐
152
+ │ Task │
153
+ ├─────────────────────────────────────┤
154
+ │ id (PK) │
155
+ │ user_id (FK → User.id) │
156
+ │ title │
157
+ │ description │
158
+ │ completed │
159
+ │ created_at │
160
+ │ updated_at │
161
+ └─────────────────────────────────────┘
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Data Access Patterns
167
+
168
+ ### Authentication Flow
169
+ 1. User submits email + password to Better Auth
170
+ 2. Better Auth verifies credentials against users table
171
+ 3. Better Auth issues JWT token with user_id in `sub` claim
172
+ 4. Frontend stores token in httpOnly cookie
173
+
174
+ ### API Request Flow
175
+ 1. Frontend includes JWT in Authorization header
176
+ 2. Backend extracts token from header
177
+ 3. Backend verifies token signature and expiration
178
+ 4. Backend extracts user_id from `sub` claim
179
+ 5. Backend filters data by user_id
180
+
181
+ ### Task Query Pattern
182
+ ```sql
183
+ -- All task queries MUST include user_id filter
184
+ SELECT * FROM tasks WHERE user_id = :authenticated_user_id;
185
+
186
+ -- Example: Get user's completed tasks
187
+ SELECT * FROM tasks
188
+ WHERE user_id = :authenticated_user_id
189
+ AND completed = true
190
+ ORDER BY created_at DESC;
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Validation Summary
196
+
197
+ ### User Entity
198
+ - ✅ Email format validation (RFC 5322)
199
+ - ✅ Email uniqueness (database constraint)
200
+ - ✅ Password strength (minimum 8 chars, complexity rules)
201
+ - ✅ Password hashing (bcrypt, cost 12)
202
+ - ✅ Name length (1-100 characters)
203
+
204
+ ### JWT Token
205
+ - ✅ Signature validation (HS256 with shared secret)
206
+ - ✅ Expiration validation (exp claim)
207
+ - ✅ Required claims present (sub, email, iat, exp)
208
+ - ✅ User ID extraction (from sub claim)
209
+
210
+ ### Task Entity (Security)
211
+ - ✅ User ownership validation (user_id matches token)
212
+ - ✅ Query filtering (all queries include user_id)
213
+ - ✅ Authorization checks (prevent cross-user access)
214
+
215
+ ---
216
+
217
+ ## Performance Considerations
218
+
219
+ ### Indexes
220
+ - `users.email` - UNIQUE INDEX for fast authentication lookups
221
+ - `tasks.user_id` - INDEX for fast user task queries
222
+ - `tasks.completed` - INDEX for filtering by status
223
+ - `tasks.created_at` - INDEX for sorting
224
+
225
+ ### Query Optimization
226
+ - JWT verification is stateless (no database lookup)
227
+ - User lookup by email is O(1) with index
228
+ - Task queries filtered by indexed user_id
229
+ - Pagination supported for large task lists
230
+
231
+ ---
232
+
233
+ ## Security Checklist
234
+
235
+ - [x] Passwords never stored in plain text
236
+ - [x] Bcrypt hashing with appropriate cost factor
237
+ - [x] Email uniqueness enforced at database level
238
+ - [x] JWT tokens contain minimal claims (no sensitive data)
239
+ - [x] Token expiration enforced (7 days)
240
+ - [x] User ID extracted from validated token only
241
+ - [x] All task queries filtered by authenticated user
242
+ - [x] Foreign key constraints prevent orphaned tasks
specs/001-auth-security/plan.md ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Plan: Authentication & API Security
2
+
3
+ **Branch**: `001-auth-security` | **Date**: 2026-01-09 | **Spec**: [spec.md](./spec.md)
4
+ **Input**: Feature specification from `/specs/001-auth-security/spec.md`
5
+
6
+ **Note**: This template is filled in by the `/sp.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
7
+
8
+ ## Summary
9
+
10
+ Implement secure user authentication using Better Auth on the frontend and JWT-based authorization on the backend. The system will enforce stateless authentication where Better Auth issues JWT tokens upon successful login, and the backend verifies these tokens on every API request to ensure users can only access their own data.
11
+
12
+ ## Technical Context
13
+
14
+ **Language/Version**: Python 3.11+ (backend), TypeScript 5.3+ (frontend)
15
+ **Primary Dependencies**:
16
+ - Frontend: Next.js 16+, React 18, Better Auth (to be added), Tailwind CSS
17
+ - Backend: FastAPI 0.104+, SQLModel 0.0.14, PyJWT (to be added), Pydantic 2.5+
18
+
19
+ **Storage**: Neon Serverless PostgreSQL (existing users table needs password field)
20
+ **Testing**: pytest (backend), Jest/React Testing Library (frontend - to be configured)
21
+ **Target Platform**: Web application (Linux/Docker backend, browser frontend)
22
+ **Project Type**: Web (monorepo with separate frontend/ and backend/ directories)
23
+ **Performance Goals**:
24
+ - Token verification: <50ms per request
25
+ - Authentication flow: <5 seconds end-to-end
26
+ - Support 100+ concurrent authentication requests
27
+
28
+ **Constraints**:
29
+ - Stateless backend (no server-side session storage)
30
+ - Shared secret (BETTER_AUTH_SECRET) must be identical in frontend and backend
31
+ - JWT tokens must include user_id and email claims
32
+ - All task API endpoints must require valid JWT
33
+ - Token expiry: 7 days (resolved in research.md - balances security with UX without refresh tokens)
34
+
35
+ **Scale/Scope**:
36
+ - Multi-user application (100+ users initially)
37
+ - 5 authentication-related endpoints (signup, signin, token verification)
38
+ - All existing task endpoints (6) require JWT protection
39
+
40
+ ## Constitution Check
41
+
42
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
43
+
44
+ ### Principle I: User-Centric Functionality
45
+ ✅ **PASS** - Authentication directly serves end-users by securing their data and enabling personalized task management. JWT-based authorization ensures each user only accesses their own tasks.
46
+
47
+ ### Principle II: Spec-Driven Development
48
+ ✅ **PASS** - This plan follows the Spec-Kit Plus workflow. All implementation will reference `/specs/001-auth-security/spec.md` and generated artifacts (data-model.md, contracts/).
49
+
50
+ ### Principle III: Security & Data Privacy
51
+ ✅ **PASS** - Core focus of this feature:
52
+ - JWT authentication on all task endpoints
53
+ - BETTER_AUTH_SECRET managed via environment variables
54
+ - User data filtered by authenticated user ID
55
+ - 401 responses for unauthorized requests
56
+ - No hardcoded secrets
57
+
58
+ ### Principle IV: Scalable Architecture
59
+ ✅ **PASS** - Stateless JWT design enables horizontal scaling:
60
+ - No server-side session storage
61
+ - Backend remains stateless
62
+ - Token verification is fast (<50ms target)
63
+ - Database queries use indexed user_id field
64
+
65
+ ### Principle V: Maintainable & Consistent Code
66
+ ✅ **PASS** - Follows established patterns:
67
+ - FastAPI dependency injection for JWT verification
68
+ - Better Auth integration on frontend
69
+ - Consistent error handling (401 for auth failures)
70
+ - Modular authentication middleware
71
+
72
+ ### Key Standards Compliance
73
+
74
+ **API Compliance**: ✅ All authentication endpoints will be documented in `/specs/001-auth-security/contracts/`
75
+
76
+ **Database Integrity**: ✅ Users table already exists; will add password_hash field with proper constraints
77
+
78
+ **Frontend Quality**: ✅ Better Auth integration follows Next.js App Router patterns
79
+
80
+ **Authentication**: ✅ Core requirement - Better Auth + JWT as specified
81
+
82
+ **Spec Adherence**: ✅ All implementation references spec.md
83
+
84
+ ### Gate Result: ✅ PASS - Proceed to Phase 0 Research
85
+
86
+ ## Project Structure
87
+
88
+ ### Documentation (this feature)
89
+
90
+ ```text
91
+ specs/001-auth-security/
92
+ ├── plan.md # This file (/sp.plan command output)
93
+ ├── research.md # Phase 0 output (/sp.plan command)
94
+ ├── data-model.md # Phase 1 output (/sp.plan command)
95
+ ├── quickstart.md # Phase 1 output (/sp.plan command)
96
+ ├── contracts/ # Phase 1 output (/sp.plan command)
97
+ │ ├── auth-endpoints.yaml
98
+ │ └── jwt-schema.yaml
99
+ └── tasks.md # Phase 2 output (/sp.tasks command - NOT created by /sp.plan)
100
+ ```
101
+
102
+ ### Source Code (repository root)
103
+
104
+ ```text
105
+ backend/
106
+ ├── src/
107
+ │ ├── api/
108
+ │ │ ├── deps.py # JWT verification dependency (modify)
109
+ │ │ └── routes/
110
+ │ │ ├── auth.py # New: signup, signin endpoints
111
+ │ │ └── tasks.py # Existing: already uses get_current_user
112
+ │ ├── core/
113
+ │ │ ├── config.py # Add BETTER_AUTH_SECRET (modify)
114
+ │ │ ├── database.py # Existing
115
+ │ │ └── security.py # New: JWT verification logic
116
+ │ ├── models/
117
+ │ │ ├── user.py # Add password_hash field (modify)
118
+ │ │ └── task.py # Existing
119
+ │ ├── schemas/
120
+ │ │ ├── auth.py # New: signup, signin, token schemas
121
+ │ │ └── task.py # Existing
122
+ │ └── services/
123
+ │ ├── auth_service.py # New: authentication business logic
124
+ │ └── task_service.py # Existing
125
+ ├── alembic/
126
+ │ └── versions/
127
+ │ └── 002_add_user_password.py # New migration
128
+ └── tests/
129
+ ├── test_auth.py # New: authentication tests
130
+ └── test_tasks.py # Existing: update to test JWT protection
131
+
132
+ frontend/
133
+ ├── src/
134
+ │ ├── app/
135
+ │ │ ├── auth/
136
+ │ │ │ ├── signin/
137
+ │ │ │ │ └── page.tsx # New: sign-in page
138
+ │ │ │ └── signup/
139
+ │ │ │ └── page.tsx # New: sign-up page
140
+ │ │ ├── layout.tsx # Modify: add auth provider
141
+ │ │ └── page.tsx # Existing: task list (protect)
142
+ │ ├── components/
143
+ │ │ ├── auth/
144
+ │ │ │ ├── SignInForm.tsx # New: sign-in form
145
+ │ │ │ └── SignUpForm.tsx # New: sign-up form
146
+ │ │ └── tasks/ # Existing components
147
+ │ ├── lib/
148
+ │ │ ├── api.ts # Modify: add JWT to headers
149
+ │ │ ├── auth.ts # New: Better Auth configuration
150
+ │ │ └── types.ts # Existing
151
+ │ └── providers/
152
+ │ └── AuthProvider.tsx # New: auth context provider
153
+ └── tests/
154
+ └── auth/ # New: authentication tests
155
+ ```
156
+
157
+ **Structure Decision**: Web application (Option 2) with separate backend/ and frontend/ directories. This is a monorepo structure where:
158
+ - Backend handles JWT verification and API protection
159
+ - Frontend handles Better Auth integration and token management
160
+ - Both share BETTER_AUTH_SECRET via environment variables
161
+
162
+ ## Complexity Tracking
163
+
164
+ > **Fill ONLY if Constitution Check has violations that must be justified**
165
+
166
+ No constitutional violations detected. All complexity is justified by security requirements and follows established patterns.
specs/001-auth-security/quickstart.md ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quickstart: Authentication & API Security
2
+
3
+ **Feature**: 001-auth-security
4
+ **Date**: 2026-01-09
5
+
6
+ ## Overview
7
+
8
+ This guide provides step-by-step instructions for setting up and testing the authentication and API security feature. Follow these steps to configure Better Auth on the frontend and JWT verification on the backend.
9
+
10
+ ## Prerequisites
11
+
12
+ - Node.js 18+ and npm installed
13
+ - Python 3.11+ installed
14
+ - PostgreSQL database (Neon Serverless) accessible
15
+ - Git repository cloned
16
+ - Existing task CRUD functionality working (from Spec 001-task-crud)
17
+
18
+ ## Setup Instructions
19
+
20
+ ### 1. Environment Configuration
21
+
22
+ #### Backend Environment Variables
23
+
24
+ Create or update `backend/.env`:
25
+
26
+ ```bash
27
+ # Database
28
+ DATABASE_URL=postgresql://user:password@host:5432/database
29
+
30
+ # Authentication
31
+ BETTER_AUTH_SECRET=your-secret-key-min-32-characters-long-and-random
32
+
33
+ # Application
34
+ APP_NAME=Task CRUD API
35
+ DEBUG=True
36
+ CORS_ORIGINS=http://localhost:3000
37
+ ```
38
+
39
+ **Important**: Generate a strong random secret for `BETTER_AUTH_SECRET`:
40
+ ```bash
41
+ # Generate a secure random secret (32+ characters)
42
+ python -c "import secrets; print(secrets.token_urlsafe(32))"
43
+ ```
44
+
45
+ #### Frontend Environment Variables
46
+
47
+ Create or update `frontend/.env.local`:
48
+
49
+ ```bash
50
+ # API Configuration
51
+ NEXT_PUBLIC_API_URL=http://localhost:8000
52
+
53
+ # Authentication (MUST match backend secret)
54
+ BETTER_AUTH_SECRET=your-secret-key-min-32-characters-long-and-random
55
+
56
+ # Better Auth Database (optional - uses same as backend)
57
+ DATABASE_URL=postgresql://user:password@host:5432/database
58
+ ```
59
+
60
+ **Critical**: The `BETTER_AUTH_SECRET` must be **identical** in both frontend and backend.
61
+
62
+ ---
63
+
64
+ ### 2. Install Dependencies
65
+
66
+ #### Backend Dependencies
67
+
68
+ ```bash
69
+ cd backend
70
+
71
+ # Add new dependencies to requirements.txt
72
+ echo "PyJWT==2.8.0" >> requirements.txt
73
+ echo "passlib[bcrypt]==1.7.4" >> requirements.txt
74
+ echo "python-multipart==0.0.6" >> requirements.txt
75
+
76
+ # Install all dependencies
77
+ pip install -r requirements.txt
78
+ ```
79
+
80
+ #### Frontend Dependencies
81
+
82
+ ```bash
83
+ cd frontend
84
+
85
+ # Install Better Auth
86
+ npm install better-auth @better-auth/react
87
+
88
+ # Install development dependencies (if not already installed)
89
+ npm install --save-dev @types/node @types/react @types/react-dom
90
+ ```
91
+
92
+ ---
93
+
94
+ ### 3. Database Migration
95
+
96
+ #### Run Migration to Add Password Field
97
+
98
+ ```bash
99
+ cd backend
100
+
101
+ # Create migration
102
+ alembic revision --autogenerate -m "Add password_hash to users"
103
+
104
+ # Review the generated migration file in alembic/versions/
105
+ # Ensure it adds password_hash column to users table
106
+
107
+ # Apply migration
108
+ alembic upgrade head
109
+ ```
110
+
111
+ **Expected Migration**:
112
+ ```python
113
+ def upgrade():
114
+ op.add_column('users', sa.Column('password_hash', sa.String(255), nullable=False))
115
+
116
+ def downgrade():
117
+ op.drop_column('users', 'password_hash')
118
+ ```
119
+
120
+ ---
121
+
122
+ ### 4. Backend Implementation
123
+
124
+ #### Create Security Module
125
+
126
+ Create `backend/src/core/security.py`:
127
+
128
+ ```python
129
+ import jwt
130
+ from datetime import datetime, timedelta
131
+ from passlib.context import CryptContext
132
+ from fastapi import HTTPException, status
133
+ from src.core.config import settings
134
+
135
+ # Password hashing
136
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
137
+
138
+ def hash_password(password: str) -> str:
139
+ """Hash a password using bcrypt."""
140
+ return pwd_context.hash(password)
141
+
142
+ def verify_password(plain_password: str, hashed_password: str) -> bool:
143
+ """Verify a password against its hash."""
144
+ return pwd_context.verify(plain_password, hashed_password)
145
+
146
+ def create_jwt_token(user_id: int, email: str) -> str:
147
+ """Create a JWT token for a user."""
148
+ payload = {
149
+ "sub": str(user_id),
150
+ "email": email,
151
+ "iat": datetime.utcnow(),
152
+ "exp": datetime.utcnow() + timedelta(days=7),
153
+ "iss": "better-auth"
154
+ }
155
+ return jwt.encode(payload, settings.BETTER_AUTH_SECRET, algorithm="HS256")
156
+
157
+ def verify_jwt_token(token: str) -> dict:
158
+ """Verify and decode a JWT token."""
159
+ try:
160
+ payload = jwt.decode(
161
+ token,
162
+ settings.BETTER_AUTH_SECRET,
163
+ algorithms=["HS256"]
164
+ )
165
+ return payload
166
+ except jwt.ExpiredSignatureError:
167
+ raise HTTPException(
168
+ status_code=status.HTTP_401_UNAUTHORIZED,
169
+ detail="Token has expired"
170
+ )
171
+ except jwt.InvalidTokenError:
172
+ raise HTTPException(
173
+ status_code=status.HTTP_401_UNAUTHORIZED,
174
+ detail="Invalid token"
175
+ )
176
+ ```
177
+
178
+ #### Update Dependencies
179
+
180
+ Modify `backend/src/api/deps.py`:
181
+
182
+ ```python
183
+ from fastapi import Depends, HTTPException, status
184
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
185
+ from sqlmodel import Session
186
+ from src.core.database import get_session
187
+ from src.core.security import verify_jwt_token
188
+
189
+ security = HTTPBearer()
190
+
191
+ def get_db() -> Generator[Session, None, None]:
192
+ """Get database session dependency."""
193
+ yield from get_session()
194
+
195
+ def get_current_user(
196
+ credentials: HTTPAuthorizationCredentials = Depends(security)
197
+ ) -> int:
198
+ """
199
+ Get current user ID from JWT token.
200
+ Extracts and verifies JWT from Authorization header.
201
+ """
202
+ token = credentials.credentials
203
+ payload = verify_jwt_token(token)
204
+ user_id = payload.get("sub")
205
+
206
+ if not user_id:
207
+ raise HTTPException(
208
+ status_code=status.HTTP_401_UNAUTHORIZED,
209
+ detail="Invalid token payload"
210
+ )
211
+
212
+ return int(user_id)
213
+ ```
214
+
215
+ #### Update Configuration
216
+
217
+ Modify `backend/src/core/config.py`:
218
+
219
+ ```python
220
+ class Settings(BaseSettings):
221
+ # ... existing fields ...
222
+
223
+ # Authentication
224
+ BETTER_AUTH_SECRET: str # Remove Optional, make required
225
+ JWT_ALGORITHM: str = "HS256"
226
+ JWT_EXPIRATION_DAYS: int = 7
227
+ ```
228
+
229
+ ---
230
+
231
+ ### 5. Frontend Implementation
232
+
233
+ #### Configure Better Auth
234
+
235
+ Create `frontend/src/lib/auth.ts`:
236
+
237
+ ```typescript
238
+ import { betterAuth } from "better-auth"
239
+ import { jwt } from "better-auth/plugins"
240
+
241
+ export const auth = betterAuth({
242
+ database: {
243
+ provider: "postgres",
244
+ url: process.env.DATABASE_URL!,
245
+ },
246
+ emailAndPassword: {
247
+ enabled: true,
248
+ requireEmailVerification: false,
249
+ },
250
+ plugins: [
251
+ jwt({
252
+ secret: process.env.BETTER_AUTH_SECRET!,
253
+ expiresIn: "7d",
254
+ })
255
+ ],
256
+ secret: process.env.BETTER_AUTH_SECRET!,
257
+ })
258
+ ```
259
+
260
+ #### Update API Client
261
+
262
+ Modify `frontend/src/lib/api.ts`:
263
+
264
+ ```typescript
265
+ import { auth } from './auth'
266
+
267
+ async function fetchAPI<T>(
268
+ endpoint: string,
269
+ options: RequestInit = {}
270
+ ): Promise<T> {
271
+ const session = await auth()
272
+ const token = session?.token
273
+
274
+ const url = `${API_BASE_URL}${endpoint}`
275
+
276
+ const response = await fetch(url, {
277
+ ...options,
278
+ headers: {
279
+ 'Content-Type': 'application/json',
280
+ ...(token && { 'Authorization': `Bearer ${token}` }),
281
+ ...options.headers,
282
+ },
283
+ })
284
+
285
+ if (response.status === 401) {
286
+ // Redirect to login
287
+ if (typeof window !== 'undefined') {
288
+ window.location.href = '/auth/signin'
289
+ }
290
+ throw new APIError('Authentication required', 401)
291
+ }
292
+
293
+ if (!response.ok) {
294
+ const errorData: ErrorResponse = await response.json().catch(() => ({
295
+ detail: 'An unexpected error occurred',
296
+ }))
297
+
298
+ throw new APIError(
299
+ errorData.detail,
300
+ response.status,
301
+ errorData.error_code,
302
+ errorData.field_errors
303
+ )
304
+ }
305
+
306
+ return response.json()
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ### 6. Testing
313
+
314
+ #### Backend Tests
315
+
316
+ ```bash
317
+ cd backend
318
+
319
+ # Test authentication endpoints
320
+ pytest tests/test_auth.py -v
321
+
322
+ # Test JWT protection on task endpoints
323
+ pytest tests/test_tasks.py -v
324
+
325
+ # Run all tests
326
+ pytest -v
327
+ ```
328
+
329
+ #### Manual Testing with curl
330
+
331
+ **Sign Up**:
332
+ ```bash
333
+ curl -X POST http://localhost:8000/api/auth/signup \
334
+ -H "Content-Type: application/json" \
335
+ -d '{
336
+ "email": "test@example.com",
337
+ "password": "SecurePass123!",
338
+ "name": "Test User"
339
+ }'
340
+ ```
341
+
342
+ **Sign In**:
343
+ ```bash
344
+ curl -X POST http://localhost:8000/api/auth/signin \
345
+ -H "Content-Type: application/json" \
346
+ -d '{
347
+ "email": "test@example.com",
348
+ "password": "SecurePass123!"
349
+ }'
350
+ ```
351
+
352
+ **Access Protected Endpoint**:
353
+ ```bash
354
+ # Save token from signin response
355
+ TOKEN="your-jwt-token-here"
356
+
357
+ curl -X GET http://localhost:8000/api/tasks \
358
+ -H "Authorization: Bearer $TOKEN"
359
+ ```
360
+
361
+ **Test Unauthorized Access**:
362
+ ```bash
363
+ # Should return 401
364
+ curl -X GET http://localhost:8000/api/tasks
365
+ ```
366
+
367
+ ---
368
+
369
+ ### 7. Running the Application
370
+
371
+ #### Start Backend
372
+
373
+ ```bash
374
+ cd backend
375
+ uvicorn src.main:app --reload --port 8000
376
+ ```
377
+
378
+ #### Start Frontend
379
+
380
+ ```bash
381
+ cd frontend
382
+ npm run dev
383
+ ```
384
+
385
+ #### Access Application
386
+
387
+ - Frontend: http://localhost:3000
388
+ - Backend API: http://localhost:8000
389
+ - API Docs: http://localhost:8000/docs
390
+
391
+ ---
392
+
393
+ ## Verification Checklist
394
+
395
+ ### Backend Verification
396
+
397
+ - [ ] `BETTER_AUTH_SECRET` is set in backend/.env
398
+ - [ ] PyJWT, passlib, python-multipart installed
399
+ - [ ] Database migration applied (password_hash column exists)
400
+ - [ ] `src/core/security.py` created with JWT functions
401
+ - [ ] `src/api/deps.py` updated with JWT verification
402
+ - [ ] Backend starts without errors: `uvicorn src.main:app --reload`
403
+ - [ ] API docs accessible at http://localhost:8000/docs
404
+
405
+ ### Frontend Verification
406
+
407
+ - [ ] `BETTER_AUTH_SECRET` matches backend (identical value)
408
+ - [ ] better-auth and @better-auth/react installed
409
+ - [ ] `src/lib/auth.ts` created with Better Auth config
410
+ - [ ] `src/lib/api.ts` updated to include JWT in headers
411
+ - [ ] Frontend starts without errors: `npm run dev`
412
+ - [ ] Can access http://localhost:3000
413
+
414
+ ### Integration Verification
415
+
416
+ - [ ] User can sign up with email/password
417
+ - [ ] User can sign in and receive JWT token
418
+ - [ ] Authenticated requests to /api/tasks succeed
419
+ - [ ] Unauthenticated requests to /api/tasks return 401
420
+ - [ ] User can only see their own tasks
421
+ - [ ] Token expires after 7 days (test with modified exp claim)
422
+
423
+ ---
424
+
425
+ ## Troubleshooting
426
+
427
+ ### "Invalid token" errors
428
+
429
+ **Cause**: BETTER_AUTH_SECRET mismatch between frontend and backend
430
+
431
+ **Solution**: Verify both .env files have identical BETTER_AUTH_SECRET values
432
+
433
+ ### "Token has expired" immediately
434
+
435
+ **Cause**: System clock skew or incorrect exp claim
436
+
437
+ **Solution**: Check system time, verify token exp claim is 7 days in future
438
+
439
+ ### "Not authenticated" on all requests
440
+
441
+ **Cause**: Token not being included in Authorization header
442
+
443
+ **Solution**: Check frontend api.ts includes `Authorization: Bearer ${token}` header
444
+
445
+ ### Database connection errors
446
+
447
+ **Cause**: DATABASE_URL incorrect or database not accessible
448
+
449
+ **Solution**: Verify DATABASE_URL format and database is running
450
+
451
+ ### Import errors for better-auth
452
+
453
+ **Cause**: Package not installed or wrong version
454
+
455
+ **Solution**: Run `npm install better-auth @better-auth/react` in frontend directory
456
+
457
+ ---
458
+
459
+ ## Next Steps
460
+
461
+ After completing this setup:
462
+
463
+ 1. Run `/sp.tasks` to generate implementation tasks
464
+ 2. Implement authentication endpoints (signup, signin)
465
+ 3. Implement JWT verification middleware
466
+ 4. Update task endpoints to require authentication
467
+ 5. Create frontend auth pages (signin, signup)
468
+ 6. Test end-to-end authentication flow
469
+ 7. Deploy to production with HTTPS enabled
470
+
471
+ ---
472
+
473
+ ## Security Reminders
474
+
475
+ - ✅ Never commit .env files to git
476
+ - ✅ Use HTTPS in production
477
+ - ✅ Rotate BETTER_AUTH_SECRET periodically
478
+ - ✅ Use strong passwords (min 8 chars, complexity requirements)
479
+ - ✅ Monitor for suspicious authentication attempts
480
+ - ✅ Keep dependencies updated for security patches
481
+
482
+ ---
483
+
484
+ ## Reference Documentation
485
+
486
+ - Better Auth: https://better-auth.com/docs
487
+ - PyJWT: https://pyjwt.readthedocs.io/
488
+ - FastAPI Security: https://fastapi.tiangolo.com/tutorial/security/
489
+ - JWT.io: https://jwt.io/ (for debugging tokens)
specs/001-auth-security/research.md ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research: Authentication & API Security
2
+
3
+ **Feature**: 001-auth-security
4
+ **Date**: 2026-01-09
5
+ **Phase**: 0 - Research & Technical Decisions
6
+
7
+ ## Overview
8
+
9
+ This document captures research findings and technical decisions for implementing authentication and API security using Better Auth (frontend) and JWT verification (backend).
10
+
11
+ ## Research Questions & Resolutions
12
+
13
+ ### 1. Token Expiry Duration
14
+
15
+ **Question**: Spec says 1 hour, user input says 7 days - which should we use?
16
+
17
+ **Decision**: **7 days**
18
+
19
+ **Rationale**:
20
+ - The spec explicitly excludes "Token refresh mechanism and refresh tokens" from scope
21
+ - Without refresh tokens, 1-hour expiry creates poor UX (users logged out every hour)
22
+ - This is a hackathon/MVP project where simplicity is prioritized
23
+ - 7 days balances security with usability for the initial release
24
+ - Industry standard for web apps *with refresh tokens* is 1 hour access + long-lived refresh
25
+ - Industry standard for web apps *without refresh tokens* is 7-30 days
26
+
27
+ **Alternatives Considered**:
28
+ - 1 hour: Too short without refresh mechanism, poor UX
29
+ - 24 hours: Reasonable middle ground, but 7 days is acceptable for MVP
30
+ - 30 days: Too long, increases security risk unnecessarily
31
+
32
+ **Implementation**: Set `exp` claim in JWT to 7 days (604800 seconds) from issuance
33
+
34
+ ---
35
+
36
+ ### 2. Better Auth Integration Pattern
37
+
38
+ **Question**: How should Better Auth be integrated in Next.js 16 App Router?
39
+
40
+ **Decision**: Use Better Auth with email/password provider and JWT plugin
41
+
42
+ **Research Findings**:
43
+ - Better Auth supports Next.js App Router with server-side session management
44
+ - JWT plugin allows issuing tokens that can be verified by external backends
45
+ - Configuration file: `lib/auth.ts` with email provider and JWT plugin
46
+ - Session management via Better Auth's built-in session handling
47
+ - Token accessible via `auth()` helper in server components
48
+
49
+ **Implementation Pattern**:
50
+ ```typescript
51
+ // lib/auth.ts
52
+ import { betterAuth } from "better-auth"
53
+ import { jwt } from "better-auth/plugins"
54
+
55
+ export const auth = betterAuth({
56
+ database: {
57
+ // Database connection for Better Auth's session storage
58
+ },
59
+ emailAndPassword: {
60
+ enabled: true,
61
+ },
62
+ plugins: [
63
+ jwt({
64
+ secret: process.env.BETTER_AUTH_SECRET!,
65
+ expiresIn: "7d",
66
+ })
67
+ ],
68
+ })
69
+ ```
70
+
71
+ **Alternatives Considered**:
72
+ - NextAuth.js: More popular but heavier, Better Auth is simpler for JWT use case
73
+ - Custom JWT implementation: Reinventing the wheel, Better Auth handles edge cases
74
+ - Auth0/Clerk: Third-party services, adds external dependency and cost
75
+
76
+ ---
77
+
78
+ ### 3. Backend JWT Verification Strategy
79
+
80
+ **Question**: How should FastAPI verify JWT tokens from Better Auth?
81
+
82
+ **Decision**: Use PyJWT library with FastAPI dependency injection
83
+
84
+ **Research Findings**:
85
+ - PyJWT is the standard Python library for JWT handling
86
+ - FastAPI's dependency injection system is ideal for auth middleware
87
+ - Better Auth uses HS256 (HMAC-SHA256) by default with shared secret
88
+ - Token verification should happen in a reusable dependency
89
+
90
+ **Implementation Pattern**:
91
+ ```python
92
+ # src/core/security.py
93
+ import jwt
94
+ from fastapi import HTTPException, status
95
+ from src.core.config import settings
96
+
97
+ def verify_jwt_token(token: str) -> dict:
98
+ try:
99
+ payload = jwt.decode(
100
+ token,
101
+ settings.BETTER_AUTH_SECRET,
102
+ algorithms=["HS256"]
103
+ )
104
+ return payload
105
+ except jwt.ExpiredSignatureError:
106
+ raise HTTPException(
107
+ status_code=status.HTTP_401_UNAUTHORIZED,
108
+ detail="Token has expired"
109
+ )
110
+ except jwt.InvalidTokenError:
111
+ raise HTTPException(
112
+ status_code=status.HTTP_401_UNAUTHORIZED,
113
+ detail="Invalid token"
114
+ )
115
+
116
+ # src/api/deps.py
117
+ from fastapi import Depends, HTTPException, status
118
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
119
+
120
+ security = HTTPBearer()
121
+
122
+ def get_current_user(
123
+ credentials: HTTPAuthorizationCredentials = Depends(security)
124
+ ) -> int:
125
+ token = credentials.credentials
126
+ payload = verify_jwt_token(token)
127
+ user_id = payload.get("sub") # Better Auth uses 'sub' for user ID
128
+ if not user_id:
129
+ raise HTTPException(
130
+ status_code=status.HTTP_401_UNAUTHORIZED,
131
+ detail="Invalid token payload"
132
+ )
133
+ return int(user_id)
134
+ ```
135
+
136
+ **Alternatives Considered**:
137
+ - python-jose: Older library, PyJWT is more actively maintained
138
+ - Middleware approach: Less flexible than dependency injection
139
+ - Manual token parsing: Error-prone, PyJWT handles edge cases
140
+
141
+ ---
142
+
143
+ ### 4. Password Hashing Strategy
144
+
145
+ **Question**: How should passwords be hashed and verified?
146
+
147
+ **Decision**: Use passlib with bcrypt algorithm
148
+
149
+ **Research Findings**:
150
+ - Better Auth handles password hashing on the frontend side
151
+ - Backend needs to verify passwords for custom auth endpoints (if any)
152
+ - passlib is the standard Python library for password hashing
153
+ - bcrypt is industry-standard, resistant to rainbow table attacks
154
+ - Cost factor of 12 provides good security/performance balance
155
+
156
+ **Implementation Pattern**:
157
+ ```python
158
+ # src/core/security.py
159
+ from passlib.context import CryptContext
160
+
161
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
162
+
163
+ def hash_password(password: str) -> str:
164
+ return pwd_context.hash(password)
165
+
166
+ def verify_password(plain_password: str, hashed_password: str) -> bool:
167
+ return pwd_context.verify(plain_password, hashed_password)
168
+ ```
169
+
170
+ **Note**: Since Better Auth handles authentication, backend password hashing may only be needed for:
171
+ - Admin user creation scripts
172
+ - Testing utilities
173
+ - Future direct authentication endpoints
174
+
175
+ **Alternatives Considered**:
176
+ - argon2: More modern but requires C dependencies, complicates deployment
177
+ - scrypt: Good but bcrypt is more widely supported
178
+ - Plain SHA256: Insecure, vulnerable to rainbow tables
179
+
180
+ ---
181
+
182
+ ### 5. Frontend Token Storage
183
+
184
+ **Question**: Where should JWT tokens be stored in the frontend?
185
+
186
+ **Decision**: Use Better Auth's built-in session management (httpOnly cookies)
187
+
188
+ **Research Findings**:
189
+ - Better Auth stores session tokens in httpOnly cookies by default
190
+ - This prevents XSS attacks (JavaScript cannot access the token)
191
+ - Better Auth's `auth()` helper automatically includes token in requests
192
+ - For API calls to backend, extract token from Better Auth session
193
+
194
+ **Implementation Pattern**:
195
+ ```typescript
196
+ // lib/api.ts
197
+ import { auth } from './auth'
198
+
199
+ async function fetchAPI<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
200
+ const session = await auth()
201
+ const token = session?.token // Better Auth provides token in session
202
+
203
+ const response = await fetch(`${API_BASE_URL}${endpoint}`, {
204
+ ...options,
205
+ headers: {
206
+ 'Content-Type': 'application/json',
207
+ ...(token && { 'Authorization': `Bearer ${token}` }),
208
+ ...options.headers,
209
+ },
210
+ })
211
+
212
+ // Handle 401 responses
213
+ if (response.status === 401) {
214
+ // Redirect to login
215
+ window.location.href = '/auth/signin'
216
+ }
217
+
218
+ return response.json()
219
+ }
220
+ ```
221
+
222
+ **Alternatives Considered**:
223
+ - localStorage: Vulnerable to XSS attacks
224
+ - sessionStorage: Same XSS vulnerability as localStorage
225
+ - Memory only: Lost on page refresh, poor UX
226
+
227
+ ---
228
+
229
+ ### 6. Error Handling for Authentication Failures
230
+
231
+ **Question**: How should authentication errors be communicated to users?
232
+
233
+ **Decision**: Use standardized error responses with appropriate HTTP status codes
234
+
235
+ **Research Findings**:
236
+ - 401 Unauthorized: Authentication required or failed
237
+ - 403 Forbidden: Authenticated but not authorized (not used in this spec)
238
+ - Generic error messages prevent information leakage
239
+ - Specific errors only in development mode
240
+
241
+ **Implementation Pattern**:
242
+ ```python
243
+ # Backend error responses
244
+ {
245
+ "detail": "Invalid credentials", # Generic, doesn't reveal if email or password wrong
246
+ "error_code": "AUTH_FAILED"
247
+ }
248
+
249
+ {
250
+ "detail": "Token has expired",
251
+ "error_code": "TOKEN_EXPIRED"
252
+ }
253
+
254
+ {
255
+ "detail": "Invalid token",
256
+ "error_code": "TOKEN_INVALID"
257
+ }
258
+ ```
259
+
260
+ **Security Considerations**:
261
+ - Never reveal whether email exists in database
262
+ - Never reveal which field (email/password) was incorrect
263
+ - Log detailed errors server-side for debugging
264
+ - Return generic errors to client
265
+
266
+ ---
267
+
268
+ ### 7. Database Schema Changes
269
+
270
+ **Question**: What changes are needed to the existing User model?
271
+
272
+ **Decision**: Add `password_hash` field to users table
273
+
274
+ **Research Findings**:
275
+ - Current User model has: id, email, name, created_at, updated_at
276
+ - Need to add: password_hash (string, nullable=False)
277
+ - Better Auth may also need its own tables for session management
278
+ - Migration should be reversible
279
+
280
+ **Implementation**:
281
+ ```python
282
+ # alembic/versions/002_add_user_password.py
283
+ def upgrade():
284
+ op.add_column('users', sa.Column('password_hash', sa.String(255), nullable=False))
285
+
286
+ def downgrade():
287
+ op.drop_column('users', 'password_hash')
288
+ ```
289
+
290
+ **Note**: Better Auth may create its own tables (sessions, accounts, etc.) - these should be in a separate migration or handled by Better Auth's migration system.
291
+
292
+ ---
293
+
294
+ ## Dependencies to Add
295
+
296
+ ### Backend
297
+ - `PyJWT==2.8.0` - JWT encoding/decoding
298
+ - `passlib[bcrypt]==1.7.4` - Password hashing
299
+ - `python-multipart==0.0.6` - Form data parsing (for login forms)
300
+
301
+ ### Frontend
302
+ - `better-auth` - Authentication library
303
+ - `@better-auth/react` - React hooks for Better Auth
304
+
305
+ ---
306
+
307
+ ## Environment Variables
308
+
309
+ ### Backend (.env)
310
+ ```
311
+ BETTER_AUTH_SECRET=<shared-secret-min-32-chars>
312
+ DATABASE_URL=<neon-postgres-url>
313
+ ```
314
+
315
+ ### Frontend (.env.local)
316
+ ```
317
+ BETTER_AUTH_SECRET=<same-shared-secret>
318
+ NEXT_PUBLIC_API_URL=http://localhost:8000
319
+ ```
320
+
321
+ **Critical**: BETTER_AUTH_SECRET must be identical in both frontend and backend.
322
+
323
+ ---
324
+
325
+ ## Security Checklist
326
+
327
+ - [x] Passwords hashed with bcrypt (cost factor 12)
328
+ - [x] JWT tokens signed with HS256 and shared secret
329
+ - [x] Tokens expire after 7 days
330
+ - [x] httpOnly cookies prevent XSS attacks
331
+ - [x] Generic error messages prevent information leakage
332
+ - [x] HTTPS required in production (documented in assumptions)
333
+ - [x] User ID extracted from validated token, not request parameters
334
+ - [x] All task endpoints require authentication
335
+ - [x] Database queries filtered by authenticated user ID
336
+
337
+ ---
338
+
339
+ ## Next Steps
340
+
341
+ Phase 1 will use these research findings to:
342
+ 1. Create data-model.md with User entity updates
343
+ 2. Generate API contracts for auth endpoints
344
+ 3. Create quickstart.md with setup instructions
345
+ 4. Update agent context files with new dependencies
specs/001-auth-security/spec.md ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Feature Specification: Authentication & API Security
2
+
3
+ **Feature Branch**: `001-auth-security`
4
+ **Created**: 2026-01-09
5
+ **Status**: Draft
6
+ **Input**: User description: "Authentication & API Security – Phase II Todo Web App"
7
+
8
+ ## User Scenarios & Testing *(mandatory)*
9
+
10
+ ### User Story 1 - User Sign Up (Priority: P1)
11
+
12
+ A new user visits the application and creates an account to start managing their tasks. The system securely registers the user and establishes their identity for future sessions.
13
+
14
+ **Why this priority**: Without user registration, no one can use the application. This is the entry point for all users and must work reliably.
15
+
16
+ **Independent Test**: Can be fully tested by submitting registration form with valid credentials and verifying account creation. Delivers immediate value by allowing users to establish their identity in the system.
17
+
18
+ **Acceptance Scenarios**:
19
+
20
+ 1. **Given** a new user on the sign-up page, **When** they provide valid email and password, **Then** their account is created and they receive confirmation
21
+ 2. **Given** a user attempting to sign up, **When** they provide an email that already exists, **Then** they receive a clear error message indicating the email is already registered
22
+ 3. **Given** a user on the sign-up page, **When** they provide invalid credentials (weak password, malformed email), **Then** they receive specific validation feedback before submission
23
+
24
+ ---
25
+
26
+ ### User Story 2 - User Sign In (Priority: P2)
27
+
28
+ A registered user returns to the application and signs in with their credentials. The system authenticates them and provides a secure token for accessing their personal data.
29
+
30
+ **Why this priority**: After registration, users need to authenticate to access their tasks. This enables returning users to access the application.
31
+
32
+ **Independent Test**: Can be fully tested by submitting valid credentials and verifying successful authentication with token issuance. Delivers value by allowing registered users to access their accounts.
33
+
34
+ **Acceptance Scenarios**:
35
+
36
+ 1. **Given** a registered user on the sign-in page, **When** they provide correct email and password, **Then** they are authenticated and receive a secure token
37
+ 2. **Given** a user attempting to sign in, **When** they provide incorrect credentials, **Then** they receive a generic error message without revealing which field was incorrect
38
+ 3. **Given** an authenticated user, **When** their session token is issued, **Then** the token contains their user identity and has a defined expiration time
39
+
40
+ ---
41
+
42
+ ### User Story 3 - Protected API Access (Priority: P3)
43
+
44
+ An authenticated user makes requests to the API to manage their tasks. The system verifies their identity on every request and ensures they can only access their own data.
45
+
46
+ **Why this priority**: This enforces the security boundary that prevents users from accessing each other's data. Critical for data privacy and security.
47
+
48
+ **Independent Test**: Can be fully tested by making API requests with valid tokens and verifying that only the authenticated user's data is returned. Delivers value by ensuring data isolation between users.
49
+
50
+ **Acceptance Scenarios**:
51
+
52
+ 1. **Given** an authenticated user with a valid token, **When** they request their tasks via the API, **Then** they receive only their own tasks
53
+ 2. **Given** an authenticated user, **When** they attempt to access another user's task by ID, **Then** the request is denied with appropriate error
54
+ 3. **Given** a user making an API request, **When** the token is included in the Authorization header, **Then** the backend extracts and verifies the token signature
55
+
56
+ ---
57
+
58
+ ### User Story 4 - Invalid Token Handling (Priority: P4)
59
+
60
+ A user attempts to access protected resources without a valid token (expired, malformed, or missing). The system rejects the request and returns a clear unauthorized response.
61
+
62
+ **Why this priority**: This prevents unauthorized access and provides clear feedback when authentication fails. Essential for security but lower priority than the happy path flows.
63
+
64
+ **Independent Test**: Can be fully tested by making API requests with invalid/missing tokens and verifying 401 responses. Delivers value by enforcing authentication requirements.
65
+
66
+ **Acceptance Scenarios**:
67
+
68
+ 1. **Given** a user making an API request, **When** no token is provided, **Then** the system returns 401 Unauthorized
69
+ 2. **Given** a user with an expired token, **When** they make an API request, **Then** the system returns 401 Unauthorized with indication that token is expired
70
+ 3. **Given** a user with a malformed token, **When** they make an API request, **Then** the system returns 401 Unauthorized without exposing internal error details
71
+
72
+ ---
73
+
74
+ ### Edge Cases
75
+
76
+ - What happens when a user tries to sign up with an email that's already registered?
77
+ - How does the system handle concurrent sign-in attempts from the same user?
78
+ - What happens when the shared secret (BETTER_AUTH_SECRET) is missing or misconfigured?
79
+ - How does the system handle tokens that are syntactically valid but signed with the wrong secret?
80
+ - What happens when a user's token expires mid-session while they're actively using the application?
81
+ - How does the system handle extremely long passwords or email addresses?
82
+ - What happens when the backend receives a token with valid signature but for a user that no longer exists?
83
+
84
+ ## Requirements *(mandatory)*
85
+
86
+ ### Functional Requirements
87
+
88
+ - **FR-001**: System MUST allow new users to create accounts with email and password
89
+ - **FR-002**: System MUST validate email format and password strength during registration
90
+ - **FR-003**: System MUST prevent duplicate account creation with the same email address
91
+ - **FR-004**: System MUST authenticate users by verifying their email and password credentials
92
+ - **FR-005**: System MUST issue JWT tokens upon successful authentication
93
+ - **FR-006**: System MUST include user identity (user ID, email) in the JWT token payload
94
+ - **FR-007**: System MUST sign JWT tokens using the shared secret (BETTER_AUTH_SECRET)
95
+ - **FR-008**: System MUST set token expiration time to prevent indefinite access
96
+ - **FR-009**: System MUST require JWT token in Authorization header for all protected API endpoints
97
+ - **FR-010**: System MUST verify JWT signature on every protected API request
98
+ - **FR-011**: System MUST extract user identity from verified JWT tokens
99
+ - **FR-012**: System MUST filter all task queries by the authenticated user's ID
100
+ - **FR-013**: System MUST return 401 Unauthorized for requests without valid tokens
101
+ - **FR-014**: System MUST return 401 Unauthorized for expired tokens
102
+ - **FR-015**: System MUST return 401 Unauthorized for tokens with invalid signatures
103
+ - **FR-016**: System MUST prevent users from accessing or modifying other users' tasks
104
+ - **FR-017**: System MUST use the same BETTER_AUTH_SECRET value in both frontend and backend
105
+ - **FR-018**: System MUST store passwords securely using industry-standard hashing
106
+ - **FR-019**: System MUST not expose sensitive error details in authentication failure responses
107
+ - **FR-020**: System MUST maintain stateless authentication (no server-side session storage)
108
+
109
+ ### Key Entities
110
+
111
+ - **User**: Represents a registered user account with email, hashed password, and unique identifier. Each user owns a collection of tasks and can only access their own data.
112
+ - **JWT Token**: A cryptographically signed token containing user identity claims (user ID, email, expiration time). Used to authenticate API requests without server-side session state.
113
+ - **Authentication Session**: The period during which a user's JWT token is valid, allowing them to make authenticated requests to the API.
114
+
115
+ ## Success Criteria *(mandatory)*
116
+
117
+ ### Measurable Outcomes
118
+
119
+ - **SC-001**: Users can complete account registration in under 1 minute with clear validation feedback
120
+ - **SC-002**: Users can sign in and receive authentication token in under 5 seconds
121
+ - **SC-003**: 100% of API requests without valid tokens receive 401 Unauthorized responses
122
+ - **SC-004**: 100% of authenticated users can only retrieve and modify their own tasks
123
+ - **SC-005**: System successfully verifies token signatures for 100% of valid tokens
124
+ - **SC-006**: Zero instances of users accessing other users' data in testing
125
+ - **SC-007**: Authentication flow handles 100 concurrent sign-in requests without errors
126
+ - **SC-008**: Token verification adds less than 50ms latency to API requests
127
+
128
+ ## Assumptions *(optional)*
129
+
130
+ - Better Auth library is already configured in the frontend application
131
+ - Database schema includes a users table with email and password fields
132
+ - Frontend and backend share the same BETTER_AUTH_SECRET environment variable
133
+ - JWT tokens will use HS256 (HMAC with SHA-256) signing algorithm
134
+ - Access tokens will expire after 1 hour (industry standard for web applications)
135
+ - Password requirements: minimum 8 characters, at least one uppercase, one lowercase, one number
136
+ - Email validation follows RFC 5322 standard format
137
+ - The application uses HTTPS in production to protect tokens in transit
138
+ - Rate limiting for authentication endpoints will be handled separately (not in this spec)
139
+
140
+ ## Dependencies *(optional)*
141
+
142
+ - Better Auth library must be installed and configured in the Next.js frontend
143
+ - Backend must have JWT library for token verification (e.g., PyJWT for Python)
144
+ - Database must have users table with appropriate schema
145
+ - Environment configuration must support BETTER_AUTH_SECRET in both frontend and backend
146
+ - Task CRUD API endpoints must be implemented (from Spec 001-task-crud)
147
+
148
+ ## Out of Scope *(optional)*
149
+
150
+ - OAuth providers (Google, GitHub, etc.) and social login
151
+ - Password reset and forgot password functionality
152
+ - Email verification and account activation
153
+ - Multi-factor authentication (MFA)
154
+ - Token refresh mechanism and refresh tokens
155
+ - Remember me functionality
156
+ - Session management across multiple devices
157
+ - Account deletion and data export
158
+ - Role-based access control (RBAC) beyond basic user isolation
159
+ - Rate limiting and brute force protection
160
+ - Chatbot or AI-powered features
161
+ - UI/UX polish and advanced form interactions
162
+ - Password strength meter or complexity requirements beyond basic validation
specs/001-auth-security/tasks.md ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tasks: Authentication & API Security
2
+
3
+ **Input**: Design documents from `/specs/001-auth-security/`
4
+ **Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/
5
+
6
+ **Organization**: Tasks are grouped by user story to enable independent implementation and testing.
7
+
8
+ ## Format: `[ID] [P?] [Story] Description`
9
+
10
+ - **[P]**: Can run in parallel (different files, no dependencies)
11
+ - **[Story]**: Which user story this task belongs to (US1, US2, US3, US4)
12
+ - Include exact file paths in descriptions
13
+
14
+ ---
15
+
16
+ ## Phase 1: Setup (Shared Infrastructure)
17
+
18
+ **Purpose**: Project initialization and dependency installation
19
+
20
+ - [x] T001 Add PyJWT==2.8.0, passlib[bcrypt]==1.7.4, python-multipart==0.0.6 to backend/requirements.txt
21
+ - [x] T002 Install backend dependencies with pip install -r backend/requirements.txt
22
+ - [x] T003 [P] Add better-auth and @better-auth/react to frontend/package.json
23
+ - [x] T004 [P] Install frontend dependencies with npm install in frontend/
24
+ - [x] T005 [P] Add BETTER_AUTH_SECRET to backend/.env (generate 32+ char random string)
25
+ - [x] T006 [P] Add BETTER_AUTH_SECRET to frontend/.env.local (same value as backend)
26
+
27
+ ---
28
+
29
+ ## Phase 2: Foundational (Blocking Prerequisites)
30
+
31
+ **Purpose**: Core infrastructure that MUST be complete before ANY user story
32
+
33
+ **⚠️ CRITICAL**: No user story work can begin until this phase is complete
34
+
35
+ - [x] T007 Create backend/src/core/security.py with password hashing and JWT functions
36
+ - [x] T008 Update backend/src/core/config.py to add BETTER_AUTH_SECRET (required, not optional)
37
+ - [x] T009 Add password_hash field to User model in backend/src/models/user.py
38
+ - [x] T010 Create database migration backend/alembic/versions/002_add_user_password.py
39
+ - [x] T011 Run alembic upgrade head to apply password_hash migration
40
+ - [x] T012 Create backend/src/schemas/auth.py with SignupRequest, SigninRequest, TokenResponse schemas
41
+ - [x] T013 Create frontend/src/lib/auth.ts with Better Auth configuration (email/password + JWT plugin)
42
+
43
+ **Checkpoint**: Foundation ready - user story implementation can now begin in parallel
44
+
45
+ ---
46
+
47
+ ## Phase 3: User Story 1 - User Sign Up (Priority: P1) 🎯 MVP
48
+
49
+ **Goal**: New users can create accounts with email and password
50
+
51
+ **Independent Test**: Submit signup form with valid credentials and verify account creation in database
52
+
53
+ ### Implementation for User Story 1
54
+
55
+ - [x] T014 [P] [US1] Create backend/src/services/auth_service.py with signup method (hash password, create user)
56
+ - [x] T015 [P] [US1] Create backend/src/api/routes/auth.py with POST /api/auth/signup endpoint
57
+ - [x] T016 [US1] Add email validation (RFC 5322 format) in signup endpoint
58
+ - [x] T017 [US1] Add password validation (min 8 chars, uppercase, lowercase, number) in signup endpoint
59
+ - [x] T018 [US1] Handle duplicate email error (409 Conflict) in signup endpoint
60
+ - [x] T019 [P] [US1] Create frontend/src/components/auth/SignUpForm.tsx with form fields and validation
61
+ - [x] T020 [P] [US1] Create frontend/src/app/auth/signup/page.tsx using SignUpForm component
62
+ - [x] T021 [US1] Connect SignUpForm to Better Auth signup API
63
+
64
+ **Checkpoint**: Users can successfully sign up and create accounts
65
+
66
+ ---
67
+
68
+ ## Phase 4: User Story 2 - User Sign In (Priority: P2)
69
+
70
+ **Goal**: Registered users can sign in and receive JWT tokens
71
+
72
+ **Independent Test**: Submit signin form with valid credentials and verify JWT token is issued
73
+
74
+ ### Implementation for User Story 2
75
+
76
+ - [x] T022 [US2] Add signin method to backend/src/services/auth_service.py (verify password, create JWT)
77
+ - [x] T023 [US2] Add POST /api/auth/signin endpoint to backend/src/api/routes/auth.py
78
+ - [x] T024 [US2] Return JWT token with 7-day expiration in signin response
79
+ - [x] T025 [US2] Handle invalid credentials with generic error (401 Unauthorized)
80
+ - [x] T026 [P] [US2] Create frontend/src/components/auth/SignInForm.tsx with email/password fields
81
+ - [x] T027 [P] [US2] Create frontend/src/app/auth/signin/page.tsx using SignInForm component
82
+ - [x] T028 [US2] Connect SignInForm to Better Auth signin API
83
+ - [x] T029 [US2] Store JWT token in httpOnly cookie via Better Auth session
84
+
85
+ **Checkpoint**: Users can sign in and receive valid JWT tokens
86
+
87
+ ---
88
+
89
+ ## Phase 5: User Story 3 - Protected API Access (Priority: P3)
90
+
91
+ **Goal**: Authenticated users can access API with JWT tokens and only see their own data
92
+
93
+ **Independent Test**: Make API request with valid token and verify only authenticated user's tasks are returned
94
+
95
+ ### Implementation for User Story 3
96
+
97
+ - [x] T030 [US3] Update backend/src/api/deps.py get_current_user to extract and verify JWT from Authorization header
98
+ - [x] T031 [US3] Add HTTPBearer security scheme to get_current_user dependency
99
+ - [x] T032 [US3] Extract user_id from JWT 'sub' claim in get_current_user
100
+ - [x] T033 [US3] Return 401 Unauthorized if token is missing in get_current_user
101
+ - [x] T034 [P] [US3] Update frontend/src/lib/api.ts fetchAPI to include Authorization: Bearer header
102
+ - [x] T035 [P] [US3] Get JWT token from Better Auth session in fetchAPI
103
+ - [x] T036 [US3] Verify all task endpoints filter by authenticated user_id (already implemented, just verify)
104
+ - [x] T037 [US3] Add GET /api/auth/me endpoint to return current user profile
105
+
106
+ **Checkpoint**: API requests require valid JWT tokens and enforce user data isolation
107
+
108
+ ---
109
+
110
+ ## Phase 6: User Story 4 - Invalid Token Handling (Priority: P4)
111
+
112
+ **Goal**: System rejects invalid, expired, or missing tokens with clear error responses
113
+
114
+ **Independent Test**: Make API requests with invalid/missing tokens and verify 401 responses
115
+
116
+ ### Implementation for User Story 4
117
+
118
+ - [x] T038 [P] [US4] Handle expired token error (jwt.ExpiredSignatureError) in backend/src/core/security.py
119
+ - [x] T039 [P] [US4] Handle invalid signature error (jwt.InvalidTokenError) in backend/src/core/security.py
120
+ - [x] T040 [P] [US4] Handle malformed token error in backend/src/api/deps.py get_current_user
121
+ - [x] T041 [US4] Return 401 with error_code TOKEN_EXPIRED for expired tokens
122
+ - [x] T042 [US4] Return 401 with error_code TOKEN_INVALID for invalid tokens
123
+ - [x] T043 [US4] Return 401 with error_code TOKEN_MISSING for missing tokens
124
+ - [x] T044 [US4] Add 401 error handling in frontend/src/lib/api.ts to redirect to /auth/signin
125
+
126
+ **Checkpoint**: All authentication errors are handled gracefully with appropriate responses
127
+
128
+ ---
129
+
130
+ ## Phase 7: Polish & Cross-Cutting Concerns
131
+
132
+ **Purpose**: Integration, testing, and documentation
133
+
134
+ - [x] T045 [P] Create frontend/src/providers/AuthProvider.tsx to wrap app with Better Auth context
135
+ - [x] T046 [P] Update frontend/src/app/layout.tsx to include AuthProvider
136
+ - [x] T047 Protect frontend/src/app/page.tsx (task list) to require authentication
137
+ - [x] T047.1 Register auth router in backend/src/main.py (bugfix)
138
+ - [ ] T048 Test signup flow end-to-end (frontend → backend → database)
139
+ - [ ] T049 Test signin flow end-to-end (frontend → backend → JWT issuance)
140
+ - [ ] T050 Test protected API access (valid token → success, invalid → 401)
141
+ - [ ] T051 Test user data isolation (user A cannot access user B's tasks)
142
+ - [x] T052 Verify BETTER_AUTH_SECRET is identical in frontend and backend .env files
143
+ - [x] T053 Update backend/README.md with authentication setup instructions
144
+ - [x] T054 Update frontend/README.md with Better Auth configuration notes
145
+
146
+ ---
147
+
148
+ ## Dependencies & Execution Order
149
+
150
+ ### Phase Dependencies
151
+
152
+ - **Setup (Phase 1)**: No dependencies - can start immediately
153
+ - **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
154
+ - **User Stories (Phase 3-6)**: All depend on Foundational phase completion
155
+ - User stories can proceed in parallel (if staffed)
156
+ - Or sequentially in priority order (P1 → P2 → P3 → P4)
157
+ - **Polish (Phase 7)**: Depends on all user stories being complete
158
+
159
+ ### User Story Dependencies
160
+
161
+ - **User Story 1 (P1)**: Can start after Foundational - No dependencies on other stories
162
+ - **User Story 2 (P2)**: Can start after Foundational - Depends on US1 (needs User model with password_hash)
163
+ - **User Story 3 (P3)**: Can start after Foundational - Depends on US2 (needs JWT tokens to be issued)
164
+ - **User Story 4 (P4)**: Can start after US3 - Depends on JWT verification being implemented
165
+
166
+ ### Within Each User Story
167
+
168
+ - Backend services before endpoints
169
+ - Backend endpoints before frontend components
170
+ - Frontend components before frontend pages
171
+ - Core implementation before error handling
172
+
173
+ ### Parallel Opportunities
174
+
175
+ - **Phase 1**: T003, T004, T005, T006 can run in parallel
176
+ - **Phase 3 (US1)**: T014, T015 (backend) can run parallel with T019, T020 (frontend)
177
+ - **Phase 4 (US2)**: T026, T027 (frontend) can run parallel with backend work
178
+ - **Phase 5 (US3)**: T034, T035 (frontend) can run parallel with backend work
179
+ - **Phase 6 (US4)**: T038, T039, T040 can run in parallel
180
+ - **Phase 7**: T045, T046, T053, T054 can run in parallel
181
+
182
+ ---
183
+
184
+ ## Parallel Example: User Story 1
185
+
186
+ ```bash
187
+ # Launch backend and frontend tasks together:
188
+ Task: "Create backend/src/services/auth_service.py with signup method"
189
+ Task: "Create backend/src/api/routes/auth.py with POST /api/auth/signup endpoint"
190
+ Task: "Create frontend/src/components/auth/SignUpForm.tsx"
191
+ Task: "Create frontend/src/app/auth/signup/page.tsx"
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Implementation Strategy
197
+
198
+ ### MVP First (User Story 1 Only)
199
+
200
+ 1. Complete Phase 1: Setup (T001-T006)
201
+ 2. Complete Phase 2: Foundational (T007-T013) - CRITICAL
202
+ 3. Complete Phase 3: User Story 1 (T014-T021)
203
+ 4. **STOP and VALIDATE**: Test signup independently
204
+ 5. Deploy/demo if ready
205
+
206
+ ### Incremental Delivery
207
+
208
+ 1. Setup + Foundational → Foundation ready
209
+ 2. Add User Story 1 → Test independently → Deploy (MVP!)
210
+ 3. Add User Story 2 → Test independently → Deploy
211
+ 4. Add User Story 3 → Test independently → Deploy
212
+ 5. Add User Story 4 → Test independently → Deploy
213
+ 6. Polish → Final deployment
214
+
215
+ ### Parallel Team Strategy
216
+
217
+ With multiple developers:
218
+
219
+ 1. Team completes Setup + Foundational together
220
+ 2. Once Foundational is done:
221
+ - Developer A: User Story 1 (signup)
222
+ - Developer B: User Story 2 (signin) - starts after US1 model is ready
223
+ - Developer C: User Story 3 (API protection) - starts after US2 tokens are ready
224
+ 3. Stories integrate independently
225
+
226
+ ---
227
+
228
+ ## Notes
229
+
230
+ - Total tasks: 54
231
+ - MVP scope: Phase 1 + Phase 2 + Phase 3 (User Story 1) = 21 tasks
232
+ - [P] tasks = different files, no dependencies
233
+ - [Story] label maps task to specific user story
234
+ - Each user story should be independently testable
235
+ - Commit after each task or logical group
236
+ - Verify BETTER_AUTH_SECRET matches in both .env files
237
+ - Test authentication flow end-to-end before moving to next story
specs/001-openai-agent-mcp-tools/checklists/requirements.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Specification Quality Checklist: OpenAI Agent MCP Tools
2
+
3
+ **Purpose**: Validate specification completeness and quality before proceeding to planning
4
+ **Created**: 2026-01-14
5
+ **Feature**: [spec.md](../spec.md)
6
+
7
+ ## Content Quality
8
+
9
+ - [x] No implementation details (languages, frameworks, APIs)
10
+ - [x] Focused on user value and business needs
11
+ - [x] Written for non-technical stakeholders
12
+ - [x] All mandatory sections completed
13
+
14
+ ## Requirement Completeness
15
+
16
+ - [x] No [NEEDS CLARIFICATION] markers remain
17
+ - [x] Requirements are testable and unambiguous
18
+ - [x] Success criteria are measurable
19
+ - [x] Success criteria are technology-agnostic (no implementation details)
20
+ - [x] All acceptance scenarios are defined
21
+ - [x] Edge cases are identified
22
+ - [x] Scope is clearly bounded
23
+ - [x] Dependencies and assumptions identified
24
+
25
+ ## Feature Readiness
26
+
27
+ - [x] All functional requirements have clear acceptance criteria
28
+ - [x] User scenarios cover primary flows
29
+ - [x] Feature meets measurable outcomes defined in Success Criteria
30
+ - [x] No implementation details leak into specification
31
+
32
+ ## Validation Results
33
+
34
+ **Status**: ✅ PASSED
35
+
36
+ **Issues Found**: None
37
+
38
+ **Analysis**:
39
+
40
+ 1. **Content Quality**: The specification is written from a user and business perspective. While it mentions specific technologies (OpenAI Agents SDK, MCP SDK, Cohere), these are part of the explicit requirements provided by the user in the feature description. The spec focuses on what the system must do, not how to implement it at a code level.
41
+
42
+ 2. **Requirement Completeness**: All 44 functional requirements are testable and unambiguous. No [NEEDS CLARIFICATION] markers remain because the user provided a comprehensive feature description with explicit technical constraints.
43
+
44
+ 3. **Success Criteria**: All 10 success criteria are measurable and technology-agnostic from a user perspective (e.g., "95% success rate", "within 5 seconds", "50 concurrent users").
45
+
46
+ 4. **User Scenarios**: 5 prioritized user stories (P1-P5) cover the complete CRUD workflow for task management via natural language, each with independent test criteria and acceptance scenarios.
47
+
48
+ 5. **Edge Cases**: 7 edge cases identified covering API failures, ambiguous requests, concurrent access, and context window limits.
49
+
50
+ 6. **Scope**: Clear boundaries defined with explicit "Out of Scope" section listing 15 excluded items.
51
+
52
+ 7. **Dependencies**: All dependencies and assumptions clearly documented.
53
+
54
+ ## Notes
55
+
56
+ - The specification is ready for `/sp.plan` execution
57
+ - No clarifications needed from the user
58
+ - All mandatory sections are complete and meet quality standards
specs/001-openai-agent-mcp-tools/contracts/add_task.json ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "add_task",
3
+ "description": "Add a new task to the user's todo list. Creates a task with a title and optional description, due date, and priority.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "title": {
8
+ "type": "string",
9
+ "description": "The title of the task (required, max 200 characters)",
10
+ "maxLength": 200
11
+ },
12
+ "description": {
13
+ "type": "string",
14
+ "description": "Optional detailed description of the task (max 1000 characters)",
15
+ "maxLength": 1000
16
+ },
17
+ "due_date": {
18
+ "type": "string",
19
+ "description": "Optional due date in ISO 8601 format (YYYY-MM-DD)",
20
+ "format": "date"
21
+ },
22
+ "priority": {
23
+ "type": "string",
24
+ "description": "Optional priority level",
25
+ "enum": ["low", "medium", "high"]
26
+ }
27
+ },
28
+ "required": ["title"]
29
+ },
30
+ "returns": {
31
+ "type": "object",
32
+ "properties": {
33
+ "success": {
34
+ "type": "boolean",
35
+ "description": "Whether the task was created successfully"
36
+ },
37
+ "task": {
38
+ "type": "object",
39
+ "description": "The created task object",
40
+ "properties": {
41
+ "id": {
42
+ "type": "integer",
43
+ "description": "Unique task ID"
44
+ },
45
+ "title": {
46
+ "type": "string",
47
+ "description": "Task title"
48
+ },
49
+ "description": {
50
+ "type": "string",
51
+ "description": "Task description"
52
+ },
53
+ "completed": {
54
+ "type": "boolean",
55
+ "description": "Task completion status"
56
+ },
57
+ "created_at": {
58
+ "type": "string",
59
+ "description": "Task creation timestamp"
60
+ }
61
+ }
62
+ },
63
+ "message": {
64
+ "type": "string",
65
+ "description": "User-friendly confirmation message"
66
+ }
67
+ }
68
+ }
69
+ }
specs/001-openai-agent-mcp-tools/contracts/complete_task.json ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "complete_task",
3
+ "description": "Mark a task as completed. Accepts either a task ID (integer) or task title (string) to identify the task.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "task_identifier": {
8
+ "oneOf": [
9
+ {
10
+ "type": "integer",
11
+ "description": "Task ID"
12
+ },
13
+ {
14
+ "type": "string",
15
+ "description": "Task title (exact match)"
16
+ }
17
+ ],
18
+ "description": "Task ID or title to identify which task to complete"
19
+ }
20
+ },
21
+ "required": ["task_identifier"]
22
+ },
23
+ "returns": {
24
+ "type": "object",
25
+ "properties": {
26
+ "success": {
27
+ "type": "boolean",
28
+ "description": "Whether the task was marked as completed"
29
+ },
30
+ "task": {
31
+ "type": "object",
32
+ "description": "The updated task object",
33
+ "properties": {
34
+ "id": {
35
+ "type": "integer",
36
+ "description": "Unique task ID"
37
+ },
38
+ "title": {
39
+ "type": "string",
40
+ "description": "Task title"
41
+ },
42
+ "completed": {
43
+ "type": "boolean",
44
+ "description": "Task completion status (should be true)"
45
+ },
46
+ "updated_at": {
47
+ "type": "string",
48
+ "description": "Task update timestamp"
49
+ }
50
+ }
51
+ },
52
+ "message": {
53
+ "type": "string",
54
+ "description": "User-friendly confirmation message"
55
+ },
56
+ "error": {
57
+ "type": "string",
58
+ "description": "Error message if task not found or operation failed"
59
+ }
60
+ }
61
+ }
62
+ }
specs/001-openai-agent-mcp-tools/contracts/delete_task.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "delete_task",
3
+ "description": "Delete a task permanently. Accepts either a task ID (integer) or task title (string) to identify the task.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "task_identifier": {
8
+ "oneOf": [
9
+ {
10
+ "type": "integer",
11
+ "description": "Task ID"
12
+ },
13
+ {
14
+ "type": "string",
15
+ "description": "Task title (exact match)"
16
+ }
17
+ ],
18
+ "description": "Task ID or title to identify which task to delete"
19
+ }
20
+ },
21
+ "required": ["task_identifier"]
22
+ },
23
+ "returns": {
24
+ "type": "object",
25
+ "properties": {
26
+ "success": {
27
+ "type": "boolean",
28
+ "description": "Whether the task was deleted successfully"
29
+ },
30
+ "message": {
31
+ "type": "string",
32
+ "description": "User-friendly confirmation message"
33
+ },
34
+ "error": {
35
+ "type": "string",
36
+ "description": "Error message if task not found or operation failed"
37
+ }
38
+ }
39
+ }
40
+ }
specs/001-openai-agent-mcp-tools/contracts/list_tasks.json ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "list_tasks",
3
+ "description": "List all tasks for the authenticated user. Supports filtering by completion status.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "filter": {
8
+ "type": "string",
9
+ "description": "Filter tasks by completion status",
10
+ "enum": ["all", "completed", "incomplete"],
11
+ "default": "all"
12
+ }
13
+ },
14
+ "required": []
15
+ },
16
+ "returns": {
17
+ "type": "object",
18
+ "properties": {
19
+ "success": {
20
+ "type": "boolean",
21
+ "description": "Whether the operation succeeded"
22
+ },
23
+ "tasks": {
24
+ "type": "array",
25
+ "description": "List of tasks matching the filter",
26
+ "items": {
27
+ "type": "object",
28
+ "properties": {
29
+ "id": {
30
+ "type": "integer",
31
+ "description": "Unique task ID"
32
+ },
33
+ "title": {
34
+ "type": "string",
35
+ "description": "Task title"
36
+ },
37
+ "description": {
38
+ "type": "string",
39
+ "description": "Task description"
40
+ },
41
+ "completed": {
42
+ "type": "boolean",
43
+ "description": "Task completion status"
44
+ },
45
+ "created_at": {
46
+ "type": "string",
47
+ "description": "Task creation timestamp"
48
+ }
49
+ }
50
+ }
51
+ },
52
+ "count": {
53
+ "type": "integer",
54
+ "description": "Total number of tasks returned"
55
+ },
56
+ "message": {
57
+ "type": "string",
58
+ "description": "User-friendly message describing the results"
59
+ }
60
+ }
61
+ }
62
+ }
specs/001-openai-agent-mcp-tools/contracts/update_task.json ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "update_task",
3
+ "description": "Update an existing task's properties. Accepts either a task ID (integer) or task title (string) to identify the task, and a dictionary of fields to update.",
4
+ "parameters": {
5
+ "type": "object",
6
+ "properties": {
7
+ "task_identifier": {
8
+ "oneOf": [
9
+ {
10
+ "type": "integer",
11
+ "description": "Task ID"
12
+ },
13
+ {
14
+ "type": "string",
15
+ "description": "Task title (exact match)"
16
+ }
17
+ ],
18
+ "description": "Task ID or title to identify which task to update"
19
+ },
20
+ "updates": {
21
+ "type": "object",
22
+ "description": "Dictionary of fields to update",
23
+ "properties": {
24
+ "title": {
25
+ "type": "string",
26
+ "description": "New task title (max 200 characters)",
27
+ "maxLength": 200
28
+ },
29
+ "description": {
30
+ "type": "string",
31
+ "description": "New task description (max 1000 characters)",
32
+ "maxLength": 1000
33
+ },
34
+ "due_date": {
35
+ "type": "string",
36
+ "description": "New due date in ISO 8601 format (YYYY-MM-DD)",
37
+ "format": "date"
38
+ },
39
+ "priority": {
40
+ "type": "string",
41
+ "description": "New priority level",
42
+ "enum": ["low", "medium", "high"]
43
+ },
44
+ "completed": {
45
+ "type": "boolean",
46
+ "description": "New completion status"
47
+ }
48
+ },
49
+ "minProperties": 1
50
+ }
51
+ },
52
+ "required": ["task_identifier", "updates"]
53
+ },
54
+ "returns": {
55
+ "type": "object",
56
+ "properties": {
57
+ "success": {
58
+ "type": "boolean",
59
+ "description": "Whether the task was updated successfully"
60
+ },
61
+ "task": {
62
+ "type": "object",
63
+ "description": "The updated task object",
64
+ "properties": {
65
+ "id": {
66
+ "type": "integer",
67
+ "description": "Unique task ID"
68
+ },
69
+ "title": {
70
+ "type": "string",
71
+ "description": "Task title"
72
+ },
73
+ "description": {
74
+ "type": "string",
75
+ "description": "Task description"
76
+ },
77
+ "completed": {
78
+ "type": "boolean",
79
+ "description": "Task completion status"
80
+ },
81
+ "updated_at": {
82
+ "type": "string",
83
+ "description": "Task update timestamp"
84
+ }
85
+ }
86
+ },
87
+ "message": {
88
+ "type": "string",
89
+ "description": "User-friendly confirmation message"
90
+ },
91
+ "error": {
92
+ "type": "string",
93
+ "description": "Error message if task not found or operation failed"
94
+ }
95
+ }
96
+ }
97
+ }
specs/001-openai-agent-mcp-tools/data-model.md ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Model: OpenAI Agent MCP Tools
2
+
3
+ **Feature**: 001-openai-agent-mcp-tools
4
+ **Date**: 2026-01-14
5
+ **Phase**: Phase 1 - Design & Contracts
6
+
7
+ ## Overview
8
+
9
+ This document defines the runtime entities and data flow for the AI agent with MCP tools implementation. Note that these are primarily runtime entities, not new database tables. Existing database models (Task, Conversation, Message) remain unchanged.
10
+
11
+ ---
12
+
13
+ ## Runtime Entities
14
+
15
+ ### 1. AgentConfiguration
16
+
17
+ **Purpose**: Runtime configuration for agent initialization with provider selection.
18
+
19
+ **Type**: Runtime configuration object (not persisted to database)
20
+
21
+ **Attributes**:
22
+
23
+ | Attribute | Type | Description | Source |
24
+ |-----------|------|-------------|--------|
25
+ | `provider_type` | `str` | Provider identifier: "gemini", "openrouter", "cohere" | Environment variable `LLM_PROVIDER` |
26
+ | `model_name` | `str` | Model identifier (e.g., "gemini-1.5-flash") | Provider-specific default or env var |
27
+ | `api_key` | `str` | API key for the provider | Environment variable (provider-specific) |
28
+ | `context_window_size` | `int` | Maximum context window in tokens | Provider-specific constant |
29
+ | `max_tokens` | `int` | Maximum tokens per response | Provider-specific constant |
30
+ | `temperature` | `float` | Sampling temperature (0.0-1.0) | Default: 0.7 |
31
+ | `fallback_provider` | `Optional[str]` | Fallback provider if primary fails | Environment variable `FALLBACK_PROVIDER` |
32
+
33
+ **Example**:
34
+
35
+ ```python
36
+ @dataclass
37
+ class AgentConfiguration:
38
+ provider_type: str
39
+ model_name: str
40
+ api_key: str
41
+ context_window_size: int
42
+ max_tokens: int
43
+ temperature: float = 0.7
44
+ fallback_provider: Optional[str] = None
45
+
46
+ @classmethod
47
+ def from_environment(cls) -> "AgentConfiguration":
48
+ """Load configuration from environment variables."""
49
+ provider_type = os.getenv("LLM_PROVIDER", "gemini")
50
+
51
+ if provider_type == "gemini":
52
+ return cls(
53
+ provider_type="gemini",
54
+ model_name="gemini-1.5-flash",
55
+ api_key=os.getenv("GEMINI_API_KEY"),
56
+ context_window_size=1_000_000,
57
+ max_tokens=8192,
58
+ fallback_provider=os.getenv("FALLBACK_PROVIDER")
59
+ )
60
+ # ... other providers
61
+ ```
62
+
63
+ ---
64
+
65
+ ### 2. ToolExecutionResult
66
+
67
+ **Purpose**: Represents the outcome of an MCP tool invocation.
68
+
69
+ **Type**: Runtime result object (not persisted separately, stored in Message.metadata)
70
+
71
+ **Attributes**:
72
+
73
+ | Attribute | Type | Description |
74
+ |-----------|------|-------------|
75
+ | `tool_name` | `str` | Name of the executed tool |
76
+ | `success` | `bool` | Whether the tool execution succeeded |
77
+ | `data` | `dict` | Tool-specific result data (task object or list of tasks) |
78
+ | `error_message` | `Optional[str]` | Error message if execution failed |
79
+ | `execution_timestamp` | `datetime` | When the tool was executed |
80
+
81
+ **Example**:
82
+
83
+ ```python
84
+ @dataclass
85
+ class ToolExecutionResult:
86
+ tool_name: str
87
+ success: bool
88
+ data: dict
89
+ error_message: Optional[str] = None
90
+ execution_timestamp: datetime = field(default_factory=datetime.utcnow)
91
+
92
+ def to_dict(self) -> dict:
93
+ """Convert to dictionary for storage in Message.metadata."""
94
+ return {
95
+ "tool_name": self.tool_name,
96
+ "success": self.success,
97
+ "data": self.data,
98
+ "error_message": self.error_message,
99
+ "execution_timestamp": self.execution_timestamp.isoformat()
100
+ }
101
+ ```
102
+
103
+ ---
104
+
105
+ ### 3. AgentRequestContext
106
+
107
+ **Purpose**: Context needed for agent execution, assembled per request.
108
+
109
+ **Type**: Runtime context object (not persisted)
110
+
111
+ **Attributes**:
112
+
113
+ | Attribute | Type | Description |
114
+ |-----------|------|-------------|
115
+ | `user_id` | `int` | Authenticated user ID from JWT token |
116
+ | `conversation_id` | `int` | Conversation ID for this chat session |
117
+ | `message_history` | `List[dict]` | Formatted message history for agent |
118
+ | `jwt_token` | `str` | JWT token for authentication (not passed to agent) |
119
+ | `system_prompt` | `str` | System prompt for agent behavior |
120
+
121
+ **Example**:
122
+
123
+ ```python
124
+ @dataclass
125
+ class AgentRequestContext:
126
+ user_id: int
127
+ conversation_id: int
128
+ message_history: List[dict]
129
+ jwt_token: str
130
+ system_prompt: str
131
+
132
+ @classmethod
133
+ async def from_request(
134
+ cls,
135
+ user_id: int,
136
+ conversation_id: Optional[int],
137
+ jwt_token: str,
138
+ db: Session
139
+ ) -> "AgentRequestContext":
140
+ """Build context from request parameters."""
141
+ conversation_service = ConversationService(db)
142
+
143
+ # Get or create conversation
144
+ conversation = await conversation_service.get_or_create_conversation(
145
+ user_id=user_id,
146
+ conversation_id=conversation_id
147
+ )
148
+
149
+ # Load and format message history
150
+ messages = await conversation_service.get_messages(conversation.id)
151
+ message_history = await conversation_service.format_messages_for_agent(
152
+ messages=messages,
153
+ max_messages=20,
154
+ max_tokens=8000
155
+ )
156
+
157
+ return cls(
158
+ user_id=user_id,
159
+ conversation_id=conversation.id,
160
+ message_history=message_history,
161
+ jwt_token=jwt_token,
162
+ system_prompt=get_default_system_prompt()
163
+ )
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Existing Database Models (No Changes)
169
+
170
+ ### Task Model
171
+
172
+ **Table**: `tasks`
173
+
174
+ **Attributes** (existing, no changes):
175
+ - `id`: Primary key
176
+ - `user_id`: Foreign key to users table (indexed)
177
+ - `title`: Task title (max 200 chars)
178
+ - `description`: Optional description (max 1000 chars)
179
+ - `completed`: Boolean flag (indexed)
180
+ - `created_at`: Timestamp (indexed)
181
+ - `updated_at`: Timestamp
182
+
183
+ **Note**: No changes to Task model. MCP tools interact with existing schema.
184
+
185
+ ---
186
+
187
+ ### Conversation Model
188
+
189
+ **Table**: `conversation`
190
+
191
+ **Attributes** (existing, no changes):
192
+ - `id`: Primary key
193
+ - `user_id`: Foreign key to users table (indexed)
194
+ - `title`: Optional conversation title
195
+ - `created_at`: Timestamp (indexed)
196
+ - `updated_at`: Timestamp
197
+
198
+ **Note**: No changes to Conversation model.
199
+
200
+ ---
201
+
202
+ ### Message Model
203
+
204
+ **Table**: `message`
205
+
206
+ **Attributes** (existing, with metadata usage):
207
+ - `id`: Primary key
208
+ - `conversation_id`: Foreign key to conversation table
209
+ - `role`: Message role ("user" or "assistant")
210
+ - `content`: Message content (text)
211
+ - `metadata`: JSON field for storing tool calls and results (existing field, new usage)
212
+ - `created_at`: Timestamp
213
+
214
+ **Metadata Structure** (new usage of existing field):
215
+
216
+ ```json
217
+ {
218
+ "tool_calls": [
219
+ {
220
+ "name": "add_task",
221
+ "arguments": {
222
+ "title": "Buy groceries",
223
+ "description": "Milk, eggs, bread"
224
+ }
225
+ }
226
+ ],
227
+ "tool_results": [
228
+ {
229
+ "tool_name": "add_task",
230
+ "success": true,
231
+ "data": {
232
+ "id": 123,
233
+ "title": "Buy groceries",
234
+ "completed": false
235
+ },
236
+ "execution_timestamp": "2026-01-14T12:00:00Z"
237
+ }
238
+ ]
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Stateless Request Cycle Flow
245
+
246
+ ### Flow Diagram
247
+
248
+ ```
249
+ ┌─────────────────────────────────────────────────────────────────┐
250
+ │ 1. Receive Chat Request │
251
+ │ POST /api/{user_id}/chat │
252
+ │ - Validate JWT token │
253
+ │ - Extract user_id, conversation_id │
254
+ └────────────────────────────┬────────────────────────────────────┘
255
+
256
+
257
+ ┌─────────────────────────────────────────────────────────────────┐
258
+ │ 2. Load Conversation History (Database) │
259
+ │ ConversationService.get_or_create_conversation() │
260
+ │ ConversationService.get_messages() │
261
+ │ ConversationService.format_messages_for_agent() │
262
+ │ - Query: SELECT * FROM message WHERE conversation_id = ? │
263
+ │ - Trim to last 20 messages, max 8000 tokens │
264
+ └────────────────────────────┬────────────────────────────────────┘
265
+
266
+
267
+ ┌─────────────────────────────────────────────────────────────────┐
268
+ │ 3. Store User Message (Database) │
269
+ │ ConversationService.add_message() │
270
+ │ - INSERT INTO message (conversation_id, role, content) │
271
+ │ - role = "user" │
272
+ └────────────────────────────┬────────────────────────────────────┘
273
+
274
+
275
+ ┌─────────────────────────────────────────────────────────────────┐
276
+ │ 4. Execute Agent (Stateless) │
277
+ │ AgentRunner.execute() │
278
+ │ ┌──────────────────────────────────────────────────────────┐ │
279
+ │ │ 4a. Get tool definitions from MCPToolRegistry │ │
280
+ │ │ 4b. Call LLM with tools (Gemini API) │ │
281
+ │ │ 4c. If tool_calls present: │ │
282
+ │ │ - Execute each tool via MCPToolRegistry │ │
283
+ │ │ - Inject user_id for security │ │
284
+ │ │ - Collect tool results │ │
285
+ │ │ 4d. Call LLM with tool results │ │
286
+ │ │ 4e. Return final response │ │
287
+ │ └──────────────────────────────────────────────────────────┘ │
288
+ └────────────────────────────┬────────────────────────────────────┘
289
+
290
+
291
+ ┌─────────────────────────────────────────────────────────────────┐
292
+ │ 5. Persist Agent Response (Database) │
293
+ │ ConversationService.add_message() │
294
+ │ - INSERT INTO message (conversation_id, role, content, metadata)│
295
+ │ - role = "assistant" │
296
+ │ - metadata = {tool_calls, tool_results} │
297
+ └────────────────────────────┬────────────────────────────────────┘
298
+
299
+
300
+ ┌─────────────────────────────────────────────────────────────────┐
301
+ │ 6. Return Response │
302
+ │ ChatResponse(message, conversation_id) │
303
+ └─────────────────────────────────────────────────────────────────┘
304
+ ```
305
+
306
+ ### Detailed Flow Steps
307
+
308
+ #### Step 1: Receive Chat Request
309
+
310
+ **Endpoint**: `POST /api/{user_id}/chat`
311
+
312
+ **Input**: `ChatRequest`
313
+ ```python
314
+ class ChatRequest(BaseModel):
315
+ message: str
316
+ conversation_id: Optional[int] = None
317
+ ```
318
+
319
+ **Authentication**: JWT token validated via `get_current_user` dependency
320
+
321
+ **Authorization**: Verify `current_user["id"] == user_id`
322
+
323
+ ---
324
+
325
+ #### Step 2: Load Conversation History
326
+
327
+ **Service**: `ConversationService`
328
+
329
+ **Operations**:
330
+ 1. Get or create conversation:
331
+ ```python
332
+ conversation = await conversation_service.get_or_create_conversation(
333
+ user_id=user_id,
334
+ conversation_id=request.conversation_id
335
+ )
336
+ ```
337
+
338
+ 2. Load messages:
339
+ ```python
340
+ messages = await conversation_service.get_messages(conversation.id)
341
+ ```
342
+
343
+ 3. Format and trim for agent:
344
+ ```python
345
+ message_history = await conversation_service.format_messages_for_agent(
346
+ messages=messages,
347
+ max_messages=20,
348
+ max_tokens=8000
349
+ )
350
+ ```
351
+
352
+ **Database Queries**:
353
+ - `SELECT * FROM conversation WHERE id = ? AND user_id = ?`
354
+ - `INSERT INTO conversation (user_id, created_at, updated_at)` (if new)
355
+ - `SELECT * FROM message WHERE conversation_id = ? ORDER BY created_at ASC`
356
+
357
+ ---
358
+
359
+ #### Step 3: Store User Message
360
+
361
+ **Service**: `ConversationService`
362
+
363
+ **Operation**:
364
+ ```python
365
+ await conversation_service.add_message(
366
+ conversation_id=conversation.id,
367
+ role="user",
368
+ content=request.message
369
+ )
370
+ ```
371
+
372
+ **Database Query**:
373
+ - `INSERT INTO message (conversation_id, role, content, created_at) VALUES (?, 'user', ?, ?)`
374
+
375
+ ---
376
+
377
+ #### Step 4: Execute Agent
378
+
379
+ **Service**: `AgentRunner`
380
+
381
+ **Sub-steps**:
382
+
383
+ **4a. Get Tool Definitions**:
384
+ ```python
385
+ tool_definitions = tool_registry.get_tool_definitions()
386
+ # Returns: [{"type": "function", "function": {...}}, ...]
387
+ ```
388
+
389
+ **4b. First LLM Call**:
390
+ ```python
391
+ response = await provider.generate_response_with_tools(
392
+ messages=message_history + [{"role": "user", "content": request.message}],
393
+ system_prompt=system_prompt,
394
+ tools=tool_definitions
395
+ )
396
+ # Returns: {"content": str, "tool_calls": [...]} or {"content": str, "tool_calls": None}
397
+ ```
398
+
399
+ **4c. Execute Tools** (if tool_calls present):
400
+ ```python
401
+ tool_results = []
402
+ for tool_call in response["tool_calls"]:
403
+ result = await tool_registry.execute_tool(
404
+ tool_name=tool_call["name"],
405
+ arguments=tool_call["arguments"],
406
+ user_id=user_id # SECURITY: Injected by backend
407
+ )
408
+ tool_results.append(result)
409
+ ```
410
+
411
+ **4d. Second LLM Call** (with tool results):
412
+ ```python
413
+ final_response = await provider.generate_response_with_tool_results(
414
+ messages=message_history,
415
+ tool_calls=response["tool_calls"],
416
+ tool_results=tool_results
417
+ )
418
+ # Returns: {"content": str, "tool_calls": [...], "tool_results": [...]}
419
+ ```
420
+
421
+ **4e. Return Final Response**:
422
+ ```python
423
+ return {
424
+ "content": final_response["content"],
425
+ "tool_calls": response["tool_calls"],
426
+ "tool_results": tool_results
427
+ }
428
+ ```
429
+
430
+ ---
431
+
432
+ #### Step 5: Persist Agent Response
433
+
434
+ **Service**: `ConversationService`
435
+
436
+ **Operation**:
437
+ ```python
438
+ await conversation_service.add_message(
439
+ conversation_id=conversation.id,
440
+ role="assistant",
441
+ content=agent_response["content"],
442
+ metadata={
443
+ "tool_calls": agent_response.get("tool_calls"),
444
+ "tool_results": agent_response.get("tool_results")
445
+ }
446
+ )
447
+ ```
448
+
449
+ **Database Query**:
450
+ - `INSERT INTO message (conversation_id, role, content, metadata, created_at) VALUES (?, 'assistant', ?, ?, ?)`
451
+
452
+ ---
453
+
454
+ #### Step 6: Return Response
455
+
456
+ **Output**: `ChatResponse`
457
+ ```python
458
+ class ChatResponse(BaseModel):
459
+ message: str
460
+ conversation_id: int
461
+ ```
462
+
463
+ **HTTP Response**: `200 OK` with JSON body
464
+
465
+ ---
466
+
467
+ ## MCP Tool Execution Flow
468
+
469
+ ### Tool Invocation Sequence
470
+
471
+ ```
472
+ Agent → MCPToolRegistry.execute_tool()
473
+
474
+ ├─ Validate tool exists
475
+ ├─ Inject user_id (SECURITY)
476
+ ├─ Call tool function
477
+ │ │
478
+ │ └─ Tool Implementation
479
+ │ ├─ Validate inputs
480
+ │ ├─ Query database (with user_id filter)
481
+ │ ├─ Perform operation
482
+ │ └─ Return structured result
483
+
484
+ └─ Return result to agent
485
+ ```
486
+
487
+ ### Tool Result Format (Standard)
488
+
489
+ All MCP tools MUST return results in this format:
490
+
491
+ ```python
492
+ {
493
+ "success": bool, # True if operation succeeded
494
+ "data": dict, # Tool-specific result data
495
+ "message": str, # User-friendly message
496
+ "error": Optional[str] # Error message if success=False
497
+ }
498
+ ```
499
+
500
+ **Success Example**:
501
+ ```python
502
+ {
503
+ "success": True,
504
+ "data": {
505
+ "id": 123,
506
+ "title": "Buy groceries",
507
+ "completed": False,
508
+ "created_at": "2026-01-14T12:00:00Z"
509
+ },
510
+ "message": "Task 'Buy groceries' created successfully"
511
+ }
512
+ ```
513
+
514
+ **Error Example**:
515
+ ```python
516
+ {
517
+ "success": False,
518
+ "data": {},
519
+ "message": "Task not found",
520
+ "error": "No task found with ID 999 for user 42"
521
+ }
522
+ ```
523
+
524
+ ---
525
+
526
+ ## Security Model
527
+
528
+ ### User Context Injection
529
+
530
+ **Critical Security Pattern**: User context (`user_id`) is ALWAYS injected by the backend, NEVER trusted from LLM output.
531
+
532
+ **Implementation**:
533
+
534
+ ```python
535
+ async def execute_tool(
536
+ self,
537
+ tool_name: str,
538
+ arguments: Dict[str, Any],
539
+ user_id: int # From JWT token, not LLM
540
+ ) -> Dict[str, Any]:
541
+ """Execute tool with user context injection."""
542
+
543
+ # SECURITY: Inject user_id, overwrite if present in arguments
544
+ arguments["user_id"] = user_id
545
+
546
+ # Execute tool
547
+ result = await self.tools[tool_name](**arguments)
548
+ return result
549
+ ```
550
+
551
+ **Why This Matters**:
552
+ - Prevents cross-user data access
553
+ - LLM cannot manipulate user_id
554
+ - All database queries filtered by authenticated user_id
555
+
556
+ ---
557
+
558
+ ## Performance Considerations
559
+
560
+ ### Conversation History Trimming
561
+
562
+ **Strategy**: Keep last 20 messages, max 8000 tokens
563
+
564
+ **Rationale**:
565
+ - Free-tier context window limits (Gemini: 1M tokens, but trimming for efficiency)
566
+ - Faster LLM responses with shorter context
567
+ - Reduced API costs
568
+
569
+ **Implementation**:
570
+ ```python
571
+ async def format_messages_for_agent(
572
+ self,
573
+ messages: List[Message],
574
+ max_messages: int = 20,
575
+ max_tokens: int = 8000
576
+ ) -> List[Dict[str, str]]:
577
+ """Format and trim messages for agent context."""
578
+
579
+ # Keep last N messages
580
+ recent_messages = messages[-max_messages:]
581
+
582
+ # Format for agent
583
+ formatted = [
584
+ {"role": msg.role, "content": msg.content}
585
+ for msg in recent_messages
586
+ ]
587
+
588
+ # Estimate tokens (rough: 1 token ≈ 4 characters)
589
+ total_tokens = sum(len(msg["content"]) // 4 for msg in formatted)
590
+
591
+ # Trim oldest messages if over limit
592
+ while total_tokens > max_tokens and len(formatted) > 1:
593
+ formatted.pop(0)
594
+ total_tokens = sum(len(msg["content"]) // 4 for msg in formatted)
595
+
596
+ return formatted
597
+ ```
598
+
599
+ ---
600
+
601
+ ## Error Handling
602
+
603
+ ### Tool Execution Errors
604
+
605
+ **Pattern**: Return structured errors, don't throw exceptions
606
+
607
+ **Example**:
608
+ ```python
609
+ try:
610
+ result = await tool_function(**arguments)
611
+ return result
612
+ except ValueError as e:
613
+ return {
614
+ "success": False,
615
+ "data": {},
616
+ "message": "Invalid input",
617
+ "error": str(e)
618
+ }
619
+ except Exception as e:
620
+ logger.error(f"Tool execution error: {tool_name}", exc_info=True)
621
+ return {
622
+ "success": False,
623
+ "data": {},
624
+ "message": "Tool execution failed",
625
+ "error": "An unexpected error occurred"
626
+ }
627
+ ```
628
+
629
+ ### Provider Errors
630
+
631
+ **Pattern**: Fallback to secondary provider or return user-friendly error
632
+
633
+ **Example**:
634
+ ```python
635
+ try:
636
+ response = await primary_provider.generate_response_with_tools(...)
637
+ except RateLimitError:
638
+ if fallback_provider:
639
+ response = await fallback_provider.generate_response_with_tools(...)
640
+ else:
641
+ raise HTTPException(
642
+ status_code=429,
643
+ detail="Rate limit exceeded. Please try again in a few minutes."
644
+ )
645
+ ```
646
+
647
+ ---
648
+
649
+ ## Summary
650
+
651
+ This data model defines:
652
+ - ✅ Runtime entities for agent configuration and execution
653
+ - ✅ Stateless request cycle flow with database persistence
654
+ - ✅ MCP tool execution flow with user context injection
655
+ - ✅ Security model preventing cross-user data access
656
+ - ✅ Performance optimizations for free-tier constraints
657
+ - ✅ Error handling patterns for reliability
658
+
659
+ **Key Principles**:
660
+ 1. **Stateless**: No in-memory state, all state in database
661
+ 2. **Secure**: User context injected by backend, not LLM
662
+ 3. **Restart-safe**: Server restarts don't affect conversations
663
+ 4. **Free-tier compatible**: Conversation history trimming
664
+ 5. **Structured**: All tools return consistent format
specs/001-openai-agent-mcp-tools/plan.md ADDED
@@ -0,0 +1,747 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Plan: OpenAI Agent MCP Tools
2
+
3
+ **Branch**: `001-openai-agent-mcp-tools` | **Date**: 2026-01-14 | **Spec**: [spec.md](./spec.md)
4
+ **Input**: Feature specification from `/specs/001-openai-agent-mcp-tools/spec.md`
5
+
6
+ ## Summary
7
+
8
+ This plan implements an AI-powered Todo agent using the OpenAI Agents SDK with external client configuration to support free-tier API providers (Gemini, OpenRouter, Cohere). The agent will execute natural language task management operations through stateless MCP tools that persist all state in the database. The implementation maintains a fully stateless backend architecture where every chat request loads conversation history from the database, executes the agent with MCP tools, persists results, and returns responses.
9
+
10
+ **Primary Requirement**: Enable users to manage tasks via natural language by implementing an OpenAI Agent that maps user intents to MCP tool invocations (add_task, list_tasks, complete_task, delete_task, update_task).
11
+
12
+ **Technical Approach**:
13
+ 1. Configure OpenAI Agents SDK with external client abstraction for free-tier providers
14
+ 2. Implement MCP server using Official MCP SDK with 5 stateless task tools
15
+ 3. Integrate agent execution into existing stateless chat endpoint
16
+ 4. Ensure all state persists in Neon PostgreSQL database
17
+
18
+ ## Technical Context
19
+
20
+ **Language/Version**: Python 3.11+
21
+ **Primary Dependencies**:
22
+ - OpenAI Agents SDK (agent reasoning and orchestration)
23
+ - Official MCP SDK (tool server implementation)
24
+ - FastAPI 0.104.1 (existing backend framework)
25
+ - SQLModel 0.0.14 (existing ORM)
26
+ - google-generativeai 0.3.2 (Gemini provider - already installed)
27
+ - Cohere SDK (to be added for Cohere provider support)
28
+
29
+ **Storage**: Neon Serverless PostgreSQL (existing: tasks, conversations, messages tables)
30
+ **Testing**: pytest 7.4.3 (existing)
31
+ **Target Platform**: Linux server (FastAPI backend)
32
+ **Project Type**: Web application (backend-only changes for this spec)
33
+ **Performance Goals**:
34
+ - Agent response within 5 seconds (excluding external API latency)
35
+ - MCP tool invocations <100ms (database operations)
36
+ - Support 50 concurrent users
37
+
38
+ **Constraints**:
39
+ - Free-tier API constraints (short context windows, rate limits, token caps)
40
+ - Stateless architecture (no in-memory state)
41
+ - No frontend changes permitted
42
+ - All backend code inside backend/ directory
43
+
44
+ **Scale/Scope**:
45
+ - 5 MCP tools (add_task, list_tasks, complete_task, delete_task, update_task)
46
+ - 3 external LLM providers (Gemini, OpenRouter, Cohere)
47
+ - Multi-user support with JWT-based user scoping
48
+
49
+ ## Constitution Check
50
+
51
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
52
+
53
+ ### Phase II Constitutional Compliance
54
+
55
+ ✅ **User-Centric Functionality**: Agent enables natural language task management, improving UX
56
+ ✅ **Spec-Driven Development**: All implementation follows approved spec in `/specs/001-openai-agent-mcp-tools/`
57
+ ✅ **Security & Data Privacy**: JWT authentication enforced; MCP tools validate user scoping
58
+ ✅ **Scalable Architecture**: Stateless design with database-backed persistence
59
+ ✅ **Maintainable & Consistent Code**: Follows existing FastAPI + SQLModel patterns
60
+
61
+ ### Phase III Constitutional Compliance
62
+
63
+ ✅ **Mandatory Development Framework**: Using Spec-Kit Plus workflow with Claude Code
64
+ ✅ **Stateless FastAPI Backend**: No in-memory state; all state persists in database
65
+ ✅ **MCP Server Implementation**: Using Official MCP SDK for all tool implementations
66
+ ✅ **OpenAI Agents SDK**: Required for agent reasoning and orchestration
67
+ ✅ **Database-Persisted State**: All conversations, messages, and tasks in Neon PostgreSQL
68
+
69
+ ### Agent & Skill Governance
70
+
71
+ ✅ **Conversational AI Architect Agent**: Required for agent design, reasoning workflows, intent detection
72
+ - **Mandatory Skill**: `agent-behavior-reasoning`
73
+ - **Domain**: AI agent design, tool selection logic, response quality optimization
74
+
75
+ ✅ **Backend Systems Agent**: Required for MCP tool design, API implementation, database operations
76
+ - **Mandatory Skill**: `backend-mcp-tools`
77
+ - **Domain**: Server-side architecture, MCP tool contracts, stateless backend logic
78
+
79
+ ### MCP Tool Constitutional Rules
80
+
81
+ ✅ **Tool Implementation Requirements**: All 5 required tools defined (add_task, list_tasks, complete_task, delete_task, update_task)
82
+ ✅ **Statelessness**: Tools operate statelessly with explicit inputs
83
+ ✅ **State Persistence**: All modifications persist to Neon PostgreSQL
84
+ ✅ **Agent Access Control**: AI agents ONLY modify tasks through MCP tools
85
+ ✅ **Tool Contracts**: Each tool defines clear contracts with structured responses
86
+
87
+ ### Chat & Conversation Rules
88
+
89
+ ✅ **Stateless Request Cycle**: Load history → Execute agent → Invoke tools → Store results → Return response
90
+ ✅ **Server Restart Resilience**: All state recoverable from database
91
+ ✅ **Conversation Continuity Mandate**: Conversation context maintained across turns
92
+
93
+ ### Error Handling & Confirmation Law
94
+
95
+ ✅ **User-Facing Confirmations**: Agent returns friendly confirmations for all actions
96
+ ✅ **Graceful Error Handling**: Task not found, invalid requests, system errors handled gracefully
97
+ ✅ **Silent Failure Prohibition**: All errors logged and communicated to users
98
+
99
+ **GATE STATUS**: ✅ PASSED - All constitutional requirements satisfied
100
+
101
+ ## Project Structure
102
+
103
+ ### Documentation (this feature)
104
+
105
+ ```text
106
+ specs/001-openai-agent-mcp-tools/
107
+ ├── plan.md # This file (/sp.plan command output)
108
+ ├── research.md # Phase 0 output (research findings)
109
+ ├── data-model.md # Phase 1 output (entity definitions)
110
+ ├── quickstart.md # Phase 1 output (setup instructions)
111
+ ├── contracts/ # Phase 1 output (MCP tool contracts)
112
+ │ ├── add_task.json
113
+ │ ├── list_tasks.json
114
+ │ ├── complete_task.json
115
+ │ ├── delete_task.json
116
+ │ └── update_task.json
117
+ └── tasks.md # Phase 2 output (/sp.tasks command - NOT created by /sp.plan)
118
+ ```
119
+
120
+ ### Source Code (repository root)
121
+
122
+ ```text
123
+ backend/
124
+ ├── src/
125
+ │ ├── agent/ # NEW: Agent configuration and execution
126
+ │ │ ├── __init__.py
127
+ │ │ ├── agent_config.py # Agent setup with external client
128
+ │ │ ├── agent_runner.py # Agent execution logic
129
+ │ │ └── providers/ # External LLM provider configurations
130
+ │ │ ├── __init__.py
131
+ │ │ ├── gemini.py # Gemini provider config
132
+ │ │ ├── openrouter.py # OpenRouter provider config
133
+ │ │ └── cohere.py # Cohere provider config
134
+ │ │
135
+ │ ├── mcp/ # NEW: MCP server and tools
136
+ │ │ ├── __init__.py
137
+ │ │ ├── server.py # MCP server setup
138
+ │ │ └── tools/ # MCP tool implementations
139
+ │ │ ├── __init__.py
140
+ │ │ ├── add_task.py # add_task tool
141
+ │ │ ├── list_tasks.py # list_tasks tool
142
+ │ │ ├── complete_task.py # complete_task tool
143
+ │ │ ├── delete_task.py # delete_task tool
144
+ │ │ └── update_task.py # update_task tool
145
+ │ │
146
+ │ ├── api/
147
+ │ │ └── routes/
148
+ │ │ └── chat.py # MODIFIED: Integrate agent execution
149
+ │ │
150
+ │ ├── services/
151
+ │ │ ├── llm_service.py # MODIFIED: Delegate to agent_runner
152
+ │ │ └── conversation_service.py # EXISTING: Conversation persistence
153
+ │ │
154
+ │ ├── models/ # EXISTING: No changes
155
+ │ │ ├── task.py
156
+ │ │ ├── conversation.py
157
+ │ │ └── message.py
158
+ │ │
159
+ │ ├── schemas/ # EXISTING: No changes
160
+ │ │ ├── chat_request.py
161
+ │ │ └── chat_response.py
162
+ │ │
163
+ │ └── core/ # EXISTING: No changes
164
+ │ ├── config.py
165
+ │ ├── database.py
166
+ │ └── security.py
167
+
168
+ └── requirements.txt # MODIFIED: Add OpenAI Agents SDK, MCP SDK, Cohere SDK
169
+ ```
170
+
171
+ **Structure Decision**: Web application structure (backend-only changes). All new code resides in `backend/src/agent/` and `backend/src/mcp/` directories. Existing chat endpoint (`backend/src/api/routes/chat.py`) is modified to integrate agent execution. No frontend changes per spec requirements.
172
+
173
+ ## Complexity Tracking
174
+
175
+ > **No constitutional violations requiring justification**
176
+
177
+ All complexity introduced is justified by constitutional requirements:
178
+ - OpenAI Agents SDK: Required by Phase III constitution for agent reasoning
179
+ - MCP Server: Required by Phase III constitution for tool implementation
180
+ - External client abstraction: Required by spec to support free-tier providers
181
+ - Stateless architecture: Required by Phase III constitution for scalability
182
+
183
+ ---
184
+
185
+ ## Phase 0: Research & Technology Validation
186
+
187
+ ### Research Objectives
188
+
189
+ The following unknowns must be resolved before design:
190
+
191
+ 1. **OpenAI Agents SDK External Client Configuration**
192
+ - How to configure OpenAI Agents SDK with non-OpenAI providers
193
+ - External client abstraction patterns
194
+ - Compatibility with Gemini, OpenRouter, Cohere APIs
195
+
196
+ 2. **Official MCP SDK Integration**
197
+ - MCP SDK installation and setup for Python
198
+ - Tool registration patterns
199
+ - Stateless tool implementation best practices
200
+
201
+ 3. **Free-Tier Provider Capabilities**
202
+ - Function calling support in Gemini free tier
203
+ - Function calling support in OpenRouter free tier
204
+ - Function calling support in Cohere free tier
205
+ - Context window limits and token caps
206
+
207
+ 4. **Agent-MCP Integration Pattern**
208
+ - How OpenAI Agents SDK invokes MCP tools
209
+ - Tool result handling and response formatting
210
+ - Error propagation from tools to agent
211
+
212
+ 5. **Stateless Request Cycle Implementation**
213
+ - Loading conversation history for agent context
214
+ - Persisting tool calls and results
215
+ - Maintaining conversation continuity
216
+
217
+ ### Research Tasks
218
+
219
+ **Agent**: Conversational AI Architect Agent
220
+ **Skill**: `agent-behavior-reasoning`
221
+
222
+ #### Task 1: Research OpenAI Agents SDK External Client Configuration
223
+
224
+ **Objective**: Determine how to configure OpenAI Agents SDK to use external LLM providers (Gemini, OpenRouter, Cohere) instead of OpenAI API.
225
+
226
+ **Research Questions**:
227
+ - Does OpenAI Agents SDK support external client configuration?
228
+ - What is the abstraction layer for provider switching?
229
+ - How to implement custom client adapters for non-OpenAI providers?
230
+ - Are there existing examples or libraries for this pattern?
231
+
232
+ **Deliverable**: Document external client configuration approach with code examples
233
+
234
+ ---
235
+
236
+ #### Task 2: Research Official MCP SDK for Python
237
+
238
+ **Objective**: Understand how to implement MCP server and tools using the Official MCP SDK in Python.
239
+
240
+ **Research Questions**:
241
+ - What is the Official MCP SDK package name and installation method?
242
+ - How to define MCP tools with input/output schemas?
243
+ - How to register tools with the MCP server?
244
+ - How to handle tool invocation and return structured responses?
245
+ - Best practices for stateless tool implementation?
246
+
247
+ **Deliverable**: Document MCP SDK setup, tool definition patterns, and server configuration
248
+
249
+ ---
250
+
251
+ #### Task 3: Research Free-Tier Provider Function Calling Support
252
+
253
+ **Objective**: Validate that Gemini, OpenRouter, and Cohere free tiers support function calling (required for MCP tool invocation).
254
+
255
+ **Research Questions**:
256
+ - Does Gemini free tier support function calling?
257
+ - Does OpenRouter free tier support function calling?
258
+ - Does Cohere free tier support function calling?
259
+ - What are the context window limits for each provider?
260
+ - What are the rate limits and token caps?
261
+ - How to handle rate limit errors gracefully?
262
+
263
+ **Deliverable**: Provider capability matrix with function calling support, limits, and constraints
264
+
265
+ ---
266
+
267
+ #### Task 4: Research Agent-MCP Integration Pattern
268
+
269
+ **Objective**: Understand how OpenAI Agents SDK integrates with MCP tools for function calling.
270
+
271
+ **Research Questions**:
272
+ - How does OpenAI Agents SDK invoke external tools?
273
+ - What is the tool invocation protocol?
274
+ - How to map MCP tool schemas to agent tool definitions?
275
+ - How to handle tool results and format responses?
276
+ - How to propagate errors from tools to agent?
277
+
278
+ **Deliverable**: Document agent-MCP integration pattern with code examples
279
+
280
+ ---
281
+
282
+ #### Task 5: Research Stateless Request Cycle Implementation
283
+
284
+ **Objective**: Design the stateless request cycle for loading conversation history, executing agent, and persisting results.
285
+
286
+ **Research Questions**:
287
+ - How to format conversation history for agent context?
288
+ - How to persist tool calls and results in the database?
289
+ - How to maintain conversation continuity across requests?
290
+ - How to handle concurrent requests from the same user?
291
+
292
+ **Deliverable**: Document stateless request cycle flow with database interaction patterns
293
+
294
+ ---
295
+
296
+ ### Research Output
297
+
298
+ **File**: `specs/001-openai-agent-mcp-tools/research.md`
299
+
300
+ **Format**:
301
+ ```markdown
302
+ # Research Findings: OpenAI Agent MCP Tools
303
+
304
+ ## 1. OpenAI Agents SDK External Client Configuration
305
+
306
+ **Decision**: [Chosen approach]
307
+ **Rationale**: [Why chosen]
308
+ **Alternatives Considered**: [Other options evaluated]
309
+ **Implementation Notes**: [Key details]
310
+
311
+ ## 2. Official MCP SDK Integration
312
+
313
+ **Decision**: [Chosen approach]
314
+ **Rationale**: [Why chosen]
315
+ **Alternatives Considered**: [Other options evaluated]
316
+ **Implementation Notes**: [Key details]
317
+
318
+ ## 3. Free-Tier Provider Capabilities
319
+
320
+ **Provider Capability Matrix**:
321
+
322
+ | Provider | Function Calling | Context Window | Rate Limits | Token Caps | Recommended Use |
323
+ |----------|------------------|----------------|-------------|------------|-----------------|
324
+ | Gemini | [Yes/No] | [Size] | [Limits] | [Caps] | [Primary/Fallback] |
325
+ | OpenRouter | [Yes/No] | [Size] | [Limits] | [Caps] | [Primary/Fallback] |
326
+ | Cohere | [Yes/No] | [Size] | [Limits] | [Caps] | [Primary/Fallback] |
327
+
328
+ **Decision**: [Primary provider choice]
329
+ **Rationale**: [Why chosen]
330
+
331
+ ## 4. Agent-MCP Integration Pattern
332
+
333
+ **Decision**: [Chosen integration approach]
334
+ **Rationale**: [Why chosen]
335
+ **Implementation Notes**: [Key details]
336
+
337
+ ## 5. Stateless Request Cycle Implementation
338
+
339
+ **Decision**: [Chosen request cycle design]
340
+ **Rationale**: [Why chosen]
341
+ **Implementation Notes**: [Key details]
342
+ ```
343
+
344
+ ---
345
+
346
+ ## Phase 1: Design & Contracts
347
+
348
+ **Prerequisites**: `research.md` complete with all decisions documented
349
+
350
+ ### Design Objectives
351
+
352
+ 1. Define data models for agent configuration and tool execution results
353
+ 2. Generate MCP tool contracts (input/output schemas)
354
+ 3. Design agent configuration and provider selection logic
355
+ 4. Design stateless request cycle flow
356
+ 5. Create quickstart guide for local development
357
+
358
+ ### Design Tasks
359
+
360
+ **Agent**: Backend Systems Agent
361
+ **Skill**: `backend-mcp-tools`
362
+
363
+ #### Task 1: Generate Data Model
364
+
365
+ **Objective**: Define entities for agent configuration, tool execution, and provider management.
366
+
367
+ **Entities to Define**:
368
+
369
+ 1. **AgentConfiguration** (runtime configuration, not persisted)
370
+ - provider_type: str (gemini, openrouter, cohere)
371
+ - model_name: str
372
+ - api_key: str (from environment)
373
+ - context_window_size: int
374
+ - max_tokens: int
375
+ - temperature: float
376
+
377
+ 2. **ToolExecutionResult** (runtime result, not persisted separately)
378
+ - tool_name: str
379
+ - success: bool
380
+ - data: dict (task object or list of tasks)
381
+ - error_message: Optional[str]
382
+ - execution_timestamp: datetime
383
+
384
+ 3. **AgentRequestContext** (runtime context, not persisted)
385
+ - user_id: int
386
+ - conversation_id: int
387
+ - message_history: List[dict]
388
+ - jwt_token: str
389
+
390
+ **Note**: These are runtime entities, not database tables. Existing database models (Task, Conversation, Message) remain unchanged.
391
+
392
+ **Deliverable**: `specs/001-openai-agent-mcp-tools/data-model.md`
393
+
394
+ ---
395
+
396
+ #### Task 2: Generate MCP Tool Contracts
397
+
398
+ **Objective**: Define input/output schemas for all 5 MCP tools.
399
+
400
+ **Tools to Define**:
401
+
402
+ 1. **add_task**
403
+ - Input: title (required), description (optional), due_date (optional), priority (optional), user_id (required)
404
+ - Output: success (bool), task (Task object), message (str)
405
+
406
+ 2. **list_tasks**
407
+ - Input: user_id (required), filter (optional: "all", "completed", "incomplete")
408
+ - Output: success (bool), tasks (List[Task]), count (int), message (str)
409
+
410
+ 3. **complete_task**
411
+ - Input: user_id (required), task_identifier (int or str - ID or title)
412
+ - Output: success (bool), task (Task object), message (str)
413
+
414
+ 4. **delete_task**
415
+ - Input: user_id (required), task_identifier (int or str - ID or title)
416
+ - Output: success (bool), message (str)
417
+
418
+ 5. **update_task**
419
+ - Input: user_id (required), task_identifier (int or str), updates (dict with title, description, due_date, priority, completed)
420
+ - Output: success (bool), task (Task object), message (str)
421
+
422
+ **Deliverable**: `specs/001-openai-agent-mcp-tools/contracts/` directory with 5 JSON schema files
423
+
424
+ ---
425
+
426
+ #### Task 3: Design Agent Configuration Logic
427
+
428
+ **Objective**: Design provider selection and agent initialization logic.
429
+
430
+ **Design Elements**:
431
+
432
+ 1. **Environment Variables**:
433
+ - `LLM_PROVIDER`: Primary provider (gemini, openrouter, cohere)
434
+ - `GEMINI_API_KEY`: Gemini API key
435
+ - `OPENROUTER_API_KEY`: OpenRouter API key
436
+ - `COHERE_API_KEY`: Cohere API key
437
+ - `FALLBACK_PROVIDER`: Fallback provider (optional)
438
+
439
+ 2. **Provider Configuration**:
440
+ - Each provider has a configuration class (GeminiProvider, OpenRouterProvider, CohereProvider)
441
+ - Configuration includes model name, context window, token limits
442
+ - Provider classes implement a common interface for agent initialization
443
+
444
+ 3. **Agent Initialization**:
445
+ - Load provider configuration from environment
446
+ - Initialize external client for selected provider
447
+ - Register MCP tools with agent
448
+ - Return configured agent instance
449
+
450
+ **Deliverable**: Design documented in `research.md` or `data-model.md`
451
+
452
+ ---
453
+
454
+ #### Task 4: Design Stateless Request Cycle Flow
455
+
456
+ **Objective**: Design the complete request cycle from chat endpoint to agent execution to database persistence.
457
+
458
+ **Flow Steps**:
459
+
460
+ 1. **Receive Chat Request** (chat.py endpoint)
461
+ - Validate JWT token
462
+ - Extract user_id and conversation_id
463
+ - Validate user authorization
464
+
465
+ 2. **Load Conversation History** (conversation_service.py)
466
+ - Query database for conversation and messages
467
+ - Format messages for agent context
468
+ - Return message history
469
+
470
+ 3. **Store User Message** (conversation_service.py)
471
+ - Create new Message record with role="user"
472
+ - Persist to database
473
+ - Return message ID
474
+
475
+ 4. **Execute Agent** (agent_runner.py)
476
+ - Initialize agent with provider configuration
477
+ - Load conversation history into agent context
478
+ - Execute agent reasoning with user message
479
+ - Agent selects and invokes MCP tools
480
+ - Collect tool results
481
+ - Generate final response
482
+
483
+ 5. **Persist Agent Response** (conversation_service.py)
484
+ - Create new Message record with role="assistant"
485
+ - Store tool calls and results in message metadata
486
+ - Persist to database
487
+ - Return message ID
488
+
489
+ 6. **Return Response** (chat.py endpoint)
490
+ - Format ChatResponse with agent message
491
+ - Return to client
492
+
493
+ **Deliverable**: Flow diagram and implementation notes in `data-model.md`
494
+
495
+ ---
496
+
497
+ #### Task 5: Create Quickstart Guide
498
+
499
+ **Objective**: Document local development setup for testing agent and MCP tools.
500
+
501
+ **Quickstart Sections**:
502
+
503
+ 1. **Prerequisites**:
504
+ - Python 3.11+
505
+ - Neon PostgreSQL database
506
+ - API keys for Gemini/OpenRouter/Cohere
507
+
508
+ 2. **Installation**:
509
+ - Install dependencies: `pip install -r backend/requirements.txt`
510
+ - Set environment variables in `.env`
511
+ - Run database migrations: `alembic upgrade head`
512
+
513
+ 3. **Configuration**:
514
+ - Configure LLM provider in `.env`
515
+ - Set API keys
516
+ - Configure database connection
517
+
518
+ 4. **Running the Server**:
519
+ - Start FastAPI server: `uvicorn src.main:app --reload`
520
+ - Test chat endpoint: `curl -X POST http://localhost:8000/api/{user_id}/chat`
521
+
522
+ 5. **Testing MCP Tools**:
523
+ - Test add_task tool
524
+ - Test list_tasks tool
525
+ - Test complete_task tool
526
+ - Test delete_task tool
527
+ - Test update_task tool
528
+
529
+ **Deliverable**: `specs/001-openai-agent-mcp-tools/quickstart.md`
530
+
531
+ ---
532
+
533
+ #### Task 6: Update Agent Context
534
+
535
+ **Objective**: Update Claude Code agent context with new technologies from this plan.
536
+
537
+ **Command**: Run `.specify/scripts/powershell/update-agent-context.ps1 -AgentType claude`
538
+
539
+ **Technologies to Add**:
540
+ - OpenAI Agents SDK
541
+ - Official MCP SDK
542
+ - Cohere SDK
543
+ - External client configuration patterns
544
+ - MCP tool implementation patterns
545
+
546
+ **Deliverable**: Updated agent context file
547
+
548
+ ---
549
+
550
+ ### Phase 1 Outputs
551
+
552
+ **Files Created**:
553
+ 1. `specs/001-openai-agent-mcp-tools/research.md` - Research findings and decisions
554
+ 2. `specs/001-openai-agent-mcp-tools/data-model.md` - Entity definitions and flow diagrams
555
+ 3. `specs/001-openai-agent-mcp-tools/contracts/` - MCP tool JSON schemas (5 files)
556
+ 4. `specs/001-openai-agent-mcp-tools/quickstart.md` - Local development guide
557
+ 5. Updated agent context file
558
+
559
+ ---
560
+
561
+ ## Phase 2: Implementation Planning (Not Executed by /sp.plan)
562
+
563
+ **Note**: Phase 2 (task generation) is executed by the `/sp.tasks` command, NOT by `/sp.plan`. This section provides guidance for task generation.
564
+
565
+ ### Implementation Phases
566
+
567
+ #### Phase 2.1: MCP Server & Tools Implementation
568
+
569
+ **Agent**: Backend Systems Agent
570
+ **Skill**: `backend-mcp-tools`
571
+
572
+ **Tasks**:
573
+ 1. Install Official MCP SDK and Cohere SDK
574
+ 2. Implement MCP server setup (`backend/src/mcp/server.py`)
575
+ 3. Implement add_task tool (`backend/src/mcp/tools/add_task.py`)
576
+ 4. Implement list_tasks tool (`backend/src/mcp/tools/list_tasks.py`)
577
+ 5. Implement complete_task tool (`backend/src/mcp/tools/complete_task.py`)
578
+ 6. Implement delete_task tool (`backend/src/mcp/tools/delete_task.py`)
579
+ 7. Implement update_task tool (`backend/src/mcp/tools/update_task.py`)
580
+ 8. Test MCP tools in isolation
581
+
582
+ #### Phase 2.2: Agent Configuration & Provider Setup
583
+
584
+ **Agent**: Conversational AI Architect Agent
585
+ **Skill**: `agent-behavior-reasoning`
586
+
587
+ **Tasks**:
588
+ 1. Install OpenAI Agents SDK
589
+ 2. Implement provider configuration classes (`backend/src/agent/providers/`)
590
+ 3. Implement agent configuration logic (`backend/src/agent/agent_config.py`)
591
+ 4. Implement agent runner (`backend/src/agent/agent_runner.py`)
592
+ 5. Test agent initialization with each provider
593
+
594
+ #### Phase 2.3: Agent-MCP Integration
595
+
596
+ **Agent**: Backend Systems Agent
597
+ **Skill**: `backend-mcp-tools`
598
+
599
+ **Tasks**:
600
+ 1. Register MCP tools with agent
601
+ 2. Implement tool invocation handling
602
+ 3. Implement tool result processing
603
+ 4. Test agent-MCP integration
604
+
605
+ #### Phase 2.4: Chat Endpoint Integration
606
+
607
+ **Agent**: Backend Systems Agent
608
+ **Skill**: `backend-mcp-tools`
609
+
610
+ **Tasks**:
611
+ 1. Modify chat endpoint to use agent_runner
612
+ 2. Implement stateless request cycle
613
+ 3. Persist tool calls and results
614
+ 4. Test end-to-end chat flow
615
+
616
+ #### Phase 2.5: Error Handling & Edge Cases
617
+
618
+ **Agent**: Backend Systems Agent
619
+ **Skill**: `backend-mcp-tools`
620
+
621
+ **Tasks**:
622
+ 1. Implement provider error handling
623
+ 2. Implement rate limit handling
624
+ 3. Implement tool error handling
625
+ 4. Test edge cases (task not found, invalid input, concurrent requests)
626
+
627
+ #### Phase 2.6: Testing & Validation
628
+
629
+ **Agent**: Backend Systems Agent
630
+ **Skill**: `backend-mcp-tools`
631
+
632
+ **Tasks**:
633
+ 1. Write unit tests for MCP tools
634
+ 2. Write integration tests for agent execution
635
+ 3. Write end-to-end tests for chat flow
636
+ 4. Validate all acceptance criteria from spec
637
+
638
+ ---
639
+
640
+ ## Acceptance Criteria
641
+
642
+ ### Phase 0 Acceptance
643
+
644
+ - [ ] All research questions answered
645
+ - [ ] Provider capability matrix complete
646
+ - [ ] External client configuration approach documented
647
+ - [ ] MCP SDK integration approach documented
648
+ - [ ] Stateless request cycle design documented
649
+
650
+ ### Phase 1 Acceptance
651
+
652
+ - [ ] Data model entities defined
653
+ - [ ] All 5 MCP tool contracts defined with JSON schemas
654
+ - [ ] Agent configuration logic designed
655
+ - [ ] Stateless request cycle flow documented
656
+ - [ ] Quickstart guide created
657
+ - [ ] Agent context updated
658
+
659
+ ### Phase 2 Acceptance (Guidance for /sp.tasks)
660
+
661
+ - [ ] MCP server implemented and running
662
+ - [ ] All 5 MCP tools implemented and tested
663
+ - [ ] Agent configured with external client
664
+ - [ ] Agent-MCP integration working
665
+ - [ ] Chat endpoint integrated with agent
666
+ - [ ] Stateless request cycle functional
667
+ - [ ] All error handling implemented
668
+ - [ ] All tests passing
669
+ - [ ] All spec acceptance criteria met
670
+
671
+ ---
672
+
673
+ ## Risk Analysis
674
+
675
+ ### Technical Risks
676
+
677
+ 1. **OpenAI Agents SDK External Client Compatibility**
678
+ - **Risk**: OpenAI Agents SDK may not support external clients
679
+ - **Mitigation**: Research alternative agent frameworks if needed
680
+ - **Fallback**: Implement custom agent logic without SDK
681
+
682
+ 2. **Free-Tier Function Calling Support**
683
+ - **Risk**: Free-tier providers may not support function calling
684
+ - **Mitigation**: Validate provider capabilities in Phase 0
685
+ - **Fallback**: Use prompt-based tool selection if function calling unavailable
686
+
687
+ 3. **MCP SDK Python Availability**
688
+ - **Risk**: Official MCP SDK may not have Python implementation
689
+ - **Mitigation**: Research MCP SDK availability in Phase 0
690
+ - **Fallback**: Implement custom MCP server if SDK unavailable
691
+
692
+ 4. **Rate Limit Handling**
693
+ - **Risk**: Free-tier rate limits may impact user experience
694
+ - **Mitigation**: Implement graceful degradation and retry logic
695
+ - **Fallback**: Queue requests or display rate limit messages
696
+
697
+ ### Architectural Risks
698
+
699
+ 1. **Stateless Architecture Complexity**
700
+ - **Risk**: Loading conversation history on every request may impact performance
701
+ - **Mitigation**: Optimize database queries with proper indexing
702
+ - **Fallback**: Implement conversation history pagination if needed
703
+
704
+ 2. **Concurrent Request Handling**
705
+ - **Risk**: Concurrent requests from same user may cause race conditions
706
+ - **Mitigation**: Use database transactions and optimistic locking
707
+ - **Fallback**: Implement request queuing per user
708
+
709
+ ---
710
+
711
+ ## Dependencies
712
+
713
+ ### External Dependencies
714
+
715
+ 1. **OpenAI Agents SDK**: Required for agent reasoning and orchestration
716
+ 2. **Official MCP SDK**: Required for MCP server and tool implementation
717
+ 3. **Cohere SDK**: Required for Cohere provider support
718
+ 4. **External API Accounts**: Gemini, OpenRouter, Cohere accounts with API keys
719
+
720
+ ### Internal Dependencies
721
+
722
+ 1. **Spec-1 Completion**: Chat UI and basic chat endpoint must be functional
723
+ 2. **Database Schema**: Conversations and messages tables must exist
724
+ 3. **Better Auth**: JWT authentication must be functional
725
+ 4. **Existing Models**: Task, Conversation, Message models must be available
726
+
727
+ ---
728
+
729
+ ## Next Steps
730
+
731
+ 1. **Execute Phase 0**: Run research tasks to resolve all unknowns
732
+ 2. **Execute Phase 1**: Generate design artifacts (data-model.md, contracts/, quickstart.md)
733
+ 3. **Re-evaluate Constitution Check**: Verify all constitutional requirements still satisfied
734
+ 4. **Execute /sp.tasks**: Generate implementation tasks based on this plan
735
+ 5. **Execute /sp.implement**: Implement tasks in dependency order
736
+
737
+ ---
738
+
739
+ ## Notes
740
+
741
+ - This plan focuses exclusively on backend implementation; no frontend changes
742
+ - All code must reside in `backend/` directory per constitutional requirements
743
+ - Agent behavior must follow Agent Behavior Specification (to be referenced in tasks)
744
+ - MCP tools must be stateless and database-backed per constitutional requirements
745
+ - Error handling must prioritize user experience with friendly messages
746
+ - Provider selection must be configurable via environment variables
747
+ - Fallback provider support is optional but recommended for reliability
specs/001-openai-agent-mcp-tools/quickstart.md ADDED
@@ -0,0 +1,521 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quickstart Guide: OpenAI Agent MCP Tools
2
+
3
+ **Feature**: 001-openai-agent-mcp-tools
4
+ **Date**: 2026-01-14
5
+ **Purpose**: Local development setup for testing AI agent with MCP tools
6
+
7
+ ---
8
+
9
+ ## Prerequisites
10
+
11
+ Before starting, ensure you have:
12
+
13
+ - **Python 3.11+** installed
14
+ - **Neon PostgreSQL database** accessible (connection string ready)
15
+ - **API keys** for at least one LLM provider:
16
+ - Google Gemini API key (recommended, free tier)
17
+ - OpenRouter API key (optional, fallback)
18
+ - Cohere API key (optional, not recommended)
19
+ - **Git** installed
20
+ - **Node.js 18+** (for frontend, if testing end-to-end)
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ### 1. Clone Repository (if not already done)
27
+
28
+ ```bash
29
+ git clone <repository-url>
30
+ cd evolution-of-todo/phase-2-full-stack-web-app
31
+ ```
32
+
33
+ ### 2. Checkout Feature Branch
34
+
35
+ ```bash
36
+ git checkout 001-openai-agent-mcp-tools
37
+ ```
38
+
39
+ ### 3. Install Backend Dependencies
40
+
41
+ ```bash
42
+ cd backend
43
+ pip install -r requirements.txt
44
+ ```
45
+
46
+ **Expected new dependencies** (added by this feature):
47
+ - `mcp` - Official MCP SDK
48
+ - `cohere` - Cohere SDK (if using Cohere provider)
49
+ - `openai` - OpenAI SDK (for agent compatibility, even if not using OpenAI)
50
+
51
+ ### 4. Set Up Environment Variables
52
+
53
+ Create a `.env` file in the `backend/` directory:
54
+
55
+ ```bash
56
+ cd backend
57
+ touch .env
58
+ ```
59
+
60
+ Add the following configuration to `.env`:
61
+
62
+ ```env
63
+ # Database Configuration
64
+ DATABASE_URL=postgresql://user:password@host:5432/database
65
+
66
+ # Authentication
67
+ BETTER_AUTH_SECRET=your-secret-key-here
68
+
69
+ # LLM Provider Configuration
70
+ LLM_PROVIDER=gemini # Options: gemini, openrouter, cohere
71
+ FALLBACK_PROVIDER=openrouter # Optional fallback provider
72
+
73
+ # API Keys (provide at least one)
74
+ GEMINI_API_KEY=your-gemini-api-key-here
75
+ OPENROUTER_API_KEY=your-openrouter-key-here # Optional
76
+ COHERE_API_KEY=your-cohere-key-here # Optional
77
+
78
+ # Agent Configuration (optional, defaults provided)
79
+ AGENT_TEMPERATURE=0.7
80
+ AGENT_MAX_TOKENS=8192
81
+ CONVERSATION_MAX_MESSAGES=20
82
+ CONVERSATION_MAX_TOKENS=8000
83
+ ```
84
+
85
+ **How to get API keys**:
86
+
87
+ - **Gemini**: Visit [Google AI Studio](https://makersuite.google.com/app/apikey) (free, no credit card required)
88
+ - **OpenRouter**: Visit [OpenRouter](https://openrouter.ai/) (free models available)
89
+ - **Cohere**: Visit [Cohere](https://cohere.com/) (trial only, not recommended)
90
+
91
+ ### 5. Run Database Migrations
92
+
93
+ ```bash
94
+ cd backend
95
+ alembic upgrade head
96
+ ```
97
+
98
+ **Expected output**:
99
+ ```
100
+ INFO [alembic.runtime.migration] Running upgrade -> 20260114_1044, add conversation and message tables
101
+ INFO [alembic.runtime.migration] Running upgrade 20260114_1044 -> 20260114_1115, add metadata to message
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Running the Server
107
+
108
+ ### Start Backend Server
109
+
110
+ ```bash
111
+ cd backend
112
+ uvicorn src.main:app --reload --host 0.0.0.0 --port 8000
113
+ ```
114
+
115
+ **Expected output**:
116
+ ```
117
+ INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
118
+ INFO: Started reloader process [12345] using StatReload
119
+ INFO: Started server process [12346]
120
+ INFO: Waiting for application startup.
121
+ INFO: Application startup complete.
122
+ ```
123
+
124
+ **Verify server is running**:
125
+ ```bash
126
+ curl http://localhost:8000/health
127
+ ```
128
+
129
+ Expected response: `{"status": "healthy"}`
130
+
131
+ ---
132
+
133
+ ## Testing the Agent
134
+
135
+ ### 1. Create a Test User
136
+
137
+ First, create a test user via the auth endpoint:
138
+
139
+ ```bash
140
+ curl -X POST http://localhost:8000/api/auth/signup \
141
+ -H "Content-Type: application/json" \
142
+ -d '{
143
+ "email": "test@example.com",
144
+ "password": "testpassword123"
145
+ }'
146
+ ```
147
+
148
+ **Expected response**:
149
+ ```json
150
+ {
151
+ "user": {
152
+ "id": 1,
153
+ "email": "test@example.com"
154
+ },
155
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
156
+ }
157
+ ```
158
+
159
+ **Save the token** - you'll need it for authenticated requests.
160
+
161
+ ### 2. Test Chat Endpoint (Without Agent)
162
+
163
+ Test basic chat functionality:
164
+
165
+ ```bash
166
+ curl -X POST http://localhost:8000/api/1/chat \
167
+ -H "Content-Type: application/json" \
168
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
169
+ -d '{
170
+ "message": "Hello, can you help me manage my tasks?"
171
+ }'
172
+ ```
173
+
174
+ **Expected response**:
175
+ ```json
176
+ {
177
+ "message": "Hello! I'm your AI task assistant. I can help you create, view, complete, and manage your tasks. What would you like to do?",
178
+ "conversation_id": 1
179
+ }
180
+ ```
181
+
182
+ ### 3. Test Task Creation via Natural Language
183
+
184
+ ```bash
185
+ curl -X POST http://localhost:8000/api/1/chat \
186
+ -H "Content-Type: application/json" \
187
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
188
+ -d '{
189
+ "message": "Add a task to buy groceries",
190
+ "conversation_id": 1
191
+ }'
192
+ ```
193
+
194
+ **Expected response**:
195
+ ```json
196
+ {
197
+ "message": "I've created a new task: 'Buy groceries'. Your task has been added to your list!",
198
+ "conversation_id": 1
199
+ }
200
+ ```
201
+
202
+ ### 4. Test Task Listing
203
+
204
+ ```bash
205
+ curl -X POST http://localhost:8000/api/1/chat \
206
+ -H "Content-Type: application/json" \
207
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
208
+ -d '{
209
+ "message": "Show me my tasks",
210
+ "conversation_id": 1
211
+ }'
212
+ ```
213
+
214
+ **Expected response**:
215
+ ```json
216
+ {
217
+ "message": "You have 1 task:\n\n1. Buy groceries (incomplete)\n\nWould you like to complete any of these tasks?",
218
+ "conversation_id": 1
219
+ }
220
+ ```
221
+
222
+ ### 5. Test Task Completion
223
+
224
+ ```bash
225
+ curl -X POST http://localhost:8000/api/1/chat \
226
+ -H "Content-Type: application/json" \
227
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
228
+ -d '{
229
+ "message": "Mark the groceries task as complete",
230
+ "conversation_id": 1
231
+ }'
232
+ ```
233
+
234
+ **Expected response**:
235
+ ```json
236
+ {
237
+ "message": "Great! I've marked 'Buy groceries' as completed. Well done!",
238
+ "conversation_id": 1
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Testing MCP Tools Directly
245
+
246
+ ### Test add_task Tool
247
+
248
+ ```bash
249
+ # This requires accessing the MCP server directly (advanced)
250
+ # For now, test via the agent as shown above
251
+ ```
252
+
253
+ ### Test list_tasks Tool
254
+
255
+ ```bash
256
+ # Access via agent chat interface
257
+ curl -X POST http://localhost:8000/api/1/chat \
258
+ -H "Content-Type: application/json" \
259
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
260
+ -d '{
261
+ "message": "List all my incomplete tasks"
262
+ }'
263
+ ```
264
+
265
+ ### Test complete_task Tool
266
+
267
+ ```bash
268
+ # Access via agent chat interface
269
+ curl -X POST http://localhost:8000/api/1/chat \
270
+ -H "Content-Type: application/json" \
271
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
272
+ -d '{
273
+ "message": "Complete task 1"
274
+ }'
275
+ ```
276
+
277
+ ### Test delete_task Tool
278
+
279
+ ```bash
280
+ # Access via agent chat interface
281
+ curl -X POST http://localhost:8000/api/1/chat \
282
+ -H "Content-Type: application/json" \
283
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
284
+ -d '{
285
+ "message": "Delete the groceries task"
286
+ }'
287
+ ```
288
+
289
+ ### Test update_task Tool
290
+
291
+ ```bash
292
+ # Access via agent chat interface
293
+ curl -X POST http://localhost:8000/api/1/chat \
294
+ -H "Content-Type: application/json" \
295
+ -H "Authorization: Bearer YOUR_TOKEN_HERE" \
296
+ -d '{
297
+ "message": "Change the groceries task to buy groceries and milk"
298
+ }'
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Troubleshooting
304
+
305
+ ### Issue: "Rate limit exceeded"
306
+
307
+ **Cause**: Gemini free tier has 15 requests/minute limit
308
+
309
+ **Solution**:
310
+ 1. Wait 1 minute before retrying
311
+ 2. Configure fallback provider in `.env`:
312
+ ```env
313
+ FALLBACK_PROVIDER=openrouter
314
+ OPENROUTER_API_KEY=your-key-here
315
+ ```
316
+
317
+ ### Issue: "Tool not found"
318
+
319
+ **Cause**: MCP tools not registered properly
320
+
321
+ **Solution**:
322
+ 1. Check MCP server logs for errors
323
+ 2. Verify tool registration in `backend/src/mcp/server.py`
324
+ 3. Restart server: `uvicorn src.main:app --reload`
325
+
326
+ ### Issue: "Unauthorized" (401 error)
327
+
328
+ **Cause**: Invalid or expired JWT token
329
+
330
+ **Solution**:
331
+ 1. Get a new token via `/api/auth/signin`
332
+ 2. Ensure token is included in `Authorization: Bearer <token>` header
333
+ 3. Check `BETTER_AUTH_SECRET` matches between frontend and backend
334
+
335
+ ### Issue: "Task not found"
336
+
337
+ **Cause**: Task doesn't exist or belongs to different user
338
+
339
+ **Solution**:
340
+ 1. List tasks first: "Show me my tasks"
341
+ 2. Use exact task ID or title
342
+ 3. Verify user_id in request matches authenticated user
343
+
344
+ ### Issue: "Database connection failed"
345
+
346
+ **Cause**: Invalid `DATABASE_URL` or database not accessible
347
+
348
+ **Solution**:
349
+ 1. Verify `DATABASE_URL` in `.env`
350
+ 2. Test connection: `psql $DATABASE_URL`
351
+ 3. Check Neon dashboard for database status
352
+ 4. Ensure IP is whitelisted in Neon settings
353
+
354
+ ### Issue: "Agent returns generic response, doesn't use tools"
355
+
356
+ **Cause**: LLM provider doesn't support function calling or tools not registered
357
+
358
+ **Solution**:
359
+ 1. Verify provider supports function calling (Gemini does)
360
+ 2. Check tool definitions in agent logs
361
+ 3. Test with explicit tool request: "Use the add_task tool to create a task"
362
+
363
+ ---
364
+
365
+ ## Viewing Logs
366
+
367
+ ### Backend Logs
368
+
369
+ ```bash
370
+ # View real-time logs
371
+ tail -f backend/logs/app.log
372
+
373
+ # View last 100 lines
374
+ tail -n 100 backend/logs/app.log
375
+
376
+ # Search for errors
377
+ grep ERROR backend/logs/app.log
378
+ ```
379
+
380
+ ### Database Queries
381
+
382
+ ```bash
383
+ # Connect to database
384
+ psql $DATABASE_URL
385
+
386
+ # View conversations
387
+ SELECT * FROM conversation WHERE user_id = 1;
388
+
389
+ # View messages
390
+ SELECT * FROM message WHERE conversation_id = 1 ORDER BY created_at;
391
+
392
+ # View tasks
393
+ SELECT * FROM tasks WHERE user_id = 1;
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Testing with Frontend (Optional)
399
+
400
+ If you want to test the full stack with the frontend UI:
401
+
402
+ ### 1. Start Frontend
403
+
404
+ ```bash
405
+ cd frontend
406
+ npm install
407
+ npm run dev
408
+ ```
409
+
410
+ ### 2. Access UI
411
+
412
+ Open browser to `http://localhost:3000`
413
+
414
+ ### 3. Sign In
415
+
416
+ Use the test user credentials:
417
+ - Email: `test@example.com`
418
+ - Password: `testpassword123`
419
+
420
+ ### 4. Navigate to Chat
421
+
422
+ Click "Chat" in the navigation menu
423
+
424
+ ### 5. Test Natural Language Commands
425
+
426
+ Try these commands:
427
+ - "Add a task to buy groceries"
428
+ - "Show me my tasks"
429
+ - "Mark task 1 as complete"
430
+ - "Delete the groceries task"
431
+
432
+ ---
433
+
434
+ ## Next Steps
435
+
436
+ After verifying the agent works locally:
437
+
438
+ 1. **Run Tests**: `pytest backend/tests/`
439
+ 2. **Check Coverage**: `pytest --cov=src backend/tests/`
440
+ 3. **Review Logs**: Check for any errors or warnings
441
+ 4. **Test Edge Cases**: Try ambiguous requests, invalid inputs
442
+ 5. **Performance Testing**: Test with multiple concurrent requests
443
+
444
+ ---
445
+
446
+ ## Development Workflow
447
+
448
+ ### Making Changes
449
+
450
+ 1. **Modify Code**: Edit files in `backend/src/`
451
+ 2. **Server Auto-Reloads**: Uvicorn detects changes and reloads
452
+ 3. **Test Changes**: Use curl or frontend to test
453
+ 4. **Check Logs**: Monitor logs for errors
454
+ 5. **Commit Changes**: `git add . && git commit -m "description"`
455
+
456
+ ### Adding New MCP Tools
457
+
458
+ 1. Create tool file: `backend/src/mcp/tools/new_tool.py`
459
+ 2. Define tool function with decorator: `@mcp_server.tool()`
460
+ 3. Register tool in `backend/src/mcp/tool_registry.py`
461
+ 4. Test tool via agent chat interface
462
+ 5. Add tests: `backend/tests/mcp/test_new_tool.py`
463
+
464
+ ### Debugging Agent Behavior
465
+
466
+ 1. **Enable Debug Logging**: Set `LOG_LEVEL=DEBUG` in `.env`
467
+ 2. **View Tool Calls**: Check message metadata in database
468
+ 3. **Test Tool Directly**: Call tool function in Python shell
469
+ 4. **Check Provider Logs**: Review Gemini API logs
470
+ 5. **Validate Tool Schemas**: Ensure JSON schemas are correct
471
+
472
+ ---
473
+
474
+ ## Useful Commands
475
+
476
+ ```bash
477
+ # Start backend with debug logging
478
+ LOG_LEVEL=DEBUG uvicorn src.main:app --reload
479
+
480
+ # Run specific test
481
+ pytest backend/tests/mcp/test_add_task.py -v
482
+
483
+ # Check database schema
484
+ psql $DATABASE_URL -c "\d tasks"
485
+
486
+ # View recent messages
487
+ psql $DATABASE_URL -c "SELECT role, content FROM message ORDER BY created_at DESC LIMIT 10;"
488
+
489
+ # Clear conversation history (for testing)
490
+ psql $DATABASE_URL -c "DELETE FROM message WHERE conversation_id = 1;"
491
+
492
+ # Reset database (CAUTION: deletes all data)
493
+ alembic downgrade base
494
+ alembic upgrade head
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Support
500
+
501
+ If you encounter issues not covered in this guide:
502
+
503
+ 1. Check the [research.md](./research.md) for implementation details
504
+ 2. Review the [data-model.md](./data-model.md) for architecture
505
+ 3. Inspect the [plan.md](./plan.md) for design decisions
506
+ 4. Check backend logs for error messages
507
+ 5. Verify environment variables are set correctly
508
+
509
+ ---
510
+
511
+ ## Summary
512
+
513
+ You should now have:
514
+ - ✅ Backend server running on `http://localhost:8000`
515
+ - ✅ Database migrations applied
516
+ - ✅ Test user created with JWT token
517
+ - ✅ Agent responding to natural language commands
518
+ - ✅ MCP tools executing task operations
519
+ - ✅ Conversation history persisting in database
520
+
521
+ **Ready for implementation!** Proceed to `/sp.tasks` to generate implementation tasks.
specs/001-openai-agent-mcp-tools/research.md ADDED
@@ -0,0 +1,758 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research Findings: OpenAI Agent MCP Tools
2
+
3
+ **Date**: 2026-01-14
4
+ **Feature**: 001-openai-agent-mcp-tools
5
+ **Research Phase**: Phase 0 - Technology Validation
6
+
7
+ ## Executive Summary
8
+
9
+ This research validates the technical approach for implementing an AI-powered Todo agent with MCP tools using free-tier API providers. Key findings:
10
+
11
+ 1. **OpenAI Agents SDK is NOT suitable** - Has compatibility issues and doesn't support external providers
12
+ 2. **Custom agent implementation is RECOMMENDED** - Provides full control and works with any provider
13
+ 3. **Google Gemini is the PRIMARY provider** - Best free-tier offering with full function calling support
14
+ 4. **MCP SDK (FastMCP) is production-ready** - Already installed, provides clean decorator-based API
15
+ 5. **Stateless architecture is feasible** - Conversation history trimming handles free-tier constraints
16
+
17
+ ---
18
+
19
+ ## 1. OpenAI Agents SDK External Client Configuration
20
+
21
+ ### Decision: Use Custom Agent Implementation (NOT OpenAI Agents SDK)
22
+
23
+ **Rationale**:
24
+ - OpenAI Agents SDK (v0.4.2) has compatibility issues with current OpenAI SDK
25
+ - SDK is NOT designed for external providers (Gemini, OpenRouter, Cohere)
26
+ - Custom implementation provides full control over agent logic
27
+ - Simpler debugging and maintenance
28
+ - Works with any provider supporting function calling
29
+
30
+ **Alternatives Considered**:
31
+ 1. **OpenAI Agents SDK with external client** - REJECTED: Not supported by SDK design
32
+ 2. **LangChain Agents** - REJECTED: Too heavy, unnecessary complexity for our use case
33
+ 3. **Custom agent orchestration** - SELECTED: Best fit for requirements
34
+
35
+ **Implementation Approach**:
36
+
37
+ ```python
38
+ class AgentRunner:
39
+ """Custom agent orchestration without OpenAI Agents SDK dependency."""
40
+
41
+ def __init__(self, provider: LLMProvider, tools: MCPToolRegistry):
42
+ self.provider = provider
43
+ self.tools = tools
44
+
45
+ async def execute(self, messages: List[Dict], system_prompt: str, user_id: int) -> Dict:
46
+ """Execute agent reasoning with tool invocation."""
47
+
48
+ # 1. Get tool definitions for LLM
49
+ tool_definitions = self.tools.get_tool_definitions()
50
+
51
+ # 2. Call LLM with tools
52
+ response = await self.provider.generate_response_with_tools(
53
+ messages=messages,
54
+ system_prompt=system_prompt,
55
+ tools=tool_definitions
56
+ )
57
+
58
+ # 3. Execute tool calls if present
59
+ if response.get("tool_calls"):
60
+ tool_results = []
61
+ for tool_call in response["tool_calls"]:
62
+ result = await self.tools.execute_tool(
63
+ tool_name=tool_call["name"],
64
+ arguments=tool_call["arguments"],
65
+ user_id=user_id # Inject user context for security
66
+ )
67
+ tool_results.append(result)
68
+
69
+ # 4. Send results back to LLM for final response
70
+ final_response = await self.provider.generate_response_with_tool_results(
71
+ messages=messages,
72
+ tool_calls=response["tool_calls"],
73
+ tool_results=tool_results
74
+ )
75
+ return final_response
76
+
77
+ return response
78
+ ```
79
+
80
+ **Key Benefits**:
81
+ - No dependency on broken SDK
82
+ - Full control over agent logic
83
+ - Works with any provider supporting function calling
84
+ - Simpler debugging and maintenance
85
+ - Follows existing codebase patterns (FastAPI, async/await)
86
+
87
+ ---
88
+
89
+ ## 2. Official MCP SDK Integration
90
+
91
+ ### Decision: Use MCP SDK with FastMCP Server
92
+
93
+ **Package**: `mcp` version 1.20.0 (already installed in environment)
94
+
95
+ **Installation**: `pip install mcp`
96
+
97
+ **Rationale**:
98
+ - Official MCP SDK provides production-ready server implementation
99
+ - FastMCP offers clean decorator-based API (similar to FastAPI)
100
+ - Already installed in the environment
101
+ - Well-documented with examples
102
+ - Supports stateless tool implementation
103
+
104
+ **Alternatives Considered**:
105
+ 1. **Custom MCP server implementation** - REJECTED: Unnecessary complexity, SDK is production-ready
106
+ 2. **Low-level MCP Server class** - REJECTED: FastMCP provides better developer experience
107
+ 3. **FastMCP (high-level)** - SELECTED: Best fit for requirements
108
+
109
+ **Tool Definition Pattern**:
110
+
111
+ ```python
112
+ from mcp.server import FastMCP
113
+ from typing import Optional
114
+
115
+ mcp_server = FastMCP("todo-mcp-server")
116
+
117
+ @mcp_server.tool()
118
+ async def add_task(
119
+ user_id: int,
120
+ title: str,
121
+ description: Optional[str] = None,
122
+ due_date: Optional[str] = None,
123
+ priority: Optional[str] = None
124
+ ) -> dict:
125
+ """Add a new task to the user's todo list.
126
+
127
+ Args:
128
+ user_id: ID of the user creating the task (injected by backend)
129
+ title: Task title (required)
130
+ description: Optional task description
131
+ due_date: Optional due date in ISO format
132
+ priority: Optional priority (low, medium, high)
133
+
134
+ Returns:
135
+ dict: {success: bool, task: Task, message: str}
136
+ """
137
+ # Implementation with database access
138
+ async with get_db_session() as db:
139
+ task = Task(
140
+ user_id=user_id,
141
+ title=title,
142
+ description=description,
143
+ # ... other fields
144
+ )
145
+ db.add(task)
146
+ await db.commit()
147
+ await db.refresh(task)
148
+
149
+ return {
150
+ "success": True,
151
+ "task": task.dict(),
152
+ "message": f"Task '{title}' created successfully"
153
+ }
154
+ ```
155
+
156
+ **Stateless Implementation Best Practices**:
157
+ 1. **No in-memory state** - All state persists in database
158
+ 2. **Explicit user context** - `user_id` passed to every tool (injected by backend, not LLM)
159
+ 3. **Database transactions** - Use transactions for consistency
160
+ 4. **Structured responses** - Always return `{success, data, message}` format
161
+ 5. **Error handling** - Return structured errors, don't throw exceptions
162
+
163
+ **Tool Registration**:
164
+
165
+ ```python
166
+ class MCPToolRegistry:
167
+ """Registry for MCP tools with user context injection."""
168
+
169
+ def __init__(self):
170
+ self.tools: Dict[str, Callable] = {}
171
+ self.tool_schemas: Dict[str, Dict] = {}
172
+
173
+ def register_tool(self, name: str, func: Callable, schema: Dict):
174
+ """Register a tool with its schema."""
175
+ self.tools[name] = func
176
+ self.tool_schemas[name] = schema
177
+
178
+ def get_tool_definitions(self) -> List[Dict]:
179
+ """Get tool definitions for LLM in OpenAI function format."""
180
+ return [
181
+ {
182
+ "type": "function",
183
+ "function": {
184
+ "name": name,
185
+ "description": schema["description"],
186
+ "parameters": schema["parameters"]
187
+ }
188
+ }
189
+ for name, schema in self.tool_schemas.items()
190
+ ]
191
+
192
+ async def execute_tool(
193
+ self,
194
+ tool_name: str,
195
+ arguments: Dict[str, Any],
196
+ user_id: int
197
+ ) -> Dict[str, Any]:
198
+ """Execute a tool with user context injection."""
199
+ if tool_name not in self.tools:
200
+ return {"success": False, "error": f"Tool '{tool_name}' not found"}
201
+
202
+ try:
203
+ # SECURITY: Inject user_id, don't trust LLM output
204
+ arguments["user_id"] = user_id
205
+ result = await self.tools[tool_name](**arguments)
206
+ return result
207
+ except Exception as e:
208
+ logger.error(f"Tool execution error: {tool_name}", exc_info=True)
209
+ return {"success": False, "error": str(e)}
210
+ ```
211
+
212
+ ---
213
+
214
+ ## 3. Free-Tier Provider Capabilities
215
+
216
+ ### Provider Capability Matrix
217
+
218
+ | Provider | Function Calling | Context Window | Rate Limits | Token Caps | Cost | Recommendation |
219
+ |----------|------------------|----------------|-------------|------------|------|----------------|
220
+ | **Google Gemini** | ✅ Full support | 1M-2M tokens | 15 RPM, 1500 RPD | 1M tokens/min | Free | **PRIMARY** |
221
+ | **OpenRouter** | ✅ Select models | 4k-200k tokens | Varies by model | Varies | Free models available | **FALLBACK** |
222
+ | **Cohere** | ✅ Yes | 4k-128k tokens | 100/min (trial) | Limited | Trial only | **NOT RECOMMENDED** |
223
+
224
+ **Legend**:
225
+ - RPM: Requests Per Minute
226
+ - RPD: Requests Per Day
227
+
228
+ ### Decision: Google Gemini as Primary Provider
229
+
230
+ **Primary Provider**: Google Gemini (`gemini-1.5-flash`)
231
+
232
+ **Rationale**:
233
+ - **Best free-tier offering**: No credit card required, true free tier
234
+ - **Full function calling support**: Native support for tool invocation
235
+ - **Large context window**: 1M tokens (handles long conversations)
236
+ - **Generous rate limits**: 15 RPM, 1500 RPD sufficient for development and small-scale production
237
+ - **Already integrated**: `google-generativeai` SDK already installed in backend
238
+
239
+ **Fallback Provider**: OpenRouter (free models)
240
+
241
+ **Rationale**:
242
+ - **Good backup**: When Gemini hits rate limits
243
+ - **Free models available**: `google/gemini-flash-1.5:free`, `meta-llama/llama-3.2-3b-instruct:free`
244
+ - **No additional cost**: Maintains free-tier requirement
245
+
246
+ **Cohere NOT Recommended**:
247
+ - **Trial only**: Not a true free tier
248
+ - **Limited availability**: Trial expires
249
+ - **Smaller context window**: 4k-128k tokens insufficient for long conversations
250
+
251
+ ### Implementation: Gemini Provider with Function Calling
252
+
253
+ ```python
254
+ import google.generativeai as genai
255
+ from typing import List, Dict, Any, Optional
256
+
257
+ class GeminiProvider(LLMProvider):
258
+ """Google Gemini provider with function calling support."""
259
+
260
+ def __init__(self, api_key: str, model_name: str = "gemini-1.5-flash"):
261
+ genai.configure(api_key=api_key)
262
+ self.model_name = model_name
263
+
264
+ async def generate_response_with_tools(
265
+ self,
266
+ messages: List[Dict[str, str]],
267
+ system_prompt: str,
268
+ tools: List[Dict[str, Any]]
269
+ ) -> Dict[str, Any]:
270
+ """Generate response with function calling support."""
271
+
272
+ # Convert tools to Gemini format
273
+ gemini_tools = self._convert_tools_to_gemini_format(tools)
274
+
275
+ # Initialize model with tools
276
+ model = genai.GenerativeModel(
277
+ model_name=self.model_name,
278
+ tools=gemini_tools,
279
+ system_instruction=system_prompt
280
+ )
281
+
282
+ # Start chat with history
283
+ chat = model.start_chat(history=self._format_history(messages[:-1]))
284
+
285
+ # Send latest message
286
+ response = chat.send_message(messages[-1]["content"])
287
+
288
+ # Check for function calls
289
+ if response.candidates[0].content.parts[0].function_call:
290
+ function_call = response.candidates[0].content.parts[0].function_call
291
+ return {
292
+ "content": None,
293
+ "tool_calls": [{
294
+ "name": function_call.name,
295
+ "arguments": dict(function_call.args)
296
+ }]
297
+ }
298
+
299
+ # Regular text response
300
+ return {
301
+ "content": response.text,
302
+ "tool_calls": None
303
+ }
304
+
305
+ async def generate_response_with_tool_results(
306
+ self,
307
+ messages: List[Dict[str, str]],
308
+ tool_calls: List[Dict],
309
+ tool_results: List[Dict]
310
+ ) -> Dict[str, Any]:
311
+ """Generate final response after tool execution."""
312
+
313
+ # Format tool results for Gemini
314
+ function_responses = [
315
+ genai.protos.FunctionResponse(
316
+ name=tool_call["name"],
317
+ response={"result": tool_result}
318
+ )
319
+ for tool_call, tool_result in zip(tool_calls, tool_results)
320
+ ]
321
+
322
+ # Send tool results back to model
323
+ model = genai.GenerativeModel(model_name=self.model_name)
324
+ chat = model.start_chat(history=self._format_history(messages))
325
+
326
+ response = chat.send_message(
327
+ genai.protos.Content(parts=[
328
+ genai.protos.Part(function_response=fr)
329
+ for fr in function_responses
330
+ ])
331
+ )
332
+
333
+ return {
334
+ "content": response.text,
335
+ "tool_calls": tool_calls,
336
+ "tool_results": tool_results
337
+ }
338
+
339
+ def _convert_tools_to_gemini_format(self, tools: List[Dict]) -> List:
340
+ """Convert OpenAI function format to Gemini format."""
341
+ gemini_tools = []
342
+ for tool in tools:
343
+ func = tool["function"]
344
+ gemini_tools.append(
345
+ genai.protos.Tool(
346
+ function_declarations=[
347
+ genai.protos.FunctionDeclaration(
348
+ name=func["name"],
349
+ description=func["description"],
350
+ parameters=func["parameters"]
351
+ )
352
+ ]
353
+ )
354
+ )
355
+ return gemini_tools
356
+
357
+ def _format_history(self, messages: List[Dict]) -> List:
358
+ """Format messages for Gemini chat history."""
359
+ return [
360
+ genai.protos.Content(
361
+ role="user" if msg["role"] == "user" else "model",
362
+ parts=[genai.protos.Part(text=msg["content"])]
363
+ )
364
+ for msg in messages
365
+ ]
366
+ ```
367
+
368
+ ### Rate Limit Handling
369
+
370
+ ```python
371
+ class RateLimitHandler:
372
+ """Handle rate limits with fallback provider."""
373
+
374
+ def __init__(self, primary_provider: LLMProvider, fallback_provider: Optional[LLMProvider] = None):
375
+ self.primary = primary_provider
376
+ self.fallback = fallback_provider
377
+ self.rate_limit_count = 0
378
+
379
+ async def generate_response(self, *args, **kwargs):
380
+ """Generate response with automatic fallback."""
381
+ try:
382
+ return await self.primary.generate_response_with_tools(*args, **kwargs)
383
+ except Exception as e:
384
+ if "rate limit" in str(e).lower() or "429" in str(e):
385
+ self.rate_limit_count += 1
386
+ logger.warning(f"Rate limit hit on primary provider, using fallback")
387
+
388
+ if self.fallback:
389
+ return await self.fallback.generate_response_with_tools(*args, **kwargs)
390
+ else:
391
+ raise HTTPException(
392
+ status_code=429,
393
+ detail="Rate limit exceeded. Please try again in a few minutes."
394
+ )
395
+ raise
396
+ ```
397
+
398
+ ---
399
+
400
+ ## 4. Agent-MCP Integration Pattern
401
+
402
+ ### Decision: Tool Registry with User Context Injection
403
+
404
+ **Rationale**:
405
+ - **Security**: User context (`user_id`) injected by backend, never trusted from LLM
406
+ - **Stateless**: Tools receive all context explicitly
407
+ - **Testable**: Tools can be tested independently
408
+ - **Maintainable**: Clear separation between agent logic and tool execution
409
+
410
+ **Tool Invocation Flow**:
411
+
412
+ ```
413
+ User Message → LLM (with tools) → Tool Calls → Execute MCP Tools →
414
+ Tool Results → LLM (with results) → Final Response
415
+ ```
416
+
417
+ **Implementation Pattern**:
418
+
419
+ ```python
420
+ class AgentRunner:
421
+ """Agent orchestration with MCP tool integration."""
422
+
423
+ async def execute(
424
+ self,
425
+ messages: List[Dict],
426
+ system_prompt: str,
427
+ user_id: int
428
+ ) -> Dict[str, Any]:
429
+ """Execute agent with tool invocation."""
430
+
431
+ # 1. Get tool definitions
432
+ tool_definitions = self.tools.get_tool_definitions()
433
+
434
+ # 2. First LLM call with tools
435
+ response = await self.provider.generate_response_with_tools(
436
+ messages=messages,
437
+ system_prompt=system_prompt,
438
+ tools=tool_definitions
439
+ )
440
+
441
+ # 3. If no tool calls, return response
442
+ if not response.get("tool_calls"):
443
+ return {
444
+ "content": response["content"],
445
+ "tool_calls": None,
446
+ "tool_results": None
447
+ }
448
+
449
+ # 4. Execute tool calls
450
+ tool_results = []
451
+ for tool_call in response["tool_calls"]:
452
+ result = await self.tools.execute_tool(
453
+ tool_name=tool_call["name"],
454
+ arguments=tool_call["arguments"],
455
+ user_id=user_id # SECURITY: Inject user context
456
+ )
457
+ tool_results.append(result)
458
+
459
+ # 5. Second LLM call with tool results
460
+ final_response = await self.provider.generate_response_with_tool_results(
461
+ messages=messages,
462
+ tool_calls=response["tool_calls"],
463
+ tool_results=tool_results
464
+ )
465
+
466
+ return {
467
+ "content": final_response["content"],
468
+ "tool_calls": response["tool_calls"],
469
+ "tool_results": tool_results
470
+ }
471
+ ```
472
+
473
+ **Error Propagation**:
474
+
475
+ ```python
476
+ async def execute_tool(self, tool_name: str, arguments: Dict, user_id: int) -> Dict:
477
+ """Execute tool with error handling."""
478
+ try:
479
+ # Inject user_id
480
+ arguments["user_id"] = user_id
481
+
482
+ # Execute tool
483
+ result = await self.tools[tool_name](**arguments)
484
+
485
+ # Validate result format
486
+ if not isinstance(result, dict) or "success" not in result:
487
+ return {
488
+ "success": False,
489
+ "error": "Tool returned invalid response format"
490
+ }
491
+
492
+ return result
493
+
494
+ except KeyError:
495
+ return {
496
+ "success": False,
497
+ "error": f"Tool '{tool_name}' not found"
498
+ }
499
+ except TypeError as e:
500
+ return {
501
+ "success": False,
502
+ "error": f"Invalid arguments for tool '{tool_name}': {str(e)}"
503
+ }
504
+ except Exception as e:
505
+ logger.error(f"Tool execution error: {tool_name}", exc_info=True)
506
+ return {
507
+ "success": False,
508
+ "error": f"Tool execution failed: {str(e)}"
509
+ }
510
+ ```
511
+
512
+ ---
513
+
514
+ ## 5. Stateless Request Cycle Implementation
515
+
516
+ ### Decision: Database-Backed Conversation History with Trimming
517
+
518
+ **Rationale**:
519
+ - **Stateless**: Every request loads conversation history from database
520
+ - **Scalable**: No in-memory state, supports horizontal scaling
521
+ - **Restart-safe**: Server restarts don't affect conversation continuity
522
+ - **Free-tier compatible**: Conversation history trimming handles token limits
523
+
524
+ **Complete Request Flow**:
525
+
526
+ ```python
527
+ @router.post("/api/{user_id}/chat", response_model=ChatResponse)
528
+ async def chat(
529
+ user_id: int,
530
+ request: ChatRequest,
531
+ db: Session = Depends(get_session),
532
+ current_user: Dict = Depends(get_current_user)
533
+ ) -> ChatResponse:
534
+ """Stateless chat endpoint with agent execution."""
535
+
536
+ # 1. Validate user authorization
537
+ if current_user["id"] != user_id:
538
+ raise HTTPException(status_code=401, detail="Unauthorized")
539
+
540
+ # 2. Load or create conversation
541
+ conversation_service = ConversationService(db)
542
+ conversation = await conversation_service.get_or_create_conversation(
543
+ user_id=user_id,
544
+ conversation_id=request.conversation_id
545
+ )
546
+
547
+ # 3. Load message history from database
548
+ messages = await conversation_service.get_messages(conversation.id)
549
+
550
+ # 4. Format and trim history for agent
551
+ message_history = await conversation_service.format_messages_for_agent(
552
+ messages=messages,
553
+ max_messages=20, # Keep last 20 messages
554
+ max_tokens=8000 # Trim to fit free-tier context window
555
+ )
556
+
557
+ # 5. Store user message
558
+ await conversation_service.add_message(
559
+ conversation_id=conversation.id,
560
+ role="user",
561
+ content=request.message
562
+ )
563
+
564
+ # 6. Execute agent with tools
565
+ llm_service = LLMService()
566
+ tool_registry = MCPToolRegistry()
567
+ agent = AgentRunner(provider=llm_service.provider, tools=tool_registry)
568
+
569
+ agent_response = await agent.execute(
570
+ messages=message_history + [{"role": "user", "content": request.message}],
571
+ system_prompt=llm_service.get_default_system_prompt(),
572
+ user_id=user_id
573
+ )
574
+
575
+ # 7. Store assistant message with tool metadata
576
+ await conversation_service.add_message(
577
+ conversation_id=conversation.id,
578
+ role="assistant",
579
+ content=agent_response["content"],
580
+ metadata={
581
+ "tool_calls": agent_response.get("tool_calls"),
582
+ "tool_results": agent_response.get("tool_results")
583
+ }
584
+ )
585
+
586
+ # 8. Return response
587
+ return ChatResponse(
588
+ message=agent_response["content"],
589
+ conversation_id=conversation.id
590
+ )
591
+ ```
592
+
593
+ **Conversation History Trimming**:
594
+
595
+ ```python
596
+ async def format_messages_for_agent(
597
+ self,
598
+ messages: List[Message],
599
+ max_messages: int = 20,
600
+ max_tokens: int = 8000
601
+ ) -> List[Dict[str, str]]:
602
+ """Format messages with trimming for free-tier constraints."""
603
+
604
+ # Keep last N messages
605
+ recent_messages = messages[-max_messages:]
606
+
607
+ # Format for agent
608
+ formatted = [
609
+ {"role": msg.role, "content": msg.content}
610
+ for msg in recent_messages
611
+ ]
612
+
613
+ # Estimate tokens (rough: 1 token ≈ 4 characters)
614
+ total_tokens = sum(len(msg["content"]) // 4 for msg in formatted)
615
+
616
+ # Trim oldest messages if over limit
617
+ while total_tokens > max_tokens and len(formatted) > 1:
618
+ formatted.pop(0) # Remove oldest
619
+ total_tokens = sum(len(msg["content"]) // 4 for msg in formatted)
620
+
621
+ return formatted
622
+ ```
623
+
624
+ **Concurrent Request Handling**:
625
+
626
+ ```python
627
+ # Use database transactions for consistency
628
+ async def add_message(
629
+ self,
630
+ conversation_id: int,
631
+ role: str,
632
+ content: str,
633
+ metadata: Optional[Dict] = None
634
+ ) -> Message:
635
+ """Add message with transaction for concurrent safety."""
636
+
637
+ async with self.db.begin(): # Transaction
638
+ message = Message(
639
+ conversation_id=conversation_id,
640
+ role=role,
641
+ content=content,
642
+ metadata=metadata,
643
+ created_at=datetime.utcnow()
644
+ )
645
+ self.db.add(message)
646
+ await self.db.flush() # Get ID before commit
647
+ await self.db.refresh(message)
648
+ return message
649
+ ```
650
+
651
+ ---
652
+
653
+ ## Implementation Recommendations
654
+
655
+ ### Phase 1: MCP Tools (Priority 1)
656
+
657
+ **Files to Create**:
658
+ - `backend/src/mcp/server.py` - MCP server setup
659
+ - `backend/src/mcp/tools/add_task.py` - add_task tool
660
+ - `backend/src/mcp/tools/list_tasks.py` - list_tasks tool
661
+ - `backend/src/mcp/tools/complete_task.py` - complete_task tool
662
+ - `backend/src/mcp/tools/delete_task.py` - delete_task tool
663
+ - `backend/src/mcp/tools/update_task.py` - update_task tool
664
+ - `backend/src/mcp/tool_registry.py` - MCPToolRegistry class
665
+
666
+ **Testing Strategy**:
667
+ - Unit tests for each tool in isolation
668
+ - Test with mock database
669
+ - Validate user scoping (users can only access their own tasks)
670
+
671
+ ### Phase 2: Provider Enhancement (Priority 2)
672
+
673
+ **Files to Modify**:
674
+ - `backend/src/services/llm_service.py` - Add function calling support to GeminiProvider
675
+ - `backend/src/services/providers/gemini.py` - Implement tool invocation methods
676
+ - `backend/src/services/providers/openrouter.py` - Create OpenRouter fallback provider
677
+
678
+ **Testing Strategy**:
679
+ - Test function calling with Gemini API
680
+ - Test tool definition conversion
681
+ - Test rate limit handling with fallback
682
+
683
+ ### Phase 3: Agent Integration (Priority 3)
684
+
685
+ **Files to Create**:
686
+ - `backend/src/agent/agent_runner.py` - AgentRunner class
687
+ - `backend/src/agent/agent_config.py` - Agent configuration
688
+
689
+ **Files to Modify**:
690
+ - `backend/src/services/llm_service.py` - Integrate AgentRunner
691
+
692
+ **Testing Strategy**:
693
+ - Test agent-tool integration
694
+ - Test tool invocation flow
695
+ - Test error handling
696
+
697
+ ### Phase 4: Chat Endpoint Integration (Priority 4)
698
+
699
+ **Files to Modify**:
700
+ - `backend/src/api/routes/chat.py` - Integrate AgentRunner
701
+ - `backend/src/services/conversation_service.py` - Add message formatting and trimming
702
+
703
+ **Testing Strategy**:
704
+ - End-to-end tests for chat flow
705
+ - Test conversation history loading
706
+ - Test tool metadata persistence
707
+ - Test concurrent requests
708
+
709
+ ---
710
+
711
+ ## Risk Mitigation
712
+
713
+ ### Technical Risks
714
+
715
+ 1. **Rate Limit Exhaustion**
716
+ - **Mitigation**: Implement fallback to OpenRouter
717
+ - **Monitoring**: Track rate limit hits
718
+ - **User Communication**: Display friendly error messages
719
+
720
+ 2. **Context Window Overflow**
721
+ - **Mitigation**: Conversation history trimming
722
+ - **Strategy**: Keep last 20 messages, max 8000 tokens
723
+ - **Fallback**: Summarize old messages if needed
724
+
725
+ 3. **Tool Execution Failures**
726
+ - **Mitigation**: Structured error responses
727
+ - **Logging**: Comprehensive error logging
728
+ - **User Experience**: Friendly error messages
729
+
730
+ ### Architectural Risks
731
+
732
+ 1. **Database Performance**
733
+ - **Mitigation**: Proper indexing on conversation_id, user_id
734
+ - **Optimization**: Limit message history queries
735
+ - **Monitoring**: Track query performance
736
+
737
+ 2. **Concurrent Requests**
738
+ - **Mitigation**: Database transactions
739
+ - **Testing**: Concurrent request tests
740
+ - **Validation**: Ensure no race conditions
741
+
742
+ ---
743
+
744
+ ## Conclusion
745
+
746
+ All research objectives have been met. The technical approach is validated and ready for implementation:
747
+
748
+ ✅ **Custom agent implementation** (not OpenAI Agents SDK)
749
+ ✅ **MCP SDK with FastMCP** (production-ready)
750
+ ✅ **Google Gemini as primary provider** (best free-tier offering)
751
+ ✅ **Tool registry with user context injection** (secure and stateless)
752
+ ✅ **Database-backed conversation history** (stateless and restart-safe)
753
+
754
+ **Next Steps**:
755
+ 1. Update `plan.md` with research decisions
756
+ 2. Generate Phase 1 design artifacts (data-model.md, contracts/, quickstart.md)
757
+ 3. Execute `/sp.tasks` to generate implementation tasks
758
+ 4. Begin implementation starting with MCP tools
specs/001-openai-agent-mcp-tools/spec.md ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Feature Specification: OpenAI Agent MCP Tools
2
+
3
+ **Feature Branch**: `001-openai-agent-mcp-tools`
4
+ **Created**: 2026-01-14
5
+ **Status**: Draft
6
+ **Input**: User description: "Spec-2: OpenAI Agent MCP Tools - AI execution layer with MCP server and task management tools"
7
+
8
+ ## Context
9
+
10
+ This is Spec-2 of Phase III: Todo AI Chatbot. This specification builds on top of Spec-1 (chat UI + basic agent wiring) and introduces the AI execution layer, MCP server, and task management tools. Spec-1 must already be complete before implementing this specification.
11
+
12
+ This specification explicitly focuses on:
13
+ - Building an AI agent using the OpenAI Agents SDK
14
+ - Configuring the agent to run using free-tier API keys via external client configuration
15
+ - Integrating Cohere as a supported provider
16
+ - Implementing MCP tools for task operations
17
+ - Keeping the backend fully stateless with database-backed persistence
18
+
19
+ ## User Scenarios & Testing *(mandatory)*
20
+
21
+ ### User Story 1 - Create Task via Natural Language (Priority: P1)
22
+
23
+ A user wants to create a new task by typing a natural language request to the AI agent, such as "Add a task to buy groceries" or "Remind me to call mom tomorrow."
24
+
25
+ **Why this priority**: This is the core value proposition of the AI-powered todo system. Without the ability to create tasks via natural language, the AI agent provides no functional value. This is the minimum viable feature that demonstrates the agent's capability.
26
+
27
+ **Independent Test**: Can be fully tested by sending a chat message with a task creation intent and verifying that a new task appears in the user's task list with the correct title and details.
28
+
29
+ **Acceptance Scenarios**:
30
+
31
+ 1. **Given** a logged-in user with an active conversation, **When** the user sends "Add a task to buy groceries", **Then** the agent creates a new task with title "Buy groceries" and confirms the creation in natural language
32
+ 2. **Given** a logged-in user, **When** the user sends "Create a task: finish project report by Friday", **Then** the agent creates a task with appropriate title and due date, and responds with confirmation
33
+ 3. **Given** a logged-in user, **When** the user sends an ambiguous request like "todo something", **Then** the agent asks for clarification about what task to create
34
+
35
+ ---
36
+
37
+ ### User Story 2 - List Tasks via Natural Language (Priority: P2)
38
+
39
+ A user wants to view their tasks by asking the AI agent in natural language, such as "Show me my tasks" or "What do I need to do today?"
40
+
41
+ **Why this priority**: After creating tasks, users need to view them. This is the second most critical feature for a functional todo system. It validates that the agent can retrieve and present information.
42
+
43
+ **Independent Test**: Can be fully tested by creating several tasks, then asking the agent to list them, and verifying that all tasks are returned in a readable format.
44
+
45
+ **Acceptance Scenarios**:
46
+
47
+ 1. **Given** a user with 3 existing tasks, **When** the user asks "Show me my tasks", **Then** the agent lists all 3 tasks with their titles and status
48
+ 2. **Given** a user with no tasks, **When** the user asks "What are my tasks?", **Then** the agent responds that there are no tasks currently
49
+ 3. **Given** a user with completed and incomplete tasks, **When** the user asks "Show me my incomplete tasks", **Then** the agent filters and shows only incomplete tasks
50
+
51
+ ---
52
+
53
+ ### User Story 3 - Complete Task via Natural Language (Priority: P3)
54
+
55
+ A user wants to mark a task as complete by telling the AI agent, such as "Mark 'buy groceries' as done" or "I finished the project report."
56
+
57
+ **Why this priority**: Completing tasks is a core workflow in any todo system. This feature demonstrates the agent's ability to modify existing data based on user intent.
58
+
59
+ **Independent Test**: Can be fully tested by creating a task, asking the agent to mark it complete, and verifying the task's status changes to completed.
60
+
61
+ **Acceptance Scenarios**:
62
+
63
+ 1. **Given** a user with an incomplete task "Buy groceries", **When** the user says "Mark 'buy groceries' as complete", **Then** the agent marks the task as complete and confirms the action
64
+ 2. **Given** a user with multiple tasks, **When** the user says "I finished task 2", **Then** the agent identifies the correct task by ID and marks it complete
65
+ 3. **Given** a user referencing a non-existent task, **When** the user says "Complete task 'xyz'", **Then** the agent responds that the task was not found and asks for clarification
66
+
67
+ ---
68
+
69
+ ### User Story 4 - Delete Task via Natural Language (Priority: P4)
70
+
71
+ A user wants to remove a task by asking the AI agent, such as "Delete the groceries task" or "Remove task 3."
72
+
73
+ **Why this priority**: Users need the ability to remove tasks that are no longer relevant. This is less critical than creation, viewing, and completion, but still important for task management.
74
+
75
+ **Independent Test**: Can be fully tested by creating a task, asking the agent to delete it, and verifying the task no longer appears in the task list.
76
+
77
+ **Acceptance Scenarios**:
78
+
79
+ 1. **Given** a user with a task "Buy groceries", **When** the user says "Delete the groceries task", **Then** the agent removes the task and confirms deletion
80
+ 2. **Given** a user with multiple tasks, **When** the user says "Remove task 2", **Then** the agent deletes the correct task by ID
81
+ 3. **Given** a user referencing a non-existent task, **When** the user says "Delete task 'xyz'", **Then** the agent responds that the task was not found
82
+
83
+ ---
84
+
85
+ ### User Story 5 - Update Task via Natural Language (Priority: P5)
86
+
87
+ A user wants to modify an existing task by telling the AI agent, such as "Change the groceries task to 'buy groceries and milk'" or "Update task 1 title to 'finish report by Monday'."
88
+
89
+ **Why this priority**: Task updates are useful but less critical than the core CRUD operations. Users can work around this by deleting and recreating tasks if needed.
90
+
91
+ **Independent Test**: Can be fully tested by creating a task, asking the agent to update it, and verifying the task's details have changed.
92
+
93
+ **Acceptance Scenarios**:
94
+
95
+ 1. **Given** a user with a task "Buy groceries", **When** the user says "Change the groceries task to 'buy groceries and milk'", **Then** the agent updates the task title and confirms the change
96
+ 2. **Given** a user with a task, **When** the user says "Update task 1 description to 'urgent'", **Then** the agent updates the task description field
97
+ 3. **Given** a user referencing a non-existent task, **When** the user says "Update task 'xyz'", **Then** the agent responds that the task was not found
98
+
99
+ ---
100
+
101
+ ### Edge Cases
102
+
103
+ - What happens when the agent receives a request while the external API provider (Gemini/OpenRouter/Cohere) is rate-limited or unavailable?
104
+ - How does the system handle ambiguous natural language requests that could map to multiple operations (e.g., "do something with task 1")?
105
+ - What happens when a user tries to complete or delete a task that was already completed or deleted by another session?
106
+ - How does the agent behave when the conversation history becomes very long and approaches the context window limit of free-tier models?
107
+ - What happens when the MCP server is unavailable or a tool call fails due to database connectivity issues?
108
+ - How does the system handle concurrent requests from the same user in multiple browser tabs?
109
+ - What happens when a user references a task by title but multiple tasks have similar titles?
110
+
111
+ ## Requirements *(mandatory)*
112
+
113
+ ### Functional Requirements
114
+
115
+ #### Agent Configuration
116
+
117
+ - **FR-001**: System MUST use the OpenAI Agents SDK to define the AI agent, including Agent, Runner, and Tool interfaces
118
+ - **FR-002**: System MUST configure the agent using an external client abstraction that supports free-tier API providers (Gemini, OpenRouter, Cohere)
119
+ - **FR-003**: System MUST allow switching between API providers via environment variables without code changes
120
+ - **FR-004**: System MUST support Cohere as either a primary provider or fallback provider
121
+ - **FR-005**: System MUST load all API keys from environment variables only (no hardcoded secrets)
122
+ - **FR-006**: System MUST handle free-tier constraints including short context windows, rate limits, and token caps
123
+ - **FR-007**: System MUST degrade gracefully when API provider errors occur or rate limits are hit
124
+
125
+ #### Agent Behavior
126
+
127
+ - **FR-008**: Agent MUST correctly map natural language task creation requests to the add_task MCP tool
128
+ - **FR-009**: Agent MUST correctly map natural language task listing requests to the list_tasks MCP tool
129
+ - **FR-010**: Agent MUST correctly map natural language task completion requests to the complete_task MCP tool
130
+ - **FR-011**: Agent MUST correctly map natural language task deletion requests to the delete_task MCP tool
131
+ - **FR-012**: Agent MUST correctly map natural language task update requests to the update_task MCP tool
132
+ - **FR-013**: Agent MUST confirm actions in friendly, natural language after executing MCP tools
133
+ - **FR-014**: Agent MUST handle errors (task not found, invalid input) gracefully and provide helpful error messages to users
134
+ - **FR-015**: Agent MUST ask clarifying questions when user intent is ambiguous
135
+ - **FR-016**: Agent MUST follow the Agent Behavior Specification defined in Phase III
136
+
137
+ #### MCP Server & Tools
138
+
139
+ - **FR-017**: System MUST implement an MCP server using the Official MCP SDK
140
+ - **FR-018**: MCP server MUST expose exactly 5 tools: add_task, list_tasks, complete_task, delete_task, update_task
141
+ - **FR-019**: Each MCP tool MUST validate all inputs before processing
142
+ - **FR-020**: Each MCP tool MUST enforce user scoping (users can only access their own tasks)
143
+ - **FR-021**: Each MCP tool MUST return structured responses that the agent can interpret
144
+ - **FR-022**: MCP tools MUST be stateless and persist all state in the database
145
+ - **FR-023**: add_task tool MUST accept task title and optional description, due date, and priority
146
+ - **FR-024**: list_tasks tool MUST return all tasks for the authenticated user with filtering options (completed/incomplete)
147
+ - **FR-025**: complete_task tool MUST accept a task identifier (ID or title) and mark the task as completed
148
+ - **FR-026**: delete_task tool MUST accept a task identifier (ID or title) and remove the task
149
+ - **FR-027**: update_task tool MUST accept a task identifier and fields to update (title, description, due date, priority, status)
150
+
151
+ #### Stateless Architecture
152
+
153
+ - **FR-028**: Backend MUST store NO in-memory state related to conversations or agent execution
154
+ - **FR-029**: Every chat request MUST load conversation and messages from the database
155
+ - **FR-030**: Every chat request MUST execute the agent with loaded context
156
+ - **FR-031**: Every chat request MUST persist agent responses and tool results to the database
157
+ - **FR-032**: Every chat request MUST return the response to the client
158
+ - **FR-033**: System MUST maintain conversation continuity across server restarts
159
+ - **FR-034**: System MUST support concurrent requests from multiple users without state conflicts
160
+
161
+ #### Security & Configuration
162
+
163
+ - **FR-035**: System MUST authenticate users using the existing Better Auth setup before allowing agent access
164
+ - **FR-036**: System MUST load external LLM provider API keys from environment variables
165
+ - **FR-037**: System MUST load Cohere API key from environment variables
166
+ - **FR-038**: System MUST support separate configuration for different API providers
167
+ - **FR-039**: System MUST NOT expose API keys in logs, error messages, or API responses
168
+ - **FR-040**: System MUST validate JWT tokens before processing any agent requests
169
+
170
+ #### Project Structure
171
+
172
+ - **FR-041**: All backend logic MUST remain inside the backend/ directory
173
+ - **FR-042**: MCP server code MUST be located inside the backend/ directory
174
+ - **FR-043**: No frontend changes are permitted in this specification
175
+ - **FR-044**: No file relocations or renames are permitted unless explicitly required and justified
176
+
177
+ ### Key Entities
178
+
179
+ - **Agent Configuration**: Represents the AI agent setup including provider selection, API keys, model parameters, and tool registrations. Attributes include provider type (Gemini/OpenRouter/Cohere), model name, context window size, and tool list.
180
+
181
+ - **MCP Tool**: Represents a callable function that the agent can invoke to perform task operations. Attributes include tool name, input schema, output schema, and validation rules.
182
+
183
+ - **Tool Execution Result**: Represents the outcome of an MCP tool invocation. Attributes include success status, data payload (task object or list of tasks), error message (if failed), and execution timestamp.
184
+
185
+ - **Agent Request Context**: Represents the context needed for agent execution. Attributes include user ID, conversation ID, message history, and authentication token.
186
+
187
+ ## Success Criteria *(mandatory)*
188
+
189
+ ### Measurable Outcomes
190
+
191
+ - **SC-001**: Users can create tasks using natural language with 95% success rate for clear, unambiguous requests
192
+ - **SC-002**: Users can list, complete, delete, and update tasks using natural language with 90% success rate
193
+ - **SC-003**: System operates successfully using free-tier API keys without requiring paid subscriptions
194
+ - **SC-004**: Conversations persist correctly across server restarts with 100% continuity
195
+ - **SC-005**: Agent responds to user requests within 5 seconds under normal conditions (excluding API provider delays)
196
+ - **SC-006**: System handles at least 50 concurrent users without degradation
197
+ - **SC-007**: MCP tool invocations succeed 99% of the time when inputs are valid
198
+ - **SC-008**: Agent correctly interprets user intent and selects the appropriate MCP tool 90% of the time
199
+ - **SC-009**: System gracefully handles API provider rate limits and errors without crashing
200
+ - **SC-010**: All task operations enforce user scoping with 100% accuracy (no cross-user data leaks)
201
+
202
+ ## Assumptions
203
+
204
+ - Spec-1 (chat UI + basic agent wiring) is already complete and functional
205
+ - Database schema for conversations and messages already exists from Spec-1
206
+ - Database schema for tasks already exists from Phase II
207
+ - Better Auth is already configured and issuing JWT tokens
208
+ - Frontend already has a chat interface that can send messages and display responses
209
+ - Users are already authenticated before accessing the chat interface
210
+ - The OpenAI Agents SDK is compatible with external client configurations for non-OpenAI providers
211
+ - Free-tier API providers (Gemini, OpenRouter, Cohere) support the necessary features for agent execution (function calling, structured outputs)
212
+ - The Official MCP SDK is available and compatible with the backend technology stack
213
+
214
+ ## Dependencies
215
+
216
+ - Spec-1 (chat UI + basic agent wiring) must be complete
217
+ - OpenAI Agents SDK must be installed and configured
218
+ - Official MCP SDK must be installed and configured
219
+ - External API provider accounts (Gemini, OpenRouter, Cohere) must be created and API keys obtained
220
+ - Database must be accessible and contain the necessary tables for conversations, messages, and tasks
221
+ - Better Auth must be functional and issuing valid JWT tokens
222
+
223
+ ## Out of Scope
224
+
225
+ The following items are explicitly excluded from this specification:
226
+
227
+ - UI/UX changes to the chat interface
228
+ - Advanced memory optimization or conversation summarization
229
+ - Multi-agent orchestration or agent-to-agent communication
230
+ - Paid OpenAI API usage or GPT-4 integration
231
+ - Voice input or speech-to-text capabilities
232
+ - Task sharing or collaboration features
233
+ - Task reminders or notifications
234
+ - Task categories or tags
235
+ - Task search or filtering beyond basic completed/incomplete status
236
+ - Performance optimization beyond basic functionality
237
+ - Advanced error recovery or retry mechanisms
238
+ - Monitoring, logging, or observability infrastructure
239
+ - Load testing or stress testing
240
+ - Deployment or infrastructure changes
241
+
242
+ ## Notes
243
+
244
+ - The agent behavior must strictly follow the Agent Behavior Specification defined in Phase III (reference to be provided during planning)
245
+ - The choice between using Cohere as primary or fallback provider should be configurable via environment variables
246
+ - The MCP server should be designed to allow easy addition of new tools in future specifications
247
+ - Error handling should prioritize user experience over technical accuracy (friendly messages, not stack traces)
248
+ - The stateless architecture is critical for scalability and must not be compromised
specs/001-openai-agent-mcp-tools/tasks.md ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tasks: OpenAI Agent MCP Tools
2
+
3
+ **Input**: Design documents from `/specs/001-openai-agent-mcp-tools/`
4
+ **Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/
5
+
6
+ **Tests**: Tests are NOT explicitly requested in the specification, so test tasks are omitted per template guidelines.
7
+
8
+ **Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
9
+
10
+ ## Format: `[ID] [P?] [Story] Description`
11
+
12
+ - **[P]**: Can run in parallel (different files, no dependencies)
13
+ - **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
14
+ - Include exact file paths in descriptions
15
+
16
+ ## Path Conventions
17
+
18
+ - **Web app**: `backend/src/`, `frontend/src/`
19
+ - All tasks are backend-only per plan.md
20
+
21
+ ---
22
+
23
+ ## Phase 1: Setup (Shared Infrastructure)
24
+
25
+ **Purpose**: Project initialization and dependency installation
26
+
27
+ - [ ] T001 Install MCP SDK and Cohere SDK in backend/requirements.txt
28
+ - [ ] T002 [P] Create backend/src/agent/ directory structure with __init__.py
29
+ - [ ] T003 [P] Create backend/src/mcp/ directory structure with __init__.py
30
+ - [ ] T004 [P] Create backend/src/agent/providers/ directory with __init__.py
31
+ - [ ] T005 [P] Create backend/src/mcp/tools/ directory with __init__.py
32
+
33
+ ---
34
+
35
+ ## Phase 2: Foundational (Blocking Prerequisites)
36
+
37
+ **Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
38
+
39
+ **⚠️ CRITICAL**: No user story work can begin until this phase is complete
40
+
41
+ - [ ] T006 Create MCPToolRegistry class in backend/src/mcp/tool_registry.py with user context injection
42
+ - [ ] T007 [P] Create LLMProvider base class in backend/src/agent/providers/base.py
43
+ - [ ] T008 [P] Implement GeminiProvider with function calling in backend/src/agent/providers/gemini.py
44
+ - [ ] T009 [P] Implement OpenRouterProvider as fallback in backend/src/agent/providers/openrouter.py
45
+ - [ ] T010 [P] Implement CohereProvider (optional) in backend/src/agent/providers/cohere.py
46
+ - [ ] T011 Create AgentConfiguration dataclass in backend/src/agent/agent_config.py
47
+ - [ ] T012 Create AgentRunner class with tool invocation in backend/src/agent/agent_runner.py
48
+ - [ ] T013 Update ConversationService with format_messages_for_agent method in backend/src/services/conversation_service.py
49
+ - [ ] T014 Add environment variable loading for LLM_PROVIDER, GEMINI_API_KEY, OPENROUTER_API_KEY in backend/src/core/config.py
50
+
51
+ **Checkpoint**: Foundation ready - user story implementation can now begin in parallel
52
+
53
+ ---
54
+
55
+ ## Phase 3: User Story 1 - Create Task via Natural Language (Priority: P1) 🎯 MVP
56
+
57
+ **Goal**: Enable users to create tasks by sending natural language requests like "Add a task to buy groceries"
58
+
59
+ **Independent Test**: Send chat message "Add a task to buy groceries" and verify new task appears in database with correct title
60
+
61
+ **Agent**: Backend Systems Agent
62
+ **Skill**: backend-mcp-tools
63
+
64
+ ### Implementation for User Story 1
65
+
66
+ - [ ] T015 [P] [US1] Implement add_task MCP tool in backend/src/mcp/tools/add_task.py with user_id injection and validation
67
+ - [ ] T016 [US1] Register add_task tool with MCPToolRegistry in backend/src/mcp/tool_registry.py
68
+ - [ ] T017 [US1] Update AgentRunner to support add_task tool invocation in backend/src/agent/agent_runner.py
69
+ - [ ] T018 [US1] Modify chat endpoint to use AgentRunner for task creation in backend/src/api/routes/chat.py
70
+ - [ ] T019 [US1] Add error handling for task creation failures in backend/src/mcp/tools/add_task.py
71
+ - [ ] T020 [US1] Test end-to-end: "Add a task to buy groceries" creates task and returns confirmation
72
+
73
+ **Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
74
+
75
+ ---
76
+
77
+ ## Phase 4: User Story 2 - List Tasks via Natural Language (Priority: P2)
78
+
79
+ **Goal**: Enable users to view their tasks by asking "Show me my tasks" or "What do I need to do today?"
80
+
81
+ **Independent Test**: Create 3 tasks, send "Show me my tasks", verify all 3 tasks are listed in response
82
+
83
+ **Agent**: Backend Systems Agent
84
+ **Skill**: backend-mcp-tools
85
+
86
+ ### Implementation for User Story 2
87
+
88
+ - [ ] T021 [P] [US2] Implement list_tasks MCP tool with filtering in backend/src/mcp/tools/list_tasks.py
89
+ - [ ] T022 [US2] Register list_tasks tool with MCPToolRegistry in backend/src/mcp/tool_registry.py
90
+ - [ ] T023 [US2] Update AgentRunner to support list_tasks tool invocation in backend/src/agent/agent_runner.py
91
+ - [ ] T024 [US2] Add filtering logic for completed/incomplete tasks in backend/src/mcp/tools/list_tasks.py
92
+ - [ ] T025 [US2] Test end-to-end: "Show me my tasks" returns all user tasks with correct formatting
93
+
94
+ **Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
95
+
96
+ ---
97
+
98
+ ## Phase 5: User Story 3 - Complete Task via Natural Language (Priority: P3)
99
+
100
+ **Goal**: Enable users to mark tasks complete by saying "Mark 'buy groceries' as done" or "I finished task 2"
101
+
102
+ **Independent Test**: Create task, send "Mark task 1 as complete", verify task status changes to completed in database
103
+
104
+ **Agent**: Backend Systems Agent
105
+ **Skill**: backend-mcp-tools
106
+
107
+ ### Implementation for User Story 3
108
+
109
+ - [ ] T026 [P] [US3] Implement complete_task MCP tool with ID/title lookup in backend/src/mcp/tools/complete_task.py
110
+ - [ ] T027 [US3] Register complete_task tool with MCPToolRegistry in backend/src/mcp/tool_registry.py
111
+ - [ ] T028 [US3] Update AgentRunner to support complete_task tool invocation in backend/src/agent/agent_runner.py
112
+ - [ ] T029 [US3] Add task identifier resolution (ID or title) in backend/src/mcp/tools/complete_task.py
113
+ - [ ] T030 [US3] Test end-to-end: "Mark task 1 as complete" updates task status and returns confirmation
114
+
115
+ **Checkpoint**: At this point, User Stories 1, 2, AND 3 should all work independently
116
+
117
+ ---
118
+
119
+ ## Phase 6: User Story 4 - Delete Task via Natural Language (Priority: P4)
120
+
121
+ **Goal**: Enable users to remove tasks by saying "Delete the groceries task" or "Remove task 3"
122
+
123
+ **Independent Test**: Create task, send "Delete task 1", verify task no longer exists in database
124
+
125
+ **Agent**: Backend Systems Agent
126
+ **Skill**: backend-mcp-tools
127
+
128
+ ### Implementation for User Story 4
129
+
130
+ - [ ] T031 [P] [US4] Implement delete_task MCP tool with ID/title lookup in backend/src/mcp/tools/delete_task.py
131
+ - [ ] T032 [US4] Register delete_task tool with MCPToolRegistry in backend/src/mcp/tool_registry.py
132
+ - [ ] T033 [US4] Update AgentRunner to support delete_task tool invocation in backend/src/agent/agent_runner.py
133
+ - [ ] T034 [US4] Add task identifier resolution (ID or title) in backend/src/mcp/tools/delete_task.py
134
+ - [ ] T035 [US4] Test end-to-end: "Delete task 1" removes task and returns confirmation
135
+
136
+ **Checkpoint**: At this point, User Stories 1-4 should all work independently
137
+
138
+ ---
139
+
140
+ ## Phase 7: User Story 5 - Update Task via Natural Language (Priority: P5)
141
+
142
+ **Goal**: Enable users to modify tasks by saying "Change the groceries task to 'buy groceries and milk'"
143
+
144
+ **Independent Test**: Create task, send "Update task 1 title to 'new title'", verify task title changes in database
145
+
146
+ **Agent**: Backend Systems Agent
147
+ **Skill**: backend-mcp-tools
148
+
149
+ ### Implementation for User Story 5
150
+
151
+ - [ ] T036 [P] [US5] Implement update_task MCP tool with field updates in backend/src/mcp/tools/update_task.py
152
+ - [ ] T037 [US5] Register update_task tool with MCPToolRegistry in backend/src/mcp/tool_registry.py
153
+ - [ ] T038 [US5] Update AgentRunner to support update_task tool invocation in backend/src/agent/agent_runner.py
154
+ - [ ] T039 [US5] Add task identifier resolution and field validation in backend/src/mcp/tools/update_task.py
155
+ - [ ] T040 [US5] Test end-to-end: "Update task 1 title to 'new title'" modifies task and returns confirmation
156
+
157
+ **Checkpoint**: All user stories should now be independently functional
158
+
159
+ ---
160
+
161
+ ## Phase 8: Polish & Cross-Cutting Concerns
162
+
163
+ **Purpose**: Improvements that affect multiple user stories
164
+
165
+ - [ ] T041 [P] Add rate limit handling with fallback provider in backend/src/agent/agent_runner.py
166
+ - [ ] T042 [P] Add comprehensive error logging for all MCP tools in backend/src/mcp/tools/
167
+ - [ ] T043 [P] Add conversation history trimming (20 messages, 8000 tokens) in backend/src/services/conversation_service.py
168
+ - [ ] T044 [P] Update LLMService to delegate to AgentRunner in backend/src/services/llm_service.py
169
+ - [ ] T045 [P] Add tool call metadata persistence in Message.metadata in backend/src/services/conversation_service.py
170
+ - [ ] T046 Validate quickstart.md instructions by running all test scenarios
171
+ - [ ] T047 [P] Add system prompt configuration for agent behavior in backend/src/agent/agent_config.py
172
+ - [ ] T048 [P] Document environment variables in backend/.env.example
173
+
174
+ ---
175
+
176
+ ## Dependencies & Execution Order
177
+
178
+ ### Phase Dependencies
179
+
180
+ - **Setup (Phase 1)**: No dependencies - can start immediately
181
+ - **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
182
+ - **User Stories (Phase 3-7)**: All depend on Foundational phase completion
183
+ - User stories can then proceed in parallel (if staffed)
184
+ - Or sequentially in priority order (P1 → P2 → P3 → P4 → P5)
185
+ - **Polish (Phase 8)**: Depends on all desired user stories being complete
186
+
187
+ ### User Story Dependencies
188
+
189
+ - **User Story 1 (P1)**: Can start after Foundational (Phase 2) - No dependencies on other stories
190
+ - **User Story 2 (P2)**: Can start after Foundational (Phase 2) - Independent of US1
191
+ - **User Story 3 (P3)**: Can start after Foundational (Phase 2) - Independent of US1/US2
192
+ - **User Story 4 (P4)**: Can start after Foundational (Phase 2) - Independent of US1/US2/US3
193
+ - **User Story 5 (P5)**: Can start after Foundational (Phase 2) - Independent of US1/US2/US3/US4
194
+
195
+ ### Within Each User Story
196
+
197
+ - MCP tool implementation before registration
198
+ - Tool registration before AgentRunner integration
199
+ - AgentRunner integration before chat endpoint modification
200
+ - Core implementation before end-to-end testing
201
+
202
+ ### Parallel Opportunities
203
+
204
+ - All Setup tasks (T002-T005) marked [P] can run in parallel
205
+ - All Foundational provider tasks (T007-T010) marked [P] can run in parallel
206
+ - Once Foundational phase completes, all user stories can start in parallel (if team capacity allows)
207
+ - All MCP tool implementations (T015, T021, T026, T031, T036) marked [P] can run in parallel after Foundational
208
+ - All Polish tasks marked [P] can run in parallel
209
+
210
+ ---
211
+
212
+ ## Parallel Example: After Foundational Phase
213
+
214
+ ```bash
215
+ # Launch all MCP tool implementations together:
216
+ Task: "Implement add_task MCP tool in backend/src/mcp/tools/add_task.py"
217
+ Task: "Implement list_tasks MCP tool in backend/src/mcp/tools/list_tasks.py"
218
+ Task: "Implement complete_task MCP tool in backend/src/mcp/tools/complete_task.py"
219
+ Task: "Implement delete_task MCP tool in backend/src/mcp/tools/delete_task.py"
220
+ Task: "Implement update_task MCP tool in backend/src/mcp/tools/update_task.py"
221
+
222
+ # Then register all tools together:
223
+ Task: "Register add_task tool with MCPToolRegistry"
224
+ Task: "Register list_tasks tool with MCPToolRegistry"
225
+ Task: "Register complete_task tool with MCPToolRegistry"
226
+ Task: "Register delete_task tool with MCPToolRegistry"
227
+ Task: "Register update_task tool with MCPToolRegistry"
228
+ ```
229
+
230
+ ---
231
+
232
+ ## Implementation Strategy
233
+
234
+ ### MVP First (User Story 1 Only)
235
+
236
+ 1. Complete Phase 1: Setup (T001-T005)
237
+ 2. Complete Phase 2: Foundational (T006-T014) - CRITICAL - blocks all stories
238
+ 3. Complete Phase 3: User Story 1 (T015-T020)
239
+ 4. **STOP and VALIDATE**: Test User Story 1 independently
240
+ - Send "Add a task to buy groceries"
241
+ - Verify task created in database
242
+ - Verify agent returns confirmation
243
+ 5. Deploy/demo if ready
244
+
245
+ ### Incremental Delivery
246
+
247
+ 1. Complete Setup + Foundational → Foundation ready
248
+ 2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
249
+ 3. Add User Story 2 → Test independently → Deploy/Demo
250
+ 4. Add User Story 3 → Test independently → Deploy/Demo
251
+ 5. Add User Story 4 → Test independently → Deploy/Demo
252
+ 6. Add User Story 5 → Test independently → Deploy/Demo
253
+ 7. Each story adds value without breaking previous stories
254
+
255
+ ### Parallel Team Strategy
256
+
257
+ With multiple developers:
258
+
259
+ 1. Team completes Setup + Foundational together (T001-T014)
260
+ 2. Once Foundational is done:
261
+ - Developer A: User Story 1 (T015-T020)
262
+ - Developer B: User Story 2 (T021-T025)
263
+ - Developer C: User Story 3 (T026-T030)
264
+ - Developer D: User Story 4 (T031-T035)
265
+ - Developer E: User Story 5 (T036-T040)
266
+ 3. Stories complete and integrate independently
267
+
268
+ ---
269
+
270
+ ## Task Summary
271
+
272
+ **Total Tasks**: 48 tasks
273
+
274
+ **Tasks per Phase**:
275
+ - Phase 1 (Setup): 5 tasks
276
+ - Phase 2 (Foundational): 9 tasks (BLOCKING)
277
+ - Phase 3 (US1 - Create Task): 6 tasks
278
+ - Phase 4 (US2 - List Tasks): 5 tasks
279
+ - Phase 5 (US3 - Complete Task): 5 tasks
280
+ - Phase 6 (US4 - Delete Task): 5 tasks
281
+ - Phase 7 (US5 - Update Task): 5 tasks
282
+ - Phase 8 (Polish): 8 tasks
283
+
284
+ **Parallel Opportunities**: 23 tasks marked [P] can run in parallel within their phase
285
+
286
+ **Independent Test Criteria**:
287
+ - US1: Send "Add a task to buy groceries" → Task created in DB
288
+ - US2: Send "Show me my tasks" → All tasks listed
289
+ - US3: Send "Mark task 1 as complete" → Task status updated
290
+ - US4: Send "Delete task 1" → Task removed from DB
291
+ - US5: Send "Update task 1 title to 'new title'" → Task title changed
292
+
293
+ **Suggested MVP Scope**: Phase 1 + Phase 2 + Phase 3 (User Story 1 only) = 20 tasks
294
+
295
+ ---
296
+
297
+ ## Notes
298
+
299
+ - [P] tasks = different files, no dependencies
300
+ - [Story] label maps task to specific user story for traceability
301
+ - Each user story should be independently completable and testable
302
+ - Commit after each task or logical group
303
+ - Stop at any checkpoint to validate story independently
304
+ - Research.md indicates custom agent implementation (NOT OpenAI Agents SDK)
305
+ - All MCP tools must inject user_id for security (never trust LLM output)
306
+ - Stateless architecture: load conversation history from DB on every request
307
+ - Free-tier constraints: trim history to 20 messages, 8000 tokens
specs/001-task-crud/checklists/requirements.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Specification Quality Checklist: Task CRUD Operations
2
+
3
+ **Purpose**: Validate specification completeness and quality before proceeding to planning
4
+ **Created**: 2026-01-08
5
+ **Feature**: [Task CRUD Operations](../spec.md)
6
+
7
+ ## Content Quality
8
+
9
+ - [x] No implementation details (languages, frameworks, APIs)
10
+ - [x] Focused on user value and business needs
11
+ - [x] Written for non-technical stakeholders
12
+ - [x] All mandatory sections completed
13
+
14
+ **Notes**: Spec successfully avoids implementation details. Technical constraints are properly separated in their own section. User stories focus on user value and business outcomes.
15
+
16
+ ## Requirement Completeness
17
+
18
+ - [x] No [NEEDS CLARIFICATION] markers remain
19
+ - [x] Requirements are testable and unambiguous
20
+ - [x] Success criteria are measurable
21
+ - [x] Success criteria are technology-agnostic (no implementation details)
22
+ - [x] All acceptance scenarios are defined
23
+ - [x] Edge cases are identified
24
+ - [x] Scope is clearly bounded
25
+ - [x] Dependencies and assumptions identified
26
+
27
+ **Notes**: All 15 functional requirements are specific and testable. Success criteria include both quantitative metrics (time, percentage) and qualitative measures (user understanding, visual feedback). Edge cases cover validation, concurrency, error handling, and security. Out of Scope section clearly defines boundaries.
28
+
29
+ ## Feature Readiness
30
+
31
+ - [x] All functional requirements have clear acceptance criteria
32
+ - [x] User scenarios cover primary flows
33
+ - [x] Feature meets measurable outcomes defined in Success Criteria
34
+ - [x] No implementation details leak into specification
35
+
36
+ **Notes**: 4 user stories with priorities P1-P4 cover the complete task management lifecycle. Each story has independent test criteria and acceptance scenarios. Success criteria align with functional requirements.
37
+
38
+ ## Validation Summary
39
+
40
+ **Status**: ✅ PASSED - Specification is complete and ready for planning phase
41
+
42
+ **Strengths**:
43
+ - Clear prioritization of user stories (P1-P4) enables incremental delivery
44
+ - Comprehensive functional requirements (FR-001 through FR-015)
45
+ - Measurable success criteria with specific metrics
46
+ - Well-defined data isolation and security requirements
47
+ - Explicit assumptions about authentication dependency
48
+
49
+ **Ready for**: `/sp.plan` (implementation planning)
50
+
51
+ ## Notes
52
+
53
+ All checklist items passed on first validation. No clarifications needed. The specification provides sufficient detail for architectural planning while remaining technology-agnostic in the requirements and success criteria sections.
specs/001-task-crud/contracts/README.md ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # API Contracts: Task CRUD Operations
2
+
3
+ **Feature**: Task CRUD Operations
4
+ **Date**: 2026-01-08
5
+ **Status**: Complete
6
+
7
+ ## Overview
8
+
9
+ This directory contains the API contract specifications for the Task CRUD feature. The contracts define the REST API endpoints, request/response formats, validation rules, and error handling.
10
+
11
+ ## Files
12
+
13
+ - **tasks-api.yaml**: OpenAPI 3.1.0 specification for all task endpoints
14
+
15
+ ## API Endpoints Summary
16
+
17
+ | Method | Endpoint | Description | Auth Required |
18
+ |--------|----------|-------------|---------------|
19
+ | GET | `/api/tasks` | List all tasks for authenticated user | Yes (JWT) |
20
+ | POST | `/api/tasks` | Create a new task | Yes (JWT) |
21
+ | GET | `/api/tasks/{task_id}` | Get a specific task | Yes (JWT) |
22
+ | PUT | `/api/tasks/{task_id}` | Update a task (full replacement) | Yes (JWT) |
23
+ | PATCH | `/api/tasks/{task_id}` | Partially update a task | Yes (JWT) |
24
+ | DELETE | `/api/tasks/{task_id}` | Delete a task | Yes (JWT) |
25
+
26
+ ## Authentication
27
+
28
+ All endpoints require JWT authentication via the `Authorization` header:
29
+
30
+ ```
31
+ Authorization: Bearer <jwt_token>
32
+ ```
33
+
34
+ **Note**: JWT token generation and validation will be implemented in Spec 2 (Authentication feature). For Spec 1 implementation, endpoints will accept a placeholder user_id parameter.
35
+
36
+ ## Request/Response Formats
37
+
38
+ ### TaskCreate (POST /api/tasks)
39
+
40
+ **Request Body**:
41
+ ```json
42
+ {
43
+ "title": "Buy groceries",
44
+ "description": "Milk, eggs, bread"
45
+ }
46
+ ```
47
+
48
+ **Response (201 Created)**:
49
+ ```json
50
+ {
51
+ "id": 1,
52
+ "user_id": 42,
53
+ "title": "Buy groceries",
54
+ "description": "Milk, eggs, bread",
55
+ "completed": false,
56
+ "created_at": "2026-01-08T10:00:00Z",
57
+ "updated_at": "2026-01-08T10:00:00Z"
58
+ }
59
+ ```
60
+
61
+ ### TaskUpdate (PUT /api/tasks/{task_id})
62
+
63
+ **Request Body**:
64
+ ```json
65
+ {
66
+ "title": "Buy groceries and milk",
67
+ "description": "Updated description",
68
+ "completed": false
69
+ }
70
+ ```
71
+
72
+ **Response (200 OK)**:
73
+ ```json
74
+ {
75
+ "id": 1,
76
+ "user_id": 42,
77
+ "title": "Buy groceries and milk",
78
+ "description": "Updated description",
79
+ "completed": false,
80
+ "created_at": "2026-01-08T10:00:00Z",
81
+ "updated_at": "2026-01-08T10:15:00Z"
82
+ }
83
+ ```
84
+
85
+ ### TaskPatch (PATCH /api/tasks/{task_id})
86
+
87
+ **Request Body** (partial update):
88
+ ```json
89
+ {
90
+ "completed": true
91
+ }
92
+ ```
93
+
94
+ **Response (200 OK)**:
95
+ ```json
96
+ {
97
+ "id": 1,
98
+ "user_id": 42,
99
+ "title": "Buy groceries",
100
+ "description": "Milk, eggs, bread",
101
+ "completed": true,
102
+ "created_at": "2026-01-08T10:00:00Z",
103
+ "updated_at": "2026-01-08T10:20:00Z"
104
+ }
105
+ ```
106
+
107
+ ### TaskListResponse (GET /api/tasks)
108
+
109
+ **Query Parameters**:
110
+ - `completed` (boolean, optional): Filter by completion status
111
+ - `sort` (string, optional): Sort order (created_at_desc, created_at_asc)
112
+ - `limit` (integer, optional): Maximum number of tasks (default: 50, max: 100)
113
+ - `offset` (integer, optional): Number of tasks to skip (default: 0)
114
+
115
+ **Response (200 OK)**:
116
+ ```json
117
+ {
118
+ "tasks": [
119
+ {
120
+ "id": 1,
121
+ "user_id": 42,
122
+ "title": "Buy groceries",
123
+ "description": "Milk, eggs, bread",
124
+ "completed": false,
125
+ "created_at": "2026-01-08T10:00:00Z",
126
+ "updated_at": "2026-01-08T10:00:00Z"
127
+ },
128
+ {
129
+ "id": 2,
130
+ "user_id": 42,
131
+ "title": "Finish project report",
132
+ "description": null,
133
+ "completed": true,
134
+ "created_at": "2026-01-07T15:30:00Z",
135
+ "updated_at": "2026-01-08T09:00:00Z"
136
+ }
137
+ ],
138
+ "total": 2
139
+ }
140
+ ```
141
+
142
+ ## Error Responses
143
+
144
+ ### 400 Bad Request (Validation Error)
145
+
146
+ ```json
147
+ {
148
+ "detail": "Validation error",
149
+ "error_code": "VALIDATION_ERROR",
150
+ "field_errors": {
151
+ "title": [
152
+ "Title must be between 1 and 200 characters"
153
+ ]
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### 401 Unauthorized
159
+
160
+ ```json
161
+ {
162
+ "detail": "Missing or invalid authentication token",
163
+ "error_code": "UNAUTHORIZED"
164
+ }
165
+ ```
166
+
167
+ ### 404 Not Found
168
+
169
+ ```json
170
+ {
171
+ "detail": "Task not found",
172
+ "error_code": "TASK_NOT_FOUND"
173
+ }
174
+ ```
175
+
176
+ ### 500 Internal Server Error
177
+
178
+ ```json
179
+ {
180
+ "detail": "An unexpected error occurred",
181
+ "error_code": "INTERNAL_SERVER_ERROR"
182
+ }
183
+ ```
184
+
185
+ ## Validation Rules
186
+
187
+ ### Title
188
+ - **Required**: Yes
189
+ - **Min Length**: 1 character
190
+ - **Max Length**: 200 characters
191
+ - **Type**: String
192
+
193
+ ### Description
194
+ - **Required**: No
195
+ - **Max Length**: 1000 characters
196
+ - **Type**: String or null
197
+
198
+ ### Completed
199
+ - **Required**: Yes (for PUT), No (for PATCH)
200
+ - **Type**: Boolean
201
+ - **Default**: false (on creation)
202
+
203
+ ## Data Isolation
204
+
205
+ All endpoints enforce user data isolation:
206
+ - Tasks are filtered by authenticated user ID
207
+ - Users can only access their own tasks
208
+ - Attempting to access another user's task returns 404 (not 403, to avoid information leakage)
209
+
210
+ ## Filtering and Sorting
211
+
212
+ ### Filter by Completion Status
213
+
214
+ **Get active tasks**:
215
+ ```
216
+ GET /api/tasks?completed=false
217
+ ```
218
+
219
+ **Get completed tasks**:
220
+ ```
221
+ GET /api/tasks?completed=true
222
+ ```
223
+
224
+ **Get all tasks** (no filter):
225
+ ```
226
+ GET /api/tasks
227
+ ```
228
+
229
+ ### Sort by Creation Date
230
+
231
+ **Newest first** (default):
232
+ ```
233
+ GET /api/tasks?sort=created_at_desc
234
+ ```
235
+
236
+ **Oldest first**:
237
+ ```
238
+ GET /api/tasks?sort=created_at_asc
239
+ ```
240
+
241
+ ### Pagination
242
+
243
+ **First page** (50 tasks):
244
+ ```
245
+ GET /api/tasks?limit=50&offset=0
246
+ ```
247
+
248
+ **Second page**:
249
+ ```
250
+ GET /api/tasks?limit=50&offset=50
251
+ ```
252
+
253
+ ## Testing the API
254
+
255
+ ### Using cURL
256
+
257
+ **Create a task**:
258
+ ```bash
259
+ curl -X POST http://localhost:8000/api/tasks \
260
+ -H "Content-Type: application/json" \
261
+ -H "Authorization: Bearer <jwt_token>" \
262
+ -d '{"title": "Buy groceries", "description": "Milk, eggs, bread"}'
263
+ ```
264
+
265
+ **List tasks**:
266
+ ```bash
267
+ curl -X GET http://localhost:8000/api/tasks \
268
+ -H "Authorization: Bearer <jwt_token>"
269
+ ```
270
+
271
+ **Update a task**:
272
+ ```bash
273
+ curl -X PUT http://localhost:8000/api/tasks/1 \
274
+ -H "Content-Type: application/json" \
275
+ -H "Authorization: Bearer <jwt_token>" \
276
+ -d '{"title": "Buy groceries and milk", "description": "Updated", "completed": false}'
277
+ ```
278
+
279
+ **Toggle completion**:
280
+ ```bash
281
+ curl -X PATCH http://localhost:8000/api/tasks/1 \
282
+ -H "Content-Type: application/json" \
283
+ -H "Authorization: Bearer <jwt_token>" \
284
+ -d '{"completed": true}'
285
+ ```
286
+
287
+ **Delete a task**:
288
+ ```bash
289
+ curl -X DELETE http://localhost:8000/api/tasks/1 \
290
+ -H "Authorization: Bearer <jwt_token>"
291
+ ```
292
+
293
+ ### Using Swagger UI
294
+
295
+ FastAPI automatically generates interactive API documentation:
296
+
297
+ 1. Start the backend server: `uvicorn main:app --reload`
298
+ 2. Open browser: `http://localhost:8000/docs`
299
+ 3. Use the interactive interface to test endpoints
300
+
301
+ ## Implementation Notes
302
+
303
+ ### Backend (FastAPI)
304
+
305
+ The OpenAPI specification in `tasks-api.yaml` should be used to:
306
+ 1. Validate implementation matches contract
307
+ 2. Generate API documentation
308
+ 3. Guide Pydantic schema creation
309
+ 4. Define route handlers
310
+
311
+ ### Frontend (Next.js)
312
+
313
+ The API contracts should be used to:
314
+ 1. Create TypeScript interfaces for API responses
315
+ 2. Implement API client functions in `lib/api.ts`
316
+ 3. Handle error responses consistently
317
+ 4. Validate request data before sending
318
+
319
+ ### Testing
320
+
321
+ The contracts should be used to:
322
+ 1. Write contract tests (verify API matches specification)
323
+ 2. Generate test fixtures
324
+ 3. Validate request/response formats
325
+ 4. Test error handling
326
+
327
+ ## Contract Validation
328
+
329
+ To validate the OpenAPI specification:
330
+
331
+ ```bash
332
+ # Install validator
333
+ npm install -g @apidevtools/swagger-cli
334
+
335
+ # Validate specification
336
+ swagger-cli validate tasks-api.yaml
337
+ ```
338
+
339
+ ## Version History
340
+
341
+ - **v1.0.0** (2026-01-08): Initial API contract for Task CRUD operations
342
+
343
+ ## References
344
+
345
+ - OpenAPI Specification: https://spec.openapis.org/oas/v3.1.0
346
+ - FastAPI OpenAPI Support: https://fastapi.tiangolo.com/tutorial/metadata/
347
+ - Pydantic Validation: https://docs.pydantic.dev/latest/
348
+
349
+ ## Next Steps
350
+
351
+ 1. Implement backend API routes following this contract
352
+ 2. Create Pydantic schemas matching request/response formats
353
+ 3. Implement frontend API client using TypeScript interfaces
354
+ 4. Write contract tests to validate implementation
355
+ 5. Generate API documentation from OpenAPI spec
specs/001-task-crud/contracts/tasks-api.yaml ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ openapi: 3.1.0
2
+ info:
3
+ title: Task CRUD API
4
+ description: REST API for managing tasks in the Phase II Todo Web Application
5
+ version: 1.0.0
6
+ contact:
7
+ name: API Support
8
+ email: support@example.com
9
+
10
+ servers:
11
+ - url: http://localhost:8000
12
+ description: Local development server
13
+ - url: https://api.example.com
14
+ description: Production server
15
+
16
+ tags:
17
+ - name: tasks
18
+ description: Task management operations
19
+
20
+ paths:
21
+ /api/tasks:
22
+ get:
23
+ tags:
24
+ - tasks
25
+ summary: List all tasks for authenticated user
26
+ description: Retrieves all tasks belonging to the authenticated user with optional filtering and sorting
27
+ operationId: listTasks
28
+ parameters:
29
+ - name: completed
30
+ in: query
31
+ description: Filter by completion status
32
+ required: false
33
+ schema:
34
+ type: boolean
35
+ example: false
36
+ - name: sort
37
+ in: query
38
+ description: Sort order (created_at_desc, created_at_asc)
39
+ required: false
40
+ schema:
41
+ type: string
42
+ enum: [created_at_desc, created_at_asc]
43
+ default: created_at_desc
44
+ - name: limit
45
+ in: query
46
+ description: Maximum number of tasks to return
47
+ required: false
48
+ schema:
49
+ type: integer
50
+ minimum: 1
51
+ maximum: 100
52
+ default: 50
53
+ - name: offset
54
+ in: query
55
+ description: Number of tasks to skip (for pagination)
56
+ required: false
57
+ schema:
58
+ type: integer
59
+ minimum: 0
60
+ default: 0
61
+ responses:
62
+ '200':
63
+ description: Successful response with task list
64
+ content:
65
+ application/json:
66
+ schema:
67
+ $ref: '#/components/schemas/TaskListResponse'
68
+ '401':
69
+ description: Unauthorized - missing or invalid JWT token
70
+ content:
71
+ application/json:
72
+ schema:
73
+ $ref: '#/components/schemas/ErrorResponse'
74
+ '500':
75
+ description: Internal server error
76
+ content:
77
+ application/json:
78
+ schema:
79
+ $ref: '#/components/schemas/ErrorResponse'
80
+ security:
81
+ - bearerAuth: []
82
+
83
+ post:
84
+ tags:
85
+ - tasks
86
+ summary: Create a new task
87
+ description: Creates a new task for the authenticated user
88
+ operationId: createTask
89
+ requestBody:
90
+ required: true
91
+ content:
92
+ application/json:
93
+ schema:
94
+ $ref: '#/components/schemas/TaskCreate'
95
+ responses:
96
+ '201':
97
+ description: Task created successfully
98
+ content:
99
+ application/json:
100
+ schema:
101
+ $ref: '#/components/schemas/TaskResponse'
102
+ '400':
103
+ description: Bad request - validation error
104
+ content:
105
+ application/json:
106
+ schema:
107
+ $ref: '#/components/schemas/ValidationErrorResponse'
108
+ '401':
109
+ description: Unauthorized - missing or invalid JWT token
110
+ content:
111
+ application/json:
112
+ schema:
113
+ $ref: '#/components/schemas/ErrorResponse'
114
+ '500':
115
+ description: Internal server error
116
+ content:
117
+ application/json:
118
+ schema:
119
+ $ref: '#/components/schemas/ErrorResponse'
120
+ security:
121
+ - bearerAuth: []
122
+
123
+ /api/tasks/{task_id}:
124
+ get:
125
+ tags:
126
+ - tasks
127
+ summary: Get a specific task
128
+ description: Retrieves a single task by ID (must belong to authenticated user)
129
+ operationId: getTask
130
+ parameters:
131
+ - name: task_id
132
+ in: path
133
+ description: Task ID
134
+ required: true
135
+ schema:
136
+ type: integer
137
+ example: 1
138
+ responses:
139
+ '200':
140
+ description: Successful response with task details
141
+ content:
142
+ application/json:
143
+ schema:
144
+ $ref: '#/components/schemas/TaskResponse'
145
+ '401':
146
+ description: Unauthorized - missing or invalid JWT token
147
+ content:
148
+ application/json:
149
+ schema:
150
+ $ref: '#/components/schemas/ErrorResponse'
151
+ '404':
152
+ description: Task not found or does not belong to user
153
+ content:
154
+ application/json:
155
+ schema:
156
+ $ref: '#/components/schemas/ErrorResponse'
157
+ '500':
158
+ description: Internal server error
159
+ content:
160
+ application/json:
161
+ schema:
162
+ $ref: '#/components/schemas/ErrorResponse'
163
+ security:
164
+ - bearerAuth: []
165
+
166
+ put:
167
+ tags:
168
+ - tasks
169
+ summary: Update a task (full replacement)
170
+ description: Updates all fields of an existing task (must belong to authenticated user)
171
+ operationId: updateTask
172
+ parameters:
173
+ - name: task_id
174
+ in: path
175
+ description: Task ID
176
+ required: true
177
+ schema:
178
+ type: integer
179
+ example: 1
180
+ requestBody:
181
+ required: true
182
+ content:
183
+ application/json:
184
+ schema:
185
+ $ref: '#/components/schemas/TaskUpdate'
186
+ responses:
187
+ '200':
188
+ description: Task updated successfully
189
+ content:
190
+ application/json:
191
+ schema:
192
+ $ref: '#/components/schemas/TaskResponse'
193
+ '400':
194
+ description: Bad request - validation error
195
+ content:
196
+ application/json:
197
+ schema:
198
+ $ref: '#/components/schemas/ValidationErrorResponse'
199
+ '401':
200
+ description: Unauthorized - missing or invalid JWT token
201
+ content:
202
+ application/json:
203
+ schema:
204
+ $ref: '#/components/schemas/ErrorResponse'
205
+ '404':
206
+ description: Task not found or does not belong to user
207
+ content:
208
+ application/json:
209
+ schema:
210
+ $ref: '#/components/schemas/ErrorResponse'
211
+ '500':
212
+ description: Internal server error
213
+ content:
214
+ application/json:
215
+ schema:
216
+ $ref: '#/components/schemas/ErrorResponse'
217
+ security:
218
+ - bearerAuth: []
219
+
220
+ patch:
221
+ tags:
222
+ - tasks
223
+ summary: Partially update a task
224
+ description: Updates specific fields of an existing task (must belong to authenticated user)
225
+ operationId: patchTask
226
+ parameters:
227
+ - name: task_id
228
+ in: path
229
+ description: Task ID
230
+ required: true
231
+ schema:
232
+ type: integer
233
+ example: 1
234
+ requestBody:
235
+ required: true
236
+ content:
237
+ application/json:
238
+ schema:
239
+ $ref: '#/components/schemas/TaskPatch'
240
+ responses:
241
+ '200':
242
+ description: Task updated successfully
243
+ content:
244
+ application/json:
245
+ schema:
246
+ $ref: '#/components/schemas/TaskResponse'
247
+ '400':
248
+ description: Bad request - validation error
249
+ content:
250
+ application/json:
251
+ schema:
252
+ $ref: '#/components/schemas/ValidationErrorResponse'
253
+ '401':
254
+ description: Unauthorized - missing or invalid JWT token
255
+ content:
256
+ application/json:
257
+ schema:
258
+ $ref: '#/components/schemas/ErrorResponse'
259
+ '404':
260
+ description: Task not found or does not belong to user
261
+ content:
262
+ application/json:
263
+ schema:
264
+ $ref: '#/components/schemas/ErrorResponse'
265
+ '500':
266
+ description: Internal server error
267
+ content:
268
+ application/json:
269
+ schema:
270
+ $ref: '#/components/schemas/ErrorResponse'
271
+ security:
272
+ - bearerAuth: []
273
+
274
+ delete:
275
+ tags:
276
+ - tasks
277
+ summary: Delete a task
278
+ description: Permanently deletes a task (must belong to authenticated user)
279
+ operationId: deleteTask
280
+ parameters:
281
+ - name: task_id
282
+ in: path
283
+ description: Task ID
284
+ required: true
285
+ schema:
286
+ type: integer
287
+ example: 1
288
+ responses:
289
+ '204':
290
+ description: Task deleted successfully (no content)
291
+ '401':
292
+ description: Unauthorized - missing or invalid JWT token
293
+ content:
294
+ application/json:
295
+ schema:
296
+ $ref: '#/components/schemas/ErrorResponse'
297
+ '404':
298
+ description: Task not found or does not belong to user
299
+ content:
300
+ application/json:
301
+ schema:
302
+ $ref: '#/components/schemas/ErrorResponse'
303
+ '500':
304
+ description: Internal server error
305
+ content:
306
+ application/json:
307
+ schema:
308
+ $ref: '#/components/schemas/ErrorResponse'
309
+ security:
310
+ - bearerAuth: []
311
+
312
+ components:
313
+ securitySchemes:
314
+ bearerAuth:
315
+ type: http
316
+ scheme: bearer
317
+ bearerFormat: JWT
318
+ description: JWT token obtained from authentication endpoint (Spec 2)
319
+
320
+ schemas:
321
+ TaskCreate:
322
+ type: object
323
+ required:
324
+ - title
325
+ properties:
326
+ title:
327
+ type: string
328
+ minLength: 1
329
+ maxLength: 200
330
+ description: Task title (1-200 characters)
331
+ example: "Buy groceries"
332
+ description:
333
+ type: string
334
+ maxLength: 1000
335
+ nullable: true
336
+ description: Optional task description (0-1000 characters)
337
+ example: "Milk, eggs, bread"
338
+
339
+ TaskUpdate:
340
+ type: object
341
+ required:
342
+ - title
343
+ - completed
344
+ properties:
345
+ title:
346
+ type: string
347
+ minLength: 1
348
+ maxLength: 200
349
+ description: Task title (1-200 characters)
350
+ example: "Buy groceries and milk"
351
+ description:
352
+ type: string
353
+ maxLength: 1000
354
+ nullable: true
355
+ description: Optional task description (0-1000 characters)
356
+ example: "Updated description"
357
+ completed:
358
+ type: boolean
359
+ description: Task completion status
360
+ example: false
361
+
362
+ TaskPatch:
363
+ type: object
364
+ properties:
365
+ title:
366
+ type: string
367
+ minLength: 1
368
+ maxLength: 200
369
+ description: Task title (1-200 characters)
370
+ example: "Buy groceries and milk"
371
+ description:
372
+ type: string
373
+ maxLength: 1000
374
+ nullable: true
375
+ description: Optional task description (0-1000 characters)
376
+ example: "Updated description"
377
+ completed:
378
+ type: boolean
379
+ description: Task completion status
380
+ example: true
381
+
382
+ TaskResponse:
383
+ type: object
384
+ required:
385
+ - id
386
+ - user_id
387
+ - title
388
+ - completed
389
+ - created_at
390
+ - updated_at
391
+ properties:
392
+ id:
393
+ type: integer
394
+ description: Unique task identifier
395
+ example: 1
396
+ user_id:
397
+ type: integer
398
+ description: ID of the user who owns this task
399
+ example: 42
400
+ title:
401
+ type: string
402
+ description: Task title
403
+ example: "Buy groceries"
404
+ description:
405
+ type: string
406
+ nullable: true
407
+ description: Task description
408
+ example: "Milk, eggs, bread"
409
+ completed:
410
+ type: boolean
411
+ description: Task completion status
412
+ example: false
413
+ created_at:
414
+ type: string
415
+ format: date-time
416
+ description: Timestamp when task was created
417
+ example: "2026-01-08T10:00:00Z"
418
+ updated_at:
419
+ type: string
420
+ format: date-time
421
+ description: Timestamp when task was last updated
422
+ example: "2026-01-08T10:00:00Z"
423
+
424
+ TaskListResponse:
425
+ type: object
426
+ required:
427
+ - tasks
428
+ - total
429
+ properties:
430
+ tasks:
431
+ type: array
432
+ items:
433
+ $ref: '#/components/schemas/TaskResponse'
434
+ description: Array of tasks
435
+ total:
436
+ type: integer
437
+ description: Total number of tasks (before pagination)
438
+ example: 1
439
+
440
+ ErrorResponse:
441
+ type: object
442
+ required:
443
+ - detail
444
+ properties:
445
+ detail:
446
+ type: string
447
+ description: Human-readable error message
448
+ example: "Task not found"
449
+ error_code:
450
+ type: string
451
+ description: Machine-readable error code
452
+ example: "TASK_NOT_FOUND"
453
+
454
+ ValidationErrorResponse:
455
+ type: object
456
+ required:
457
+ - detail
458
+ properties:
459
+ detail:
460
+ type: string
461
+ description: Human-readable error message
462
+ example: "Validation error"
463
+ error_code:
464
+ type: string
465
+ description: Machine-readable error code
466
+ example: "VALIDATION_ERROR"
467
+ field_errors:
468
+ type: object
469
+ additionalProperties:
470
+ type: array
471
+ items:
472
+ type: string
473
+ description: Field-specific validation errors
474
+ example:
475
+ title:
476
+ - "Title must be between 1 and 200 characters"
specs/001-task-crud/data-model.md ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Model: Task CRUD Operations
2
+
3
+ **Feature**: Task CRUD Operations
4
+ **Date**: 2026-01-08
5
+ **Status**: Complete
6
+
7
+ ## Overview
8
+
9
+ This document defines the database schema, entity relationships, and data validation rules for the Task CRUD feature. The data model supports multi-user task management with user data isolation.
10
+
11
+ ## Entity Relationship Diagram
12
+
13
+ ```
14
+ ┌─────────────────┐ ┌─────────────────┐
15
+ │ User │ │ Task │
16
+ ├─────────────────┤ ├─────────────────┤
17
+ │ id (PK) │◄────────│ id (PK) │
18
+ │ email │ 1:N │ user_id (FK) │
19
+ │ name │ │ title │
20
+ │ created_at │ │ description │
21
+ │ updated_at │ │ completed │
22
+ └─────────────────┘ │ created_at │
23
+ │ updated_at │
24
+ └─────────────────┘
25
+
26
+ Relationship: One User has many Tasks
27
+ One Task belongs to one User
28
+ ```
29
+
30
+ ## Entities
31
+
32
+ ### Task Entity
33
+
34
+ **Purpose**: Represents a to-do item belonging to a specific user.
35
+
36
+ **Table Name**: `tasks`
37
+
38
+ **Columns**:
39
+
40
+ | Column Name | Type | Constraints | Description |
41
+ |--------------|--------------|--------------------------------|------------------------------------------------|
42
+ | id | Integer | PRIMARY KEY, AUTO_INCREMENT | Unique task identifier |
43
+ | user_id | Integer | FOREIGN KEY (users.id), NOT NULL, INDEX | Owner of the task |
44
+ | title | String(200) | NOT NULL, LENGTH(1-200) | Task title (required) |
45
+ | description | String(1000) | NULLABLE, LENGTH(0-1000) | Optional task description |
46
+ | completed | Boolean | NOT NULL, DEFAULT FALSE, INDEX | Completion status |
47
+ | created_at | DateTime | NOT NULL, DEFAULT NOW() | Timestamp when task was created |
48
+ | updated_at | DateTime | NOT NULL, DEFAULT NOW(), ON UPDATE NOW() | Timestamp of last update |
49
+
50
+ **Indexes**:
51
+ - PRIMARY KEY on `id`
52
+ - INDEX on `user_id` (for filtering tasks by user)
53
+ - INDEX on `completed` (for filtering active/completed tasks)
54
+ - COMPOSITE INDEX on `(user_id, completed)` (for combined filtering)
55
+ - INDEX on `created_at` (for sorting by date)
56
+
57
+ **Constraints**:
58
+ - `user_id` FOREIGN KEY references `users(id)` ON DELETE CASCADE
59
+ - `title` must be between 1 and 200 characters
60
+ - `description` must be between 0 and 1000 characters (NULL allowed)
61
+ - `completed` must be boolean (true/false)
62
+
63
+ **SQLModel Definition**:
64
+
65
+ ```python
66
+ from sqlmodel import SQLModel, Field, Relationship
67
+ from datetime import datetime
68
+ from typing import Optional
69
+
70
+ class Task(SQLModel, table=True):
71
+ """Task entity representing a to-do item."""
72
+
73
+ __tablename__ = "tasks"
74
+
75
+ id: Optional[int] = Field(default=None, primary_key=True)
76
+ user_id: int = Field(foreign_key="users.id", nullable=False, index=True)
77
+ title: str = Field(max_length=200, nullable=False)
78
+ description: Optional[str] = Field(default=None, max_length=1000)
79
+ completed: bool = Field(default=False, nullable=False, index=True)
80
+ created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
81
+ updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
82
+
83
+ # Relationship (will be fully implemented in Spec 2)
84
+ # user: Optional["User"] = Relationship(back_populates="tasks")
85
+
86
+ class Config:
87
+ json_schema_extra = {
88
+ "example": {
89
+ "id": 1,
90
+ "user_id": 42,
91
+ "title": "Buy groceries",
92
+ "description": "Milk, eggs, bread",
93
+ "completed": False,
94
+ "created_at": "2026-01-08T10:00:00Z",
95
+ "updated_at": "2026-01-08T10:00:00Z"
96
+ }
97
+ }
98
+ ```
99
+
100
+ ### User Entity (Stub)
101
+
102
+ **Purpose**: Represents an authenticated user (full implementation in Spec 2).
103
+
104
+ **Table Name**: `users`
105
+
106
+ **Columns** (minimal for Spec 1):
107
+
108
+ | Column Name | Type | Constraints | Description |
109
+ |--------------|--------------|--------------------------------|------------------------------------------------|
110
+ | id | Integer | PRIMARY KEY, AUTO_INCREMENT | Unique user identifier |
111
+ | email | String(255) | UNIQUE, NOT NULL | User email address |
112
+ | name | String(100) | NOT NULL | User display name |
113
+ | created_at | DateTime | NOT NULL, DEFAULT NOW() | Timestamp when user was created |
114
+ | updated_at | DateTime | NOT NULL, DEFAULT NOW() | Timestamp of last update |
115
+
116
+ **SQLModel Definition** (stub for Spec 1):
117
+
118
+ ```python
119
+ from sqlmodel import SQLModel, Field
120
+ from datetime import datetime
121
+ from typing import Optional
122
+
123
+ class User(SQLModel, table=True):
124
+ """User entity (stub for authentication spec)."""
125
+
126
+ __tablename__ = "users"
127
+
128
+ id: Optional[int] = Field(default=None, primary_key=True)
129
+ email: str = Field(max_length=255, unique=True, nullable=False)
130
+ name: str = Field(max_length=100, nullable=False)
131
+ created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
132
+ updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
133
+
134
+ # Relationship (will be fully implemented in Spec 2)
135
+ # tasks: List["Task"] = Relationship(back_populates="user")
136
+ ```
137
+
138
+ ## Pydantic Schemas (Request/Response)
139
+
140
+ ### TaskCreate (Request)
141
+
142
+ **Purpose**: Validate task creation requests.
143
+
144
+ ```python
145
+ from pydantic import BaseModel, Field
146
+ from typing import Optional
147
+
148
+ class TaskCreate(BaseModel):
149
+ """Schema for creating a new task."""
150
+
151
+ title: str = Field(
152
+ min_length=1,
153
+ max_length=200,
154
+ description="Task title (1-200 characters)"
155
+ )
156
+ description: Optional[str] = Field(
157
+ default=None,
158
+ max_length=1000,
159
+ description="Optional task description (0-1000 characters)"
160
+ )
161
+
162
+ class Config:
163
+ json_schema_extra = {
164
+ "example": {
165
+ "title": "Buy groceries",
166
+ "description": "Milk, eggs, bread"
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### TaskUpdate (Request)
172
+
173
+ **Purpose**: Validate task update requests (full replacement).
174
+
175
+ ```python
176
+ class TaskUpdate(BaseModel):
177
+ """Schema for updating an existing task."""
178
+
179
+ title: str = Field(
180
+ min_length=1,
181
+ max_length=200,
182
+ description="Task title (1-200 characters)"
183
+ )
184
+ description: Optional[str] = Field(
185
+ default=None,
186
+ max_length=1000,
187
+ description="Optional task description (0-1000 characters)"
188
+ )
189
+ completed: bool = Field(
190
+ description="Task completion status"
191
+ )
192
+
193
+ class Config:
194
+ json_schema_extra = {
195
+ "example": {
196
+ "title": "Buy groceries and milk",
197
+ "description": "Updated description",
198
+ "completed": False
199
+ }
200
+ }
201
+ ```
202
+
203
+ ### TaskPatch (Request)
204
+
205
+ **Purpose**: Validate partial task updates (e.g., toggle completion).
206
+
207
+ ```python
208
+ class TaskPatch(BaseModel):
209
+ """Schema for partially updating a task."""
210
+
211
+ title: Optional[str] = Field(
212
+ default=None,
213
+ min_length=1,
214
+ max_length=200,
215
+ description="Task title (1-200 characters)"
216
+ )
217
+ description: Optional[str] = Field(
218
+ default=None,
219
+ max_length=1000,
220
+ description="Optional task description (0-1000 characters)"
221
+ )
222
+ completed: Optional[bool] = Field(
223
+ default=None,
224
+ description="Task completion status"
225
+ )
226
+
227
+ class Config:
228
+ json_schema_extra = {
229
+ "example": {
230
+ "completed": True
231
+ }
232
+ }
233
+ ```
234
+
235
+ ### TaskResponse (Response)
236
+
237
+ **Purpose**: Standardized task response format.
238
+
239
+ ```python
240
+ from datetime import datetime
241
+
242
+ class TaskResponse(BaseModel):
243
+ """Schema for task responses."""
244
+
245
+ id: int
246
+ user_id: int
247
+ title: str
248
+ description: Optional[str]
249
+ completed: bool
250
+ created_at: datetime
251
+ updated_at: datetime
252
+
253
+ class Config:
254
+ from_attributes = True # Enable ORM mode
255
+ json_schema_extra = {
256
+ "example": {
257
+ "id": 1,
258
+ "user_id": 42,
259
+ "title": "Buy groceries",
260
+ "description": "Milk, eggs, bread",
261
+ "completed": False,
262
+ "created_at": "2026-01-08T10:00:00Z",
263
+ "updated_at": "2026-01-08T10:00:00Z"
264
+ }
265
+ }
266
+ ```
267
+
268
+ ### TaskListResponse (Response)
269
+
270
+ **Purpose**: Response format for listing multiple tasks.
271
+
272
+ ```python
273
+ from typing import List
274
+
275
+ class TaskListResponse(BaseModel):
276
+ """Schema for task list responses."""
277
+
278
+ tasks: List[TaskResponse]
279
+ total: int
280
+
281
+ class Config:
282
+ json_schema_extra = {
283
+ "example": {
284
+ "tasks": [
285
+ {
286
+ "id": 1,
287
+ "user_id": 42,
288
+ "title": "Buy groceries",
289
+ "description": "Milk, eggs, bread",
290
+ "completed": False,
291
+ "created_at": "2026-01-08T10:00:00Z",
292
+ "updated_at": "2026-01-08T10:00:00Z"
293
+ }
294
+ ],
295
+ "total": 1
296
+ }
297
+ }
298
+ ```
299
+
300
+ ## Data Validation Rules
301
+
302
+ ### Title Validation
303
+ - **Required**: Yes
304
+ - **Min Length**: 1 character
305
+ - **Max Length**: 200 characters
306
+ - **Allowed Characters**: Any Unicode characters
307
+ - **Trimming**: Leading/trailing whitespace should be trimmed
308
+ - **Error Message**: "Title must be between 1 and 200 characters"
309
+
310
+ ### Description Validation
311
+ - **Required**: No (optional)
312
+ - **Min Length**: 0 characters (empty string or NULL)
313
+ - **Max Length**: 1000 characters
314
+ - **Allowed Characters**: Any Unicode characters
315
+ - **Trimming**: Leading/trailing whitespace should be trimmed
316
+ - **Error Message**: "Description must be 1000 characters or less"
317
+
318
+ ### Completed Validation
319
+ - **Required**: Yes (defaults to False on creation)
320
+ - **Type**: Boolean (true/false)
321
+ - **Error Message**: "Completed must be a boolean value"
322
+
323
+ ### User ID Validation
324
+ - **Required**: Yes
325
+ - **Type**: Integer
326
+ - **Validation**: Must reference existing user in users table
327
+ - **Error Message**: "Invalid user ID"
328
+
329
+ ## State Transitions
330
+
331
+ ### Task Lifecycle
332
+
333
+ ```
334
+ ┌────────────┐
335
+ │ Created │ (completed = false)
336
+ │ (Initial) │
337
+ └──────┬──────┘
338
+
339
+ │ User marks complete
340
+
341
+ ┌─────────────┐
342
+ │ Completed │ (completed = true)
343
+ └──────┬──────┘
344
+
345
+ │ User marks incomplete
346
+
347
+ ┌─────────────┐
348
+ │ Active │ (completed = false)
349
+ └──────┬──────┘
350
+
351
+ │ User deletes
352
+
353
+ ┌─────────────┐
354
+ │ Deleted │ (removed from database)
355
+ └─────────────┘
356
+ ```
357
+
358
+ **Valid Transitions**:
359
+ - Created → Completed (mark as done)
360
+ - Completed → Active (mark as not done)
361
+ - Any state → Deleted (remove task)
362
+ - Active → Updated (edit title/description)
363
+ - Completed → Updated (edit title/description)
364
+
365
+ ## Database Migration
366
+
367
+ ### Initial Migration (Alembic)
368
+
369
+ ```python
370
+ """Create tasks table
371
+
372
+ Revision ID: 001_create_tasks
373
+ Revises:
374
+ Create Date: 2026-01-08
375
+
376
+ """
377
+ from alembic import op
378
+ import sqlalchemy as sa
379
+ from sqlalchemy.dialects import postgresql
380
+
381
+ # revision identifiers
382
+ revision = '001_create_tasks'
383
+ down_revision = None
384
+ branch_labels = None
385
+ depends_on = None
386
+
387
+ def upgrade():
388
+ # Create users table (stub for Spec 2)
389
+ op.create_table(
390
+ 'users',
391
+ sa.Column('id', sa.Integer(), nullable=False),
392
+ sa.Column('email', sa.String(length=255), nullable=False),
393
+ sa.Column('name', sa.String(length=100), nullable=False),
394
+ sa.Column('created_at', sa.DateTime(), nullable=False),
395
+ sa.Column('updated_at', sa.DateTime(), nullable=False),
396
+ sa.PrimaryKeyConstraint('id'),
397
+ sa.UniqueConstraint('email')
398
+ )
399
+
400
+ # Create tasks table
401
+ op.create_table(
402
+ 'tasks',
403
+ sa.Column('id', sa.Integer(), nullable=False),
404
+ sa.Column('user_id', sa.Integer(), nullable=False),
405
+ sa.Column('title', sa.String(length=200), nullable=False),
406
+ sa.Column('description', sa.String(length=1000), nullable=True),
407
+ sa.Column('completed', sa.Boolean(), nullable=False, server_default='false'),
408
+ sa.Column('created_at', sa.DateTime(), nullable=False),
409
+ sa.Column('updated_at', sa.DateTime(), nullable=False),
410
+ sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
411
+ sa.PrimaryKeyConstraint('id')
412
+ )
413
+
414
+ # Create indexes
415
+ op.create_index('ix_tasks_user_id', 'tasks', ['user_id'])
416
+ op.create_index('ix_tasks_completed', 'tasks', ['completed'])
417
+ op.create_index('ix_tasks_user_id_completed', 'tasks', ['user_id', 'completed'])
418
+ op.create_index('ix_tasks_created_at', 'tasks', ['created_at'])
419
+
420
+ def downgrade():
421
+ op.drop_index('ix_tasks_created_at', table_name='tasks')
422
+ op.drop_index('ix_tasks_user_id_completed', table_name='tasks')
423
+ op.drop_index('ix_tasks_completed', table_name='tasks')
424
+ op.drop_index('ix_tasks_user_id', table_name='tasks')
425
+ op.drop_table('tasks')
426
+ op.drop_table('users')
427
+ ```
428
+
429
+ ## Data Integrity Rules
430
+
431
+ ### Foreign Key Constraints
432
+ - `tasks.user_id` MUST reference valid `users.id`
433
+ - ON DELETE CASCADE: Deleting a user deletes all their tasks
434
+ - Prevents orphaned tasks in database
435
+
436
+ ### Uniqueness Constraints
437
+ - No uniqueness constraint on task titles (users can have duplicate titles)
438
+ - `users.email` must be unique (enforced in users table)
439
+
440
+ ### NOT NULL Constraints
441
+ - `tasks.id`: Always required (auto-generated)
442
+ - `tasks.user_id`: Always required (task must belong to user)
443
+ - `tasks.title`: Always required (empty tasks not allowed)
444
+ - `tasks.completed`: Always required (defaults to false)
445
+ - `tasks.created_at`: Always required (auto-generated)
446
+ - `tasks.updated_at`: Always required (auto-updated)
447
+
448
+ ### Check Constraints (Optional)
449
+ ```sql
450
+ -- Ensure title is not empty after trimming
451
+ ALTER TABLE tasks ADD CONSTRAINT check_title_not_empty
452
+ CHECK (LENGTH(TRIM(title)) > 0);
453
+
454
+ -- Ensure description length if provided
455
+ ALTER TABLE tasks ADD CONSTRAINT check_description_length
456
+ CHECK (description IS NULL OR LENGTH(description) <= 1000);
457
+ ```
458
+
459
+ ## Query Patterns
460
+
461
+ ### Common Queries
462
+
463
+ **Get all tasks for a user**:
464
+ ```sql
465
+ SELECT * FROM tasks
466
+ WHERE user_id = ?
467
+ ORDER BY created_at DESC;
468
+ ```
469
+
470
+ **Get active tasks for a user**:
471
+ ```sql
472
+ SELECT * FROM tasks
473
+ WHERE user_id = ? AND completed = false
474
+ ORDER BY created_at DESC;
475
+ ```
476
+
477
+ **Get completed tasks for a user**:
478
+ ```sql
479
+ SELECT * FROM tasks
480
+ WHERE user_id = ? AND completed = true
481
+ ORDER BY created_at DESC;
482
+ ```
483
+
484
+ **Get specific task with ownership check**:
485
+ ```sql
486
+ SELECT * FROM tasks
487
+ WHERE id = ? AND user_id = ?;
488
+ ```
489
+
490
+ **Update task with timestamp**:
491
+ ```sql
492
+ UPDATE tasks
493
+ SET title = ?, description = ?, completed = ?, updated_at = NOW()
494
+ WHERE id = ? AND user_id = ?;
495
+ ```
496
+
497
+ **Delete task with ownership check**:
498
+ ```sql
499
+ DELETE FROM tasks
500
+ WHERE id = ? AND user_id = ?;
501
+ ```
502
+
503
+ ## Performance Considerations
504
+
505
+ ### Index Usage
506
+ - `user_id` index: Used in all queries (data isolation)
507
+ - `completed` index: Used for filtering active/completed
508
+ - Composite `(user_id, completed)` index: Optimizes filtered queries
509
+ - `created_at` index: Used for sorting by date
510
+
511
+ ### Query Optimization
512
+ - Always include `user_id` in WHERE clause (uses index)
513
+ - Limit result sets for large task lists (pagination)
514
+ - Use `SELECT *` sparingly in production (specify columns)
515
+ - Avoid N+1 queries (use joins if fetching related data)
516
+
517
+ ### Connection Pooling
518
+ - Use Neon's built-in connection pooling
519
+ - Configure pool size based on expected concurrent users
520
+ - Reuse database sessions across requests
521
+
522
+ ## Data Seeding (Development)
523
+
524
+ ### Sample Data for Testing
525
+
526
+ ```python
527
+ # Sample users
528
+ users = [
529
+ {"id": 1, "email": "alice@example.com", "name": "Alice"},
530
+ {"id": 2, "email": "bob@example.com", "name": "Bob"}
531
+ ]
532
+
533
+ # Sample tasks
534
+ tasks = [
535
+ {
536
+ "user_id": 1,
537
+ "title": "Buy groceries",
538
+ "description": "Milk, eggs, bread",
539
+ "completed": False
540
+ },
541
+ {
542
+ "user_id": 1,
543
+ "title": "Finish project report",
544
+ "description": None,
545
+ "completed": True
546
+ },
547
+ {
548
+ "user_id": 2,
549
+ "title": "Call dentist",
550
+ "description": "Schedule appointment",
551
+ "completed": False
552
+ }
553
+ ]
554
+ ```
555
+
556
+ ## Summary
557
+
558
+ The data model defines two entities: Task (full implementation) and User (stub for Spec 2). Tasks have a many-to-one relationship with Users, enforced via foreign key constraint. Validation rules ensure data integrity at both API and database layers. Indexes optimize query performance for filtering and sorting. The schema supports all functional requirements from the specification while maintaining user data isolation.
559
+
560
+ **Ready for**: API contract generation (contracts/).
specs/001-task-crud/plan.md ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Plan: Task CRUD Operations
2
+
3
+ **Branch**: `001-task-crud` | **Date**: 2026-01-08 | **Spec**: [spec.md](./spec.md)
4
+ **Input**: Feature specification from `/specs/001-task-crud/spec.md`
5
+
6
+ **Note**: This template is filled in by the `/sp.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
7
+
8
+ ## Summary
9
+
10
+ Implement core task management functionality enabling authenticated users to create, view, update, delete, and mark tasks as complete. The feature provides full CRUD operations with user data isolation, responsive UI, and REST API backend. Tasks include title (1-200 chars), description (0-1000 chars), completion status, and timestamps. Implementation follows a three-layer architecture: Neon PostgreSQL database with SQLModel ORM, FastAPI REST API with Pydantic validation, and Next.js 16+ frontend with Tailwind CSS. Authentication integration deferred to Spec 2.
11
+
12
+ ## Technical Context
13
+
14
+ **Language/Version**: Python 3.11+ (backend), TypeScript 5.x (frontend), Node.js 18+ (frontend runtime)
15
+ **Primary Dependencies**: FastAPI 0.104+, SQLModel 0.0.14+, Pydantic 2.x, Next.js 16+, React 18+, Tailwind CSS 3.x
16
+ **Storage**: Neon Serverless PostgreSQL (cloud-hosted, connection pooling enabled)
17
+ **Testing**: pytest (backend unit/integration), Jest + React Testing Library (frontend), Playwright (E2E - optional)
18
+ **Target Platform**: Web application (Linux/Windows server for backend, modern browsers for frontend)
19
+ **Project Type**: Web application (monorepo with separate frontend/ and backend/ directories)
20
+ **Performance Goals**: Task list load <2s, task creation <10s, updates <1s, completion toggle <500ms, 100 concurrent users
21
+ **Constraints**: Stateless API design (JWT-based), responsive design (mobile/tablet/desktop), user data isolation (100%), 95% operation success rate
22
+ **Scale/Scope**: Initial target 100 concurrent users, 4 user stories (P1-P4), 15 functional requirements, 6 REST endpoints, 3 main frontend components
23
+
24
+ ## Constitution Check
25
+
26
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
27
+
28
+ ### ✅ I. User-Centric Functionality
29
+ - **Status**: PASS
30
+ - **Validation**: All 4 user stories directly serve end-users with clear task management value. Security enforced through user data isolation (FR-007). UX prioritized with responsive design (FR-015) and error handling (FR-014).
31
+
32
+ ### ✅ II. Spec-Driven Development
33
+ - **Status**: PASS
34
+ - **Validation**: Implementation references `/specs/001-task-crud/spec.md`. All code generation via Claude Code. No manual coding permitted. Plan, data model, and contracts will be generated before implementation.
35
+
36
+ ### ✅ III. Security & Data Privacy
37
+ - **Status**: PASS (with noted dependency)
38
+ - **Validation**: User data isolation enforced (FR-007). JWT authentication required (noted in Technical Constraints). User ID filtering on all queries.
39
+ - **Note**: JWT verification middleware implementation deferred to Spec 2 (authentication feature). Current spec assumes JWT token available and user ID extractable.
40
+
41
+ ### ✅ IV. Scalable Architecture
42
+ - **Status**: PASS
43
+ - **Validation**: Stateless API design (JWT-based, no server sessions). Database indexes planned for user_id and completed fields. Frontend components designed as reusable (Task List, Task Form, Task Item). Clear client/server separation (Next.js App Router with server/client components).
44
+
45
+ ### ✅ V. Maintainable & Consistent Code
46
+ - **Status**: PASS
47
+ - **Validation**: Standardized patterns: FastAPI + SQLModel (backend), Next.js 16+ App Router + Tailwind CSS (frontend). Modular architecture with clear layer boundaries (database/API/UI). Consistent naming conventions planned.
48
+
49
+ ### ✅ API Compliance Standard
50
+ - **Status**: PASS
51
+ - **Validation**: REST endpoints follow spec. JSON request/response format. Pydantic validation for inputs. Standardized error responses with HTTP status codes. Contracts to be documented in `/specs/001-task-crud/contracts/`.
52
+
53
+ ### ✅ Database Integrity Standard
54
+ - **Status**: PASS
55
+ - **Validation**: Neon PostgreSQL with SQLModel ORM. Foreign key relationship (Task belongs to User). Indexes for filtering. Timestamps auto-managed. Migrations to be tracked.
56
+
57
+ ### ✅ Frontend Quality Standard
58
+ - **Status**: PASS
59
+ - **Validation**: Next.js 16+ App Router patterns. Server components by default, client components for interactivity. Responsive design (mobile/tablet/desktop). Tailwind CSS for all styling.
60
+
61
+ ### ⚠️ Authentication Standard
62
+ - **Status**: DEFERRED
63
+ - **Validation**: Better Auth integration and JWT verification deferred to Spec 2. Current implementation assumes JWT token available in requests.
64
+ - **Mitigation**: Endpoints designed with JWT authorization in mind. User ID parameter in API routes prepared for token extraction.
65
+
66
+ ### ✅ Spec Adherence Standard
67
+ - **Status**: PASS
68
+ - **Validation**: All implementation references `@specs/001-task-crud/`. Plan, data model, contracts, and tasks will be generated before code. No implementation without spec.
69
+
70
+ ### Constitution Check Summary
71
+
72
+ **Overall Status**: ✅ PASS (1 deferred dependency noted)
73
+
74
+ **Violations**: None
75
+
76
+ **Deferred Items**:
77
+ - JWT authentication implementation (Spec 2 dependency - explicitly documented in spec.md Out of Scope section)
78
+
79
+ **Justification**: Authentication deferral is intentional and documented. Task CRUD feature can be implemented with placeholder user_id parameter, then integrated with JWT middleware in Spec 2.
80
+
81
+ ## Project Structure
82
+
83
+ ### Documentation (this feature)
84
+
85
+ ```text
86
+ specs/001-task-crud/
87
+ ├── spec.md # Feature specification (completed)
88
+ ├── plan.md # This file (/sp.plan command output)
89
+ ├── research.md # Phase 0 output (technology decisions)
90
+ ├── data-model.md # Phase 1 output (database schema)
91
+ ├── quickstart.md # Phase 1 output (setup instructions)
92
+ ├── contracts/ # Phase 1 output (API contracts)
93
+ │ ├── tasks-api.yaml # OpenAPI specification for task endpoints
94
+ │ └── README.md # Contract documentation
95
+ ├── checklists/ # Quality validation
96
+ │ └── requirements.md # Spec quality checklist (completed)
97
+ └── tasks.md # Phase 2 output (/sp.tasks command - NOT created by /sp.plan)
98
+ ```
99
+
100
+ ### Source Code (repository root)
101
+
102
+ ```text
103
+ backend/
104
+ ├── src/
105
+ │ ├── models/
106
+ │ │ ├── __init__.py
107
+ │ │ ├── task.py # Task SQLModel definition
108
+ │ │ └── user.py # User model (stub for Spec 2)
109
+ │ ├── schemas/
110
+ │ │ ├── __init__.py
111
+ │ │ └── task.py # Pydantic request/response schemas
112
+ │ ├── api/
113
+ │ │ ├── __init__.py
114
+ │ │ ├── deps.py # Dependencies (DB session, auth stub)
115
+ │ │ └── routes/
116
+ │ │ ├── __init__.py
117
+ │ │ └── tasks.py # Task CRUD endpoints
118
+ │ ├── services/
119
+ │ │ ├── __init__.py
120
+ │ │ └── task_service.py # Business logic layer
121
+ │ ├── core/
122
+ │ │ ├── __init__.py
123
+ │ │ ├── config.py # Settings (database URL, etc.)
124
+ │ │ └── database.py # Database connection setup
125
+ │ └── main.py # FastAPI application entry point
126
+ ├── tests/
127
+ │ ├── __init__.py
128
+ │ ├── conftest.py # Pytest fixtures
129
+ │ ├── test_task_api.py # API endpoint tests
130
+ │ └── test_task_service.py # Service layer tests
131
+ ├── alembic/ # Database migrations
132
+ │ ├── versions/
133
+ │ └── env.py
134
+ ├── requirements.txt # Python dependencies
135
+ ├── .env.example # Environment variables template
136
+ └── README.md # Backend setup instructions
137
+
138
+ frontend/
139
+ ├── src/
140
+ │ ├── app/
141
+ │ │ ├── layout.tsx # Root layout
142
+ │ │ ├── page.tsx # Home page (task list)
143
+ │ │ └── tasks/
144
+ │ │ └── [id]/
145
+ │ │ └── page.tsx # Task detail page (optional)
146
+ │ ├── components/
147
+ │ │ ├── tasks/
148
+ │ │ │ ├── TaskList.tsx # Server component - displays tasks
149
+ │ │ │ ├── TaskItem.tsx # Client component - interactive task
150
+ │ │ │ ├── TaskForm.tsx # Client component - create/edit form
151
+ │ │ │ └── TaskFilters.tsx # Client component - filter/sort controls
152
+ │ │ └── ui/
153
+ │ │ ├── Button.tsx # Reusable button component
154
+ │ │ ├── Input.tsx # Reusable input component
155
+ │ │ └── Checkbox.tsx # Reusable checkbox component
156
+ │ ├── lib/
157
+ │ │ ├── api.ts # API client functions
158
+ │ │ ├── types.ts # TypeScript type definitions
159
+ │ │ └── utils.ts # Utility functions
160
+ │ └── styles/
161
+ │ └── globals.css # Global styles (Tailwind imports)
162
+ ├── public/
163
+ │ └── assets/ # Static assets
164
+ ├── tests/
165
+ │ └── components/ # Component tests
166
+ ├── package.json # Node dependencies
167
+ ├── tsconfig.json # TypeScript configuration
168
+ ├── tailwind.config.ts # Tailwind CSS configuration
169
+ ├── next.config.js # Next.js configuration
170
+ ├── .env.local.example # Environment variables template
171
+ └── README.md # Frontend setup instructions
172
+ ```
173
+
174
+ **Structure Decision**: Web application monorepo structure selected based on:
175
+ - Feature requires both frontend UI and backend API
176
+ - Next.js 16+ App Router for frontend (server/client component separation)
177
+ - FastAPI for backend REST API
178
+ - Clear separation of concerns: database models, API routes, business logic, UI components
179
+ - Modular organization enables independent development and testing of layers
180
+ - Aligns with constitution's Maintainable & Consistent Code principle
181
+
182
+ ## Complexity Tracking
183
+
184
+ > **Fill ONLY if Constitution Check has violations that must be justified**
185
+
186
+ No violations detected. Complexity tracking not required.
187
+
188
+ ---
189
+
190
+ ## Phase 0: Research & Technology Decisions
191
+
192
+ **Status**: ✅ Complete
193
+
194
+ **Objective**: Resolve all technical unknowns and establish architectural patterns.
195
+
196
+ **Output**: [research.md](./research.md)
197
+
198
+ ### Key Decisions Made
199
+
200
+ 1. **Backend Framework**: FastAPI 0.104+ with SQLModel ORM
201
+ - Rationale: Automatic OpenAPI docs, async support, Pydantic v2 integration
202
+ - Alternatives considered: Django REST Framework, Flask
203
+
204
+ 2. **Database**: Neon Serverless PostgreSQL
205
+ - Rationale: Serverless scaling, built-in connection pooling, ACID compliance
206
+ - Alternatives considered: Traditional PostgreSQL, MySQL, MongoDB
207
+
208
+ 3. **Frontend Framework**: Next.js 16+ (App Router) with TypeScript and Tailwind CSS
209
+ - Rationale: Server/client component separation, built-in optimization, type safety
210
+ - Alternatives considered: Next.js Pages Router, Create React App, Vue.js
211
+
212
+ 4. **Architecture Pattern**: Three-layer architecture (Database → API → UI)
213
+ - Clear separation of concerns enables independent testing and development
214
+ - Service layer encapsulates business logic
215
+
216
+ 5. **RESTful API Design**: Resource-based URLs with standard HTTP methods
217
+ - GET /api/tasks, POST /api/tasks, PUT /api/tasks/{id}, etc.
218
+ - Aligns with API Compliance standard
219
+
220
+ 6. **Data Validation**: Multi-layer validation (Pydantic → SQLModel → Frontend)
221
+ - Defense in depth prevents bad data at multiple levels
222
+
223
+ 7. **User Data Isolation**: Filter all queries by authenticated user ID
224
+ - Enforces 100% data isolation success criterion
225
+
226
+ 8. **Performance Optimization**: Database indexing + Server Components
227
+ - Indexes on user_id, completed, created_at
228
+ - Server Components reduce JavaScript bundle size
229
+
230
+ 9. **Error Handling**: Consistent error response format across all layers
231
+ - Standard HTTP status codes (200, 201, 400, 401, 404, 500)
232
+
233
+ 10. **Testing Strategy**: Unit tests (services) + Integration tests (API) + Component tests (UI)
234
+
235
+ ### Dependencies and Versions
236
+
237
+ **Backend (Python 3.11+)**:
238
+ - fastapi==0.104.1
239
+ - sqlmodel==0.0.14
240
+ - pydantic==2.5.0
241
+ - uvicorn[standard]==0.24.0
242
+ - alembic==1.13.0
243
+ - psycopg2-binary==2.9.9
244
+
245
+ **Frontend (Node.js 18+)**:
246
+ - next: ^16.0.0
247
+ - react: ^18.2.0
248
+ - typescript: ^5.3.0
249
+ - tailwindcss: ^3.4.0
250
+
251
+ ### Deferred to Spec 2
252
+
253
+ - JWT token generation and validation
254
+ - Better Auth integration
255
+ - User registration and login flows
256
+ - Token refresh mechanism
257
+
258
+ ---
259
+
260
+ ## Phase 1: Design & Contracts
261
+
262
+ **Status**: ✅ Complete
263
+
264
+ **Objective**: Define data model, API contracts, and setup instructions.
265
+
266
+ **Outputs**:
267
+ - [data-model.md](./data-model.md) - Database schema and entity definitions
268
+ - [contracts/tasks-api.yaml](./contracts/tasks-api.yaml) - OpenAPI 3.1.0 specification
269
+ - [contracts/README.md](./contracts/README.md) - API contract documentation
270
+ - [quickstart.md](./quickstart.md) - Setup and development guide
271
+
272
+ ### Data Model Summary
273
+
274
+ **Task Entity**:
275
+ - Table: `tasks`
276
+ - Columns: id, user_id (FK), title, description, completed, created_at, updated_at
277
+ - Indexes: user_id, completed, (user_id, completed), created_at
278
+ - Constraints: Foreign key to users.id, title length 1-200, description length 0-1000
279
+
280
+ **User Entity** (stub for Spec 2):
281
+ - Table: `users`
282
+ - Columns: id, email, name, created_at, updated_at
283
+ - Minimal implementation for Task foreign key relationship
284
+
285
+ **Pydantic Schemas**:
286
+ - TaskCreate: Request schema for creating tasks
287
+ - TaskUpdate: Request schema for full task updates
288
+ - TaskPatch: Request schema for partial updates
289
+ - TaskResponse: Response schema for single task
290
+ - TaskListResponse: Response schema for task lists
291
+
292
+ **Validation Rules**:
293
+ - Title: Required, 1-200 characters
294
+ - Description: Optional, 0-1000 characters
295
+ - Completed: Boolean, defaults to false
296
+
297
+ ### API Contracts Summary
298
+
299
+ **6 REST Endpoints**:
300
+ 1. GET /api/tasks - List tasks (with filtering and sorting)
301
+ 2. POST /api/tasks - Create task
302
+ 3. GET /api/tasks/{task_id} - Get specific task
303
+ 4. PUT /api/tasks/{task_id} - Update task (full replacement)
304
+ 5. PATCH /api/tasks/{task_id} - Partial update (e.g., toggle completion)
305
+ 6. DELETE /api/tasks/{task_id} - Delete task
306
+
307
+ **Authentication**: All endpoints require JWT Bearer token (Spec 2)
308
+
309
+ **Query Parameters**:
310
+ - completed (boolean): Filter by completion status
311
+ - sort (string): Sort order (created_at_desc, created_at_asc)
312
+ - limit (integer): Pagination limit (default 50, max 100)
313
+ - offset (integer): Pagination offset (default 0)
314
+
315
+ **Error Responses**:
316
+ - 400: Validation error with field-specific messages
317
+ - 401: Unauthorized (missing/invalid JWT)
318
+ - 404: Task not found or doesn't belong to user
319
+ - 500: Internal server error
320
+
321
+ ### Quickstart Guide Summary
322
+
323
+ **Backend Setup**:
324
+ 1. Create Python virtual environment
325
+ 2. Install dependencies (requirements.txt)
326
+ 3. Configure .env with DATABASE_URL
327
+ 4. Run Alembic migrations
328
+ 5. Start uvicorn server on port 8000
329
+
330
+ **Frontend Setup**:
331
+ 1. Install Node dependencies (npm install)
332
+ 2. Configure .env.local with NEXT_PUBLIC_API_URL
333
+ 3. Configure Tailwind CSS
334
+ 4. Start Next.js dev server on port 3000
335
+
336
+ **Development Workflow**:
337
+ - Run backend and frontend concurrently in separate terminals
338
+ - Backend auto-reloads on file changes
339
+ - Frontend hot-reloads on file changes
340
+ - Use Swagger UI at http://localhost:8000/docs for API testing
341
+
342
+ ---
343
+
344
+ ## Phase 2: Task Generation
345
+
346
+ **Status**: ⏳ Pending
347
+
348
+ **Objective**: Generate actionable task list organized by user story.
349
+
350
+ **Command**: `/sp.tasks` (to be run after this plan is complete)
351
+
352
+ **Expected Output**: [tasks.md](./tasks.md)
353
+
354
+ **Task Organization**:
355
+ - Phase 1: Setup (project initialization)
356
+ - Phase 2: Foundational (database, core infrastructure)
357
+ - Phase 3: User Story 1 - View and Create Tasks (P1 - MVP)
358
+ - Phase 4: User Story 2 - Update and Complete Tasks (P2)
359
+ - Phase 5: User Story 3 - Delete Tasks (P3)
360
+ - Phase 6: User Story 4 - Filter and Sort Tasks (P4)
361
+ - Phase N: Polish & Cross-Cutting Concerns
362
+
363
+ **Task Format**: `[ID] [P?] [Story] Description`
364
+ - [P] indicates tasks that can run in parallel
365
+ - [Story] indicates which user story the task belongs to (US1, US2, US3, US4)
366
+
367
+ ---
368
+
369
+ ## Implementation Readiness
370
+
371
+ ### Pre-Implementation Checklist
372
+
373
+ - [x] Feature specification complete (spec.md)
374
+ - [x] Constitution check passed
375
+ - [x] Technical context defined
376
+ - [x] Research complete (technology decisions made)
377
+ - [x] Data model designed (database schema)
378
+ - [x] API contracts defined (OpenAPI specification)
379
+ - [x] Quickstart guide created (setup instructions)
380
+ - [ ] Task list generated (run `/sp.tasks`)
381
+ - [ ] Implementation executed (run `/sp.implement`)
382
+
383
+ ### Architecture Decision Records (ADRs)
384
+
385
+ **Significant Decisions Requiring ADR Documentation**:
386
+
387
+ 1. **Three-Layer Architecture** (Database → API → UI)
388
+ - Impact: Long-term maintainability and testability
389
+ - Alternatives: Monolithic architecture, microservices
390
+ - Scope: Cross-cutting, influences all development
391
+
392
+ 2. **Next.js App Router vs Pages Router**
393
+ - Impact: Frontend performance and development patterns
394
+ - Alternatives: Pages Router, other frameworks
395
+ - Scope: All frontend development
396
+
397
+ 3. **SQLModel vs Pure SQLAlchemy**
398
+ - Impact: Backend code structure and type safety
399
+ - Alternatives: Pure SQLAlchemy, Django ORM
400
+ - Scope: All database interactions
401
+
402
+ **Recommendation**: Run `/sp.adr` after implementation to document these decisions.
403
+
404
+ ---
405
+
406
+ ## Risk Analysis
407
+
408
+ ### Technical Risks
409
+
410
+ | Risk | Likelihood | Impact | Mitigation |
411
+ |------|------------|--------|------------|
412
+ | Database connection pooling issues with Neon | Medium | High | Use Neon's built-in pooling, monitor connections |
413
+ | JWT authentication integration complexity | Low | Medium | Well-documented in Spec 2, standard patterns |
414
+ | Next.js 16+ App Router learning curve | Medium | Low | Extensive documentation, clear server/client separation |
415
+ | Data isolation bugs (user accessing others' tasks) | Low | Critical | Comprehensive testing, query-level filtering |
416
+ | Performance degradation with large task lists | Medium | Medium | Implement pagination, database indexes |
417
+
418
+ ### Mitigation Strategies
419
+
420
+ 1. **Database Connection Issues**:
421
+ - Use connection pooling from day one
422
+ - Monitor connection metrics in development
423
+ - Test with concurrent users early
424
+
425
+ 2. **Authentication Integration**:
426
+ - Design endpoints with JWT in mind (user_id parameter)
427
+ - Defer full implementation to Spec 2
428
+ - Use placeholder authentication for testing
429
+
430
+ 3. **App Router Complexity**:
431
+ - Follow Next.js best practices (server components by default)
432
+ - Use client components only for interactivity
433
+ - Reference official documentation
434
+
435
+ 4. **Data Isolation**:
436
+ - Always include user_id in WHERE clauses
437
+ - Write comprehensive tests for ownership checks
438
+ - Code review all database queries
439
+
440
+ 5. **Performance**:
441
+ - Implement pagination from the start
442
+ - Create database indexes before testing
443
+ - Monitor query performance in development
444
+
445
+ ---
446
+
447
+ ## Success Metrics
448
+
449
+ ### Implementation Success Criteria
450
+
451
+ From spec.md Success Criteria section:
452
+
453
+ **Performance**:
454
+ - [ ] Task creation completes in <10 seconds
455
+ - [ ] Task list loads in <2 seconds
456
+ - [ ] Task updates reflect in <1 second
457
+ - [ ] Completion toggle responds in <500ms
458
+
459
+ **Data Integrity**:
460
+ - [ ] 100% user data isolation (no cross-user access)
461
+ - [ ] 100% data persistence (tasks survive page refresh)
462
+ - [ ] 95% operation success rate on first attempt
463
+
464
+ **Scalability**:
465
+ - [ ] System handles 100 concurrent users without errors
466
+
467
+ **User Experience**:
468
+ - [ ] Intuitive UI (no documentation needed)
469
+ - [ ] Clear error messages
470
+ - [ ] Immediate visual feedback for all actions
471
+ - [ ] Visual distinction between completed/incomplete tasks
472
+
473
+ **Technical**:
474
+ - [ ] All endpoints follow OpenAPI specification
475
+ - [ ] All database queries use proper indexes
476
+ - [ ] Frontend uses Server Components appropriately
477
+ - [ ] Code passes linting and formatting checks
478
+
479
+ ### Validation Plan
480
+
481
+ 1. **Unit Tests**: Service layer business logic
482
+ 2. **Integration Tests**: API endpoints with test database
483
+ 3. **Component Tests**: React components in isolation
484
+ 4. **Manual Testing**: Full user flows in browser
485
+ 5. **Performance Testing**: Load testing with 100 concurrent users
486
+
487
+ ---
488
+
489
+ ## Next Steps
490
+
491
+ 1. **Generate Task List**: Run `/sp.tasks` to create tasks.md
492
+ 2. **Review Tasks**: Validate task breakdown matches user stories
493
+ 3. **Execute Implementation**: Run `/sp.implement` to build the feature
494
+ 4. **Test Implementation**: Verify all success criteria met
495
+ 5. **Document ADRs**: Run `/sp.adr` for architectural decisions
496
+ 6. **Create Pull Request**: Commit changes and create PR for review
497
+
498
+ ---
499
+
500
+ ## References
501
+
502
+ - **Feature Specification**: [spec.md](./spec.md)
503
+ - **Research Document**: [research.md](./research.md)
504
+ - **Data Model**: [data-model.md](./data-model.md)
505
+ - **API Contracts**: [contracts/tasks-api.yaml](./contracts/tasks-api.yaml)
506
+ - **Quickstart Guide**: [quickstart.md](./quickstart.md)
507
+ - **Project Constitution**: [.specify/memory/constitution.md](../../.specify/memory/constitution.md)
508
+
509
+ ---
510
+
511
+ **Plan Status**: ✅ Complete - Ready for task generation (`/sp.tasks`)
512
+
513
+ **Branch**: `001-task-crud`
514
+
515
+ **Last Updated**: 2026-01-08
specs/001-task-crud/quickstart.md ADDED
@@ -0,0 +1,460 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quickstart Guide: Task CRUD Operations
2
+
3
+ **Feature**: Task CRUD Operations
4
+ **Date**: 2026-01-08
5
+ **Status**: Complete
6
+
7
+ ## Overview
8
+
9
+ This guide provides step-by-step instructions for setting up and running the Task CRUD feature locally. Follow these instructions to get the backend API and frontend UI running on your development machine.
10
+
11
+ ## Prerequisites
12
+
13
+ ### Required Software
14
+
15
+ - **Python**: 3.11 or higher
16
+ - **Node.js**: 18 or higher
17
+ - **PostgreSQL**: Neon Serverless PostgreSQL account (or local PostgreSQL 14+)
18
+ - **Git**: For version control
19
+ - **Code Editor**: VS Code recommended
20
+
21
+ ### Accounts Needed
22
+
23
+ - **Neon Account**: Sign up at https://neon.tech for serverless PostgreSQL
24
+ - **GitHub Account**: For version control (optional)
25
+
26
+ ## Project Structure
27
+
28
+ ```
29
+ phase-2-full-stack-web-app/
30
+ ├── backend/ # FastAPI backend
31
+ ├── frontend/ # Next.js frontend
32
+ └── specs/ # Feature specifications
33
+ ```
34
+
35
+ ## Backend Setup
36
+
37
+ ### 1. Navigate to Backend Directory
38
+
39
+ ```bash
40
+ cd backend
41
+ ```
42
+
43
+ ### 2. Create Python Virtual Environment
44
+
45
+ **Windows**:
46
+ ```bash
47
+ python -m venv venv
48
+ venv\Scripts\activate
49
+ ```
50
+
51
+ **macOS/Linux**:
52
+ ```bash
53
+ python3 -m venv venv
54
+ source venv/bin/activate
55
+ ```
56
+
57
+ ### 3. Install Dependencies
58
+
59
+ ```bash
60
+ pip install -r requirements.txt
61
+ ```
62
+
63
+ **requirements.txt** should contain:
64
+ ```
65
+ fastapi==0.104.1
66
+ sqlmodel==0.0.14
67
+ pydantic==2.5.0
68
+ uvicorn[standard]==0.24.0
69
+ alembic==1.13.0
70
+ psycopg2-binary==2.9.9
71
+ python-dotenv==1.0.0
72
+ pytest==7.4.3
73
+ httpx==0.25.2
74
+ ```
75
+
76
+ ### 4. Configure Environment Variables
77
+
78
+ Create `.env` file in `backend/` directory:
79
+
80
+ ```bash
81
+ cp .env.example .env
82
+ ```
83
+
84
+ Edit `.env` with your database credentials:
85
+
86
+ ```env
87
+ # Database Configuration
88
+ DATABASE_URL=postgresql://user:password@host/database
89
+
90
+ # Neon PostgreSQL Example:
91
+ # DATABASE_URL=postgresql://user:password@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require
92
+
93
+ # Application Settings
94
+ APP_NAME=Task CRUD API
95
+ DEBUG=True
96
+ CORS_ORIGINS=http://localhost:3000
97
+
98
+ # Authentication (Placeholder for Spec 2)
99
+ # JWT_SECRET=your-secret-key-here
100
+ # JWT_ALGORITHM=HS256
101
+ # JWT_EXPIRATION_MINUTES=1440
102
+ ```
103
+
104
+ ### 5. Set Up Database
105
+
106
+ **Initialize Alembic** (if not already done):
107
+ ```bash
108
+ alembic init alembic
109
+ ```
110
+
111
+ **Create initial migration**:
112
+ ```bash
113
+ alembic revision --autogenerate -m "Create tasks table"
114
+ ```
115
+
116
+ **Apply migrations**:
117
+ ```bash
118
+ alembic upgrade head
119
+ ```
120
+
121
+ ### 6. Run Backend Server
122
+
123
+ ```bash
124
+ uvicorn src.main:app --reload --host 0.0.0.0 --port 8000
125
+ ```
126
+
127
+ **Verify backend is running**:
128
+ - Open browser: http://localhost:8000/docs
129
+ - You should see the FastAPI Swagger UI with task endpoints
130
+
131
+ ### 7. Test Backend API
132
+
133
+ **Create a test user** (temporary, until Spec 2):
134
+ ```bash
135
+ # Using Python shell
136
+ python
137
+ >>> from src.core.database import engine
138
+ >>> from src.models.user import User
139
+ >>> from sqlmodel import Session
140
+ >>> with Session(engine) as session:
141
+ ... user = User(email="test@example.com", name="Test User")
142
+ ... session.add(user)
143
+ ... session.commit()
144
+ ... print(f"Created user with ID: {user.id}")
145
+ ```
146
+
147
+ **Test task creation**:
148
+ ```bash
149
+ curl -X POST http://localhost:8000/api/tasks \
150
+ -H "Content-Type: application/json" \
151
+ -d '{"title": "Test Task", "description": "Testing API"}'
152
+ ```
153
+
154
+ ## Frontend Setup
155
+
156
+ ### 1. Navigate to Frontend Directory
157
+
158
+ ```bash
159
+ cd frontend
160
+ ```
161
+
162
+ ### 2. Install Dependencies
163
+
164
+ ```bash
165
+ npm install
166
+ ```
167
+
168
+ **package.json** should contain:
169
+ ```json
170
+ {
171
+ "dependencies": {
172
+ "next": "^16.0.0",
173
+ "react": "^18.2.0",
174
+ "react-dom": "^18.2.0",
175
+ "typescript": "^5.3.0",
176
+ "tailwindcss": "^3.4.0"
177
+ },
178
+ "devDependencies": {
179
+ "@types/react": "^18.2.0",
180
+ "@types/node": "^20.10.0",
181
+ "autoprefixer": "^10.4.16",
182
+ "postcss": "^8.4.32"
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### 3. Configure Environment Variables
188
+
189
+ Create `.env.local` file in `frontend/` directory:
190
+
191
+ ```bash
192
+ cp .env.local.example .env.local
193
+ ```
194
+
195
+ Edit `.env.local`:
196
+
197
+ ```env
198
+ # API Configuration
199
+ NEXT_PUBLIC_API_URL=http://localhost:8000
200
+
201
+ # Authentication (Placeholder for Spec 2)
202
+ # NEXT_PUBLIC_AUTH_URL=http://localhost:8000/auth
203
+ ```
204
+
205
+ ### 4. Configure Tailwind CSS
206
+
207
+ **tailwind.config.ts**:
208
+ ```typescript
209
+ import type { Config } from 'tailwindcss'
210
+
211
+ const config: Config = {
212
+ content: [
213
+ './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
214
+ './src/components/**/*.{js,ts,jsx,tsx,mdx}',
215
+ './src/app/**/*.{js,ts,jsx,tsx,mdx}',
216
+ ],
217
+ theme: {
218
+ extend: {},
219
+ },
220
+ plugins: [],
221
+ }
222
+ export default config
223
+ ```
224
+
225
+ ### 5. Run Frontend Development Server
226
+
227
+ ```bash
228
+ npm run dev
229
+ ```
230
+
231
+ **Verify frontend is running**:
232
+ - Open browser: http://localhost:3000
233
+ - You should see the task list page
234
+
235
+ ### 6. Test Frontend
236
+
237
+ 1. **View Tasks**: Navigate to http://localhost:3000
238
+ 2. **Create Task**: Click "Add Task" button, fill form, submit
239
+ 3. **Edit Task**: Click edit icon on a task, modify, save
240
+ 4. **Complete Task**: Click checkbox to toggle completion
241
+ 5. **Delete Task**: Click delete icon, confirm deletion
242
+ 6. **Filter Tasks**: Use filter buttons (All/Active/Completed)
243
+
244
+ ## Development Workflow
245
+
246
+ ### Running Both Servers Concurrently
247
+
248
+ **Terminal 1 (Backend)**:
249
+ ```bash
250
+ cd backend
251
+ source venv/bin/activate # or venv\Scripts\activate on Windows
252
+ uvicorn src.main:app --reload
253
+ ```
254
+
255
+ **Terminal 2 (Frontend)**:
256
+ ```bash
257
+ cd frontend
258
+ npm run dev
259
+ ```
260
+
261
+ ### Making Changes
262
+
263
+ 1. **Backend Changes**:
264
+ - Edit files in `backend/src/`
265
+ - FastAPI auto-reloads on file changes
266
+ - Check http://localhost:8000/docs for updated API
267
+
268
+ 2. **Frontend Changes**:
269
+ - Edit files in `frontend/src/`
270
+ - Next.js auto-reloads on file changes
271
+ - Check browser for updates (hot reload)
272
+
273
+ 3. **Database Changes**:
274
+ - Modify SQLModel models in `backend/src/models/`
275
+ - Generate migration: `alembic revision --autogenerate -m "description"`
276
+ - Apply migration: `alembic upgrade head`
277
+
278
+ ## Testing
279
+
280
+ ### Backend Tests
281
+
282
+ ```bash
283
+ cd backend
284
+ pytest
285
+ ```
286
+
287
+ **Run specific test file**:
288
+ ```bash
289
+ pytest tests/test_task_api.py
290
+ ```
291
+
292
+ **Run with coverage**:
293
+ ```bash
294
+ pytest --cov=src tests/
295
+ ```
296
+
297
+ ### Frontend Tests
298
+
299
+ ```bash
300
+ cd frontend
301
+ npm test
302
+ ```
303
+
304
+ **Run specific test**:
305
+ ```bash
306
+ npm test -- TaskList.test.tsx
307
+ ```
308
+
309
+ ## Troubleshooting
310
+
311
+ ### Backend Issues
312
+
313
+ **Database connection error**:
314
+ - Verify `DATABASE_URL` in `.env` is correct
315
+ - Check Neon dashboard for connection string
316
+ - Ensure database exists and is accessible
317
+
318
+ **Import errors**:
319
+ - Verify virtual environment is activated
320
+ - Reinstall dependencies: `pip install -r requirements.txt`
321
+
322
+ **Port already in use**:
323
+ - Change port: `uvicorn src.main:app --reload --port 8001`
324
+ - Or kill process using port 8000
325
+
326
+ ### Frontend Issues
327
+
328
+ **Module not found**:
329
+ - Delete `node_modules/` and `.next/`
330
+ - Reinstall: `npm install`
331
+
332
+ **API connection error**:
333
+ - Verify backend is running on http://localhost:8000
334
+ - Check `NEXT_PUBLIC_API_URL` in `.env.local`
335
+ - Check browser console for CORS errors
336
+
337
+ **Port already in use**:
338
+ - Next.js will automatically try port 3001, 3002, etc.
339
+ - Or specify port: `npm run dev -- -p 3001`
340
+
341
+ ### Database Issues
342
+
343
+ **Migration conflicts**:
344
+ - Check `alembic/versions/` for conflicting migrations
345
+ - Downgrade: `alembic downgrade -1`
346
+ - Delete conflicting migration file
347
+ - Regenerate: `alembic revision --autogenerate -m "description"`
348
+
349
+ **Data not persisting**:
350
+ - Check database connection
351
+ - Verify migrations applied: `alembic current`
352
+ - Check for transaction rollbacks in logs
353
+
354
+ ## API Documentation
355
+
356
+ ### Swagger UI (Interactive)
357
+
358
+ http://localhost:8000/docs
359
+
360
+ ### ReDoc (Alternative)
361
+
362
+ http://localhost:8000/redoc
363
+
364
+ ### OpenAPI JSON
365
+
366
+ http://localhost:8000/openapi.json
367
+
368
+ ## Database Management
369
+
370
+ ### View Database Contents
371
+
372
+ **Using psql** (if local PostgreSQL):
373
+ ```bash
374
+ psql -d your_database
375
+ \dt # List tables
376
+ SELECT * FROM tasks;
377
+ ```
378
+
379
+ **Using Neon Console**:
380
+ 1. Log in to https://console.neon.tech
381
+ 2. Select your project
382
+ 3. Go to "SQL Editor"
383
+ 4. Run queries
384
+
385
+ ### Reset Database
386
+
387
+ **Drop all tables and recreate**:
388
+ ```bash
389
+ alembic downgrade base
390
+ alembic upgrade head
391
+ ```
392
+
393
+ **Or manually**:
394
+ ```sql
395
+ DROP TABLE tasks CASCADE;
396
+ DROP TABLE users CASCADE;
397
+ ```
398
+
399
+ Then run migrations again.
400
+
401
+ ## Environment Variables Reference
402
+
403
+ ### Backend (.env)
404
+
405
+ | Variable | Description | Example |
406
+ |----------|-------------|---------|
407
+ | DATABASE_URL | PostgreSQL connection string | postgresql://user:pass@host/db |
408
+ | APP_NAME | Application name | Task CRUD API |
409
+ | DEBUG | Enable debug mode | True |
410
+ | CORS_ORIGINS | Allowed CORS origins | http://localhost:3000 |
411
+
412
+ ### Frontend (.env.local)
413
+
414
+ | Variable | Description | Example |
415
+ |----------|-------------|---------|
416
+ | NEXT_PUBLIC_API_URL | Backend API URL | http://localhost:8000 |
417
+
418
+ ## Next Steps
419
+
420
+ 1. **Implement Authentication** (Spec 2):
421
+ - Add Better Auth integration
422
+ - Implement JWT token generation/validation
423
+ - Add user registration and login
424
+
425
+ 2. **Add Tests**:
426
+ - Write backend API tests
427
+ - Write frontend component tests
428
+ - Add E2E tests with Playwright
429
+
430
+ 3. **Deploy to Production**:
431
+ - Set up CI/CD pipeline
432
+ - Deploy backend to cloud provider
433
+ - Deploy frontend to Vercel/Netlify
434
+ - Configure production database
435
+
436
+ ## Additional Resources
437
+
438
+ - **FastAPI Documentation**: https://fastapi.tiangolo.com
439
+ - **Next.js Documentation**: https://nextjs.org/docs
440
+ - **SQLModel Documentation**: https://sqlmodel.tiangolo.com
441
+ - **Tailwind CSS Documentation**: https://tailwindcss.com/docs
442
+ - **Neon Documentation**: https://neon.tech/docs
443
+
444
+ ## Support
445
+
446
+ For issues or questions:
447
+ 1. Check the troubleshooting section above
448
+ 2. Review the specification: `specs/001-task-crud/spec.md`
449
+ 3. Check API contracts: `specs/001-task-crud/contracts/`
450
+ 4. Review data model: `specs/001-task-crud/data-model.md`
451
+
452
+ ## Summary
453
+
454
+ You should now have:
455
+ - ✅ Backend API running on http://localhost:8000
456
+ - ✅ Frontend UI running on http://localhost:3000
457
+ - ✅ Database configured and migrated
458
+ - ✅ Ability to create, view, update, delete, and complete tasks
459
+
460
+ **Ready for**: Implementation phase (`/sp.tasks` to generate task list, then `/sp.implement` to execute)
specs/001-task-crud/research.md ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research: Task CRUD Operations
2
+
3
+ **Feature**: Task CRUD Operations
4
+ **Date**: 2026-01-08
5
+ **Status**: Complete
6
+
7
+ ## Overview
8
+
9
+ This document consolidates technology decisions, best practices, and architectural patterns for implementing the Task CRUD feature. All decisions align with the project constitution and technical constraints defined in the specification.
10
+
11
+ ## Technology Stack Decisions
12
+
13
+ ### Backend Framework: FastAPI 0.104+
14
+
15
+ **Decision**: Use FastAPI with SQLModel ORM for the backend REST API.
16
+
17
+ **Rationale**:
18
+ - FastAPI provides automatic OpenAPI documentation generation
19
+ - Native async/await support for high concurrency (100+ concurrent users target)
20
+ - Pydantic v2 integration for robust request/response validation
21
+ - SQLModel combines SQLAlchemy ORM with Pydantic models, reducing code duplication
22
+ - Type hints throughout enable better IDE support and catch errors early
23
+ - Excellent performance characteristics (comparable to Node.js and Go)
24
+
25
+ **Alternatives Considered**:
26
+ - Django REST Framework: More batteries-included but heavier, slower, and less modern async support
27
+ - Flask: Lighter but requires more manual setup for validation, documentation, and async
28
+ - Express.js (Node): Would require JavaScript/TypeScript on backend, reducing type safety benefits of Python
29
+
30
+ **Best Practices**:
31
+ - Use dependency injection for database sessions and authentication
32
+ - Separate Pydantic schemas (request/response) from SQLModel models (database)
33
+ - Implement service layer for business logic (keep routes thin)
34
+ - Use HTTPException for consistent error responses
35
+ - Enable CORS middleware for frontend communication
36
+
37
+ ### Database: Neon Serverless PostgreSQL
38
+
39
+ **Decision**: Use Neon Serverless PostgreSQL with connection pooling.
40
+
41
+ **Rationale**:
42
+ - Serverless architecture scales automatically with demand
43
+ - Built-in connection pooling reduces overhead
44
+ - PostgreSQL provides ACID compliance for data integrity
45
+ - Native support for indexes, foreign keys, and constraints
46
+ - Compatible with SQLModel/SQLAlchemy ORM
47
+ - Separation of compute and storage enables cost efficiency
48
+
49
+ **Alternatives Considered**:
50
+ - Traditional PostgreSQL (self-hosted): Requires manual scaling and maintenance
51
+ - MySQL: Less feature-rich, weaker JSON support
52
+ - MongoDB: NoSQL not suitable for relational data (Task belongs to User)
53
+
54
+ **Best Practices**:
55
+ - Use connection pooling (pgbouncer or Neon's built-in pooling)
56
+ - Create indexes on user_id and completed columns for filtering
57
+ - Use foreign key constraints to enforce Task-User relationship
58
+ - Enable automatic timestamps (created_at, updated_at) via SQLModel
59
+ - Use Alembic for database migrations (version control for schema)
60
+
61
+ ### Frontend Framework: Next.js 16+ (App Router)
62
+
63
+ **Decision**: Use Next.js 16+ with App Router, TypeScript, and Tailwind CSS.
64
+
65
+ **Rationale**:
66
+ - App Router provides server/client component separation (better performance)
67
+ - Server components reduce JavaScript bundle size sent to client
68
+ - Built-in routing, API routes, and optimization features
69
+ - TypeScript ensures type safety across frontend
70
+ - Tailwind CSS enables rapid, consistent styling without CSS files
71
+ - React 18+ with concurrent features for better UX
72
+
73
+ **Alternatives Considered**:
74
+ - Next.js Pages Router: Older pattern, less efficient rendering
75
+ - Create React App: No SSR/SSG, requires manual routing setup
76
+ - Vue.js/Nuxt: Different ecosystem, team less familiar
77
+
78
+ **Best Practices**:
79
+ - Use Server Components by default (TaskList for data fetching)
80
+ - Use Client Components only for interactivity (TaskForm, TaskItem with buttons)
81
+ - Implement optimistic UI updates for better perceived performance
82
+ - Use React Server Actions for form submissions (optional, can use API routes)
83
+ - Organize components by feature (tasks/) and reusability (ui/)
84
+ - Use TypeScript interfaces for API response types
85
+
86
+ ## Architecture Patterns
87
+
88
+ ### Three-Layer Architecture
89
+
90
+ **Decision**: Implement clear separation between database, API, and UI layers.
91
+
92
+ **Layers**:
93
+ 1. **Database Layer**: SQLModel models, database connection, migrations
94
+ 2. **API Layer**: FastAPI routes, Pydantic schemas, service layer
95
+ 3. **UI Layer**: Next.js components, API client, state management
96
+
97
+ **Rationale**:
98
+ - Clear boundaries enable independent testing and development
99
+ - Service layer encapsulates business logic (reusable across endpoints)
100
+ - Separation of concerns aligns with Maintainable & Consistent Code principle
101
+ - Each layer can be scaled independently
102
+
103
+ **Implementation**:
104
+ ```
105
+ Database Layer: backend/src/models/task.py (SQLModel)
106
+ Service Layer: backend/src/services/task_service.py (business logic)
107
+ API Layer: backend/src/api/routes/tasks.py (FastAPI routes)
108
+ UI Layer: frontend/src/components/tasks/ (React components)
109
+ ```
110
+
111
+ ### RESTful API Design
112
+
113
+ **Decision**: Use REST principles with resource-based URLs and standard HTTP methods.
114
+
115
+ **Endpoint Pattern**:
116
+ ```
117
+ GET /api/tasks - List all tasks for authenticated user
118
+ POST /api/tasks - Create new task
119
+ GET /api/tasks/{id} - Get specific task
120
+ PUT /api/tasks/{id} - Update task (full replacement)
121
+ PATCH /api/tasks/{id} - Partial update (e.g., toggle completion)
122
+ DELETE /api/tasks/{id} - Delete task
123
+ ```
124
+
125
+ **Rationale**:
126
+ - Standard REST conventions are widely understood
127
+ - HTTP methods map naturally to CRUD operations
128
+ - Resource-based URLs are intuitive and cacheable
129
+ - Aligns with API Compliance standard in constitution
130
+
131
+ **Best Practices**:
132
+ - Use plural nouns for resources (/tasks not /task)
133
+ - Return appropriate HTTP status codes (200, 201, 204, 400, 401, 404, 500)
134
+ - Include resource ID in response body after creation
135
+ - Use query parameters for filtering (?completed=true) and sorting (?sort=created_at)
136
+ - Return consistent error response format
137
+
138
+ ### Data Validation Strategy
139
+
140
+ **Decision**: Use Pydantic v2 for request/response validation, SQLModel for database constraints.
141
+
142
+ **Validation Layers**:
143
+ 1. **API Layer**: Pydantic schemas validate incoming requests
144
+ 2. **Database Layer**: SQLModel/SQLAlchemy constraints enforce data integrity
145
+ 3. **Frontend Layer**: TypeScript types + HTML5 validation for UX
146
+
147
+ **Rationale**:
148
+ - Defense in depth: multiple validation layers prevent bad data
149
+ - Pydantic provides clear error messages for API consumers
150
+ - Database constraints ensure integrity even if API bypassed
151
+ - Frontend validation provides immediate user feedback
152
+
153
+ **Implementation**:
154
+ ```python
155
+ # API Layer (Pydantic)
156
+ class TaskCreate(BaseModel):
157
+ title: str = Field(min_length=1, max_length=200)
158
+ description: Optional[str] = Field(None, max_length=1000)
159
+
160
+ # Database Layer (SQLModel)
161
+ class Task(SQLModel, table=True):
162
+ title: str = Field(max_length=200, nullable=False)
163
+ description: Optional[str] = Field(max_length=1000)
164
+ ```
165
+
166
+ ## User Data Isolation Strategy
167
+
168
+ **Decision**: Filter all database queries by authenticated user ID.
169
+
170
+ **Implementation Approach**:
171
+ 1. Extract user_id from JWT token (Spec 2 will implement)
172
+ 2. Add user_id as dependency in FastAPI routes
173
+ 3. Include user_id filter in all database queries
174
+ 4. Validate task ownership before update/delete operations
175
+
176
+ **Rationale**:
177
+ - Enforces Security & Data Privacy principle
178
+ - Prevents unauthorized access to other users' tasks
179
+ - Simple to implement and audit
180
+ - Aligns with 100% data isolation success criterion
181
+
182
+ **Code Pattern**:
183
+ ```python
184
+ # Service layer
185
+ def get_tasks(db: Session, user_id: int) -> List[Task]:
186
+ return db.query(Task).filter(Task.user_id == user_id).all()
187
+
188
+ def get_task(db: Session, task_id: int, user_id: int) -> Optional[Task]:
189
+ return db.query(Task).filter(
190
+ Task.id == task_id,
191
+ Task.user_id == user_id
192
+ ).first()
193
+ ```
194
+
195
+ ## Performance Optimization
196
+
197
+ ### Database Indexing
198
+
199
+ **Decision**: Create indexes on frequently queried columns.
200
+
201
+ **Indexes to Create**:
202
+ - `user_id` (foreign key, used in all queries)
203
+ - `completed` (used for filtering active/completed tasks)
204
+ - Composite index on `(user_id, completed)` for filtered queries
205
+ - `created_at` (used for sorting)
206
+
207
+ **Rationale**:
208
+ - Indexes dramatically improve query performance for filtering and sorting
209
+ - user_id index essential for data isolation queries
210
+ - Composite index optimizes common filter combinations
211
+ - Aligns with Scalable Architecture principle
212
+
213
+ ### Frontend Optimization
214
+
215
+ **Decision**: Use Server Components for data fetching, Client Components for interactivity.
216
+
217
+ **Strategy**:
218
+ - TaskList: Server Component (fetches data, no JavaScript to client)
219
+ - TaskItem: Client Component (needs onClick handlers for complete/delete)
220
+ - TaskForm: Client Component (needs form state and submission)
221
+ - TaskFilters: Client Component (needs interactive filter/sort controls)
222
+
223
+ **Rationale**:
224
+ - Server Components reduce JavaScript bundle size
225
+ - Data fetching on server is faster (closer to database)
226
+ - Client Components only where interactivity required
227
+ - Improves initial page load time and perceived performance
228
+
229
+ ## Error Handling Strategy
230
+
231
+ **Decision**: Implement consistent error responses across all layers.
232
+
233
+ **Error Response Format**:
234
+ ```json
235
+ {
236
+ "detail": "Human-readable error message",
237
+ "error_code": "VALIDATION_ERROR",
238
+ "field_errors": {
239
+ "title": ["Title must be between 1 and 200 characters"]
240
+ }
241
+ }
242
+ ```
243
+
244
+ **HTTP Status Codes**:
245
+ - 200: Success (GET, PUT, PATCH)
246
+ - 201: Created (POST)
247
+ - 204: No Content (DELETE)
248
+ - 400: Bad Request (validation errors)
249
+ - 401: Unauthorized (missing/invalid JWT)
250
+ - 404: Not Found (task doesn't exist or doesn't belong to user)
251
+ - 500: Internal Server Error (unexpected errors)
252
+
253
+ **Rationale**:
254
+ - Consistent format enables frontend to handle errors uniformly
255
+ - Clear error messages improve developer experience
256
+ - Appropriate status codes enable proper HTTP caching and client behavior
257
+ - Aligns with API Compliance standard
258
+
259
+ ## Testing Strategy
260
+
261
+ **Decision**: Implement unit tests for services, integration tests for API endpoints.
262
+
263
+ **Test Coverage**:
264
+ - **Backend Unit Tests**: Service layer business logic (pytest)
265
+ - **Backend Integration Tests**: API endpoints with test database (pytest + TestClient)
266
+ - **Frontend Component Tests**: React components in isolation (Jest + React Testing Library)
267
+ - **E2E Tests**: Full user flows (optional, Playwright)
268
+
269
+ **Rationale**:
270
+ - Unit tests catch logic errors early
271
+ - Integration tests validate API contracts
272
+ - Component tests ensure UI behaves correctly
273
+ - Pyramid approach: many unit tests, fewer integration tests, minimal E2E
274
+
275
+ **Test Database**:
276
+ - Use SQLite in-memory database for fast test execution
277
+ - Or use separate PostgreSQL test database with cleanup between tests
278
+ - Fixtures provide consistent test data
279
+
280
+ ## Migration Strategy
281
+
282
+ **Decision**: Use Alembic for database schema migrations.
283
+
284
+ **Workflow**:
285
+ 1. Define/modify SQLModel models
286
+ 2. Generate migration: `alembic revision --autogenerate -m "description"`
287
+ 3. Review generated migration file
288
+ 4. Apply migration: `alembic upgrade head`
289
+ 5. Commit migration file to version control
290
+
291
+ **Rationale**:
292
+ - Alembic integrates seamlessly with SQLAlchemy/SQLModel
293
+ - Auto-generation reduces manual migration writing
294
+ - Version control for database schema changes
295
+ - Enables rollback if needed
296
+ - Aligns with Database Integrity standard
297
+
298
+ ## Security Considerations
299
+
300
+ ### Input Validation
301
+
302
+ **Measures**:
303
+ - Pydantic validation for all API inputs
304
+ - SQL injection prevention via SQLModel ORM (parameterized queries)
305
+ - XSS prevention via React's automatic escaping
306
+ - CSRF protection via SameSite cookies (when auth implemented)
307
+
308
+ ### Data Isolation
309
+
310
+ **Measures**:
311
+ - User ID filtering on all queries
312
+ - Ownership validation before update/delete
313
+ - No direct task ID access without user verification
314
+ - 401 responses for unauthorized access
315
+
316
+ ### Secrets Management
317
+
318
+ **Measures**:
319
+ - Database credentials in environment variables
320
+ - `.env` files excluded from version control (.gitignore)
321
+ - `.env.example` templates for required variables
322
+ - Production secrets in secure secret management (AWS Secrets Manager, etc.)
323
+
324
+ ## Dependencies and Versions
325
+
326
+ ### Backend (Python 3.11+)
327
+ ```
328
+ fastapi==0.104.1
329
+ sqlmodel==0.0.14
330
+ pydantic==2.5.0
331
+ uvicorn[standard]==0.24.0
332
+ alembic==1.13.0
333
+ psycopg2-binary==2.9.9 # PostgreSQL driver
334
+ python-dotenv==1.0.0
335
+ pytest==7.4.3
336
+ httpx==0.25.2 # For TestClient
337
+ ```
338
+
339
+ ### Frontend (Node.js 18+)
340
+ ```json
341
+ {
342
+ "dependencies": {
343
+ "next": "^16.0.0",
344
+ "react": "^18.2.0",
345
+ "react-dom": "^18.2.0",
346
+ "typescript": "^5.3.0",
347
+ "tailwindcss": "^3.4.0"
348
+ },
349
+ "devDependencies": {
350
+ "@types/react": "^18.2.0",
351
+ "@types/node": "^20.10.0",
352
+ "jest": "^29.7.0",
353
+ "@testing-library/react": "^14.1.0"
354
+ }
355
+ }
356
+ ```
357
+
358
+ ## Deferred Decisions (Spec 2)
359
+
360
+ The following decisions are deferred to the authentication specification:
361
+ - JWT token generation and validation
362
+ - Better Auth integration
363
+ - User registration and login flows
364
+ - Token refresh mechanism
365
+ - Session management
366
+
367
+ **Current Approach**: API endpoints will accept user_id as a parameter (to be replaced with JWT extraction in Spec 2).
368
+
369
+ ## Summary
370
+
371
+ All technology decisions align with the project constitution and technical constraints. The three-layer architecture with FastAPI, Neon PostgreSQL, and Next.js 16+ provides a solid foundation for scalable, maintainable task management. User data isolation is enforced at the database query level. Performance optimizations include database indexing and Server Component usage. Error handling is consistent across all layers. Testing strategy covers unit, integration, and component tests.
372
+
373
+ **Ready for Phase 1**: Data model design and API contract generation.
specs/001-task-crud/spec.md ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Feature Specification: Task CRUD Operations
2
+
3
+ **Feature Branch**: `001-task-crud`
4
+ **Created**: 2026-01-08
5
+ **Status**: Draft
6
+ **Input**: User description: "Task CRUD Feature – Phase II Todo Web App"
7
+
8
+ ## User Scenarios & Testing *(mandatory)*
9
+
10
+ ### User Story 1 - View and Create Tasks (Priority: P1)
11
+
12
+ As an authenticated user, I want to view my task list and create new tasks so that I can start managing my to-do items.
13
+
14
+ **Why this priority**: This is the foundational MVP functionality. Without the ability to create and view tasks, the application has no value. This story delivers immediate user value and can be demonstrated independently.
15
+
16
+ **Independent Test**: Can be fully tested by logging in, viewing an empty task list, creating a new task with a title, and seeing it appear in the list. Delivers core value of task creation and visibility.
17
+
18
+ **Acceptance Scenarios**:
19
+
20
+ 1. **Given** I am an authenticated user with no tasks, **When** I view my task list, **Then** I see an empty state message indicating no tasks exist
21
+ 2. **Given** I am viewing my task list, **When** I click "Add Task" and enter a title "Buy groceries", **Then** the task appears in my list with the title and a default "not completed" status
22
+ 3. **Given** I am creating a task, **When** I enter a title and optional description, **Then** both fields are saved and displayed in the task list
23
+ 4. **Given** I am viewing my task list, **When** I refresh the page, **Then** all my previously created tasks are still visible (data persists)
24
+ 5. **Given** I am an authenticated user, **When** I view my task list, **Then** I only see tasks that I created (not other users' tasks)
25
+
26
+ ---
27
+
28
+ ### User Story 2 - Update and Complete Tasks (Priority: P2)
29
+
30
+ As an authenticated user, I want to edit my tasks and mark them as complete so that I can update task details and track my progress.
31
+
32
+ **Why this priority**: After creating tasks, users need to update them as requirements change and mark them complete to track progress. This builds on P1 and adds essential task management capabilities.
33
+
34
+ **Independent Test**: Can be tested by creating a task (from P1), editing its title or description, and toggling its completion status. Delivers progress tracking value.
35
+
36
+ **Acceptance Scenarios**:
37
+
38
+ 1. **Given** I have a task "Buy groceries", **When** I click edit and change the title to "Buy groceries and milk", **Then** the updated title is saved and displayed
39
+ 2. **Given** I have a task with a description, **When** I edit the description, **Then** the updated description is saved
40
+ 3. **Given** I have an incomplete task, **When** I click the checkbox to mark it complete, **Then** the task is visually marked as completed
41
+ 4. **Given** I have a completed task, **When** I click the checkbox again, **Then** the task is marked as incomplete
42
+ 5. **Given** I am editing a task, **When** I cancel the edit, **Then** the original task details remain unchanged
43
+
44
+ ---
45
+
46
+ ### User Story 3 - Delete Tasks (Priority: P3)
47
+
48
+ As an authenticated user, I want to delete tasks I no longer need so that my task list stays clean and relevant.
49
+
50
+ **Why this priority**: Task deletion is important for list maintenance but not critical for initial value delivery. Users can work around missing deletion by marking tasks complete.
51
+
52
+ **Independent Test**: Can be tested by creating a task (from P1), deleting it, and verifying it no longer appears in the list. Delivers list management value.
53
+
54
+ **Acceptance Scenarios**:
55
+
56
+ 1. **Given** I have a task in my list, **When** I click the delete button, **Then** the task is removed from my list
57
+ 2. **Given** I have deleted a task, **When** I refresh the page, **Then** the deleted task does not reappear
58
+ 3. **Given** I am about to delete a task, **When** I am prompted for confirmation, **Then** I can confirm or cancel the deletion
59
+ 4. **Given** I have multiple tasks, **When** I delete one task, **Then** only that specific task is removed and others remain
60
+
61
+ ---
62
+
63
+ ### User Story 4 - Filter and Sort Tasks (Priority: P4)
64
+
65
+ As an authenticated user, I want to filter tasks by completion status and sort them so that I can focus on relevant tasks.
66
+
67
+ **Why this priority**: Filtering and sorting improve usability but are not essential for core task management. Users can manually scan their list initially.
68
+
69
+ **Independent Test**: Can be tested by creating multiple tasks with different completion statuses, applying filters (show all/active/completed), and verifying the correct subset is displayed. Delivers organization value.
70
+
71
+ **Acceptance Scenarios**:
72
+
73
+ 1. **Given** I have both completed and incomplete tasks, **When** I select "Active" filter, **Then** I only see incomplete tasks
74
+ 2. **Given** I have both completed and incomplete tasks, **When** I select "Completed" filter, **Then** I only see completed tasks
75
+ 3. **Given** I have multiple tasks, **When** I select "All" filter, **Then** I see all tasks regardless of completion status
76
+ 4. **Given** I have multiple tasks, **When** I sort by creation date (newest first), **Then** tasks are displayed with most recent at the top
77
+ 5. **Given** I have applied a filter, **When** I refresh the page, **Then** the filter preference is maintained
78
+
79
+ ---
80
+
81
+ ### Edge Cases
82
+
83
+ - What happens when a user tries to create a task with an empty title?
84
+ - What happens when a user tries to create a task with a title exceeding 200 characters?
85
+ - What happens when a user tries to create a task with a description exceeding 1000 characters?
86
+ - How does the system handle concurrent updates to the same task from multiple browser tabs?
87
+ - What happens when the backend API is unavailable during task operations?
88
+ - How does the system handle special characters or emojis in task titles and descriptions?
89
+ - What happens when a user tries to access another user's task directly via URL manipulation?
90
+
91
+ ## Requirements *(mandatory)*
92
+
93
+ ### Functional Requirements
94
+
95
+ - **FR-001**: System MUST allow authenticated users to create tasks with a title (1-200 characters, required) and description (0-1000 characters, optional)
96
+ - **FR-002**: System MUST display all tasks belonging to the authenticated user in a list view
97
+ - **FR-003**: System MUST allow users to edit the title and description of their existing tasks
98
+ - **FR-004**: System MUST allow users to toggle the completion status of their tasks (completed/incomplete)
99
+ - **FR-005**: System MUST allow users to delete their tasks with confirmation
100
+ - **FR-006**: System MUST persist all task data to the database with automatic timestamps (created_at, updated_at)
101
+ - **FR-007**: System MUST enforce data isolation - users can only view, edit, and delete their own tasks
102
+ - **FR-008**: System MUST validate task title length (1-200 characters) and reject invalid submissions
103
+ - **FR-009**: System MUST validate task description length (0-1000 characters) and reject invalid submissions
104
+ - **FR-010**: System MUST provide filtering options: All tasks, Active tasks (incomplete), Completed tasks
105
+ - **FR-011**: System MUST provide sorting options: by creation date (newest/oldest first)
106
+ - **FR-012**: System MUST display task metadata: creation timestamp, last updated timestamp
107
+ - **FR-013**: System MUST provide visual distinction between completed and incomplete tasks
108
+ - **FR-014**: System MUST handle API errors gracefully with user-friendly error messages
109
+ - **FR-015**: System MUST maintain responsive design across mobile, tablet, and desktop viewports
110
+
111
+ ### Assumptions
112
+
113
+ - Authentication and JWT token management are handled by a separate authentication feature (Spec 2)
114
+ - The frontend receives a valid JWT token from the authentication system
115
+ - The backend has middleware to verify JWT tokens and extract user identity
116
+ - Database connection and configuration are already established
117
+ - The user ID is available from the authenticated session/token
118
+
119
+ ### Key Entities
120
+
121
+ - **Task**: Represents a to-do item with the following attributes:
122
+ - Unique identifier (system-generated)
123
+ - Title (1-200 characters, required)
124
+ - Description (0-1000 characters, optional)
125
+ - Completion status (boolean: completed/incomplete)
126
+ - Owner (reference to the user who created it)
127
+ - Creation timestamp (automatically set)
128
+ - Last updated timestamp (automatically updated)
129
+ - Relationships: Belongs to one User
130
+
131
+ - **User**: Represents an authenticated user (defined in authentication spec)
132
+ - Unique identifier
133
+ - Relationships: Has many Tasks
134
+
135
+ ## Success Criteria *(mandatory)*
136
+
137
+ ### Measurable Outcomes
138
+
139
+ - **SC-001**: Users can create a new task in under 10 seconds from clicking "Add Task" to seeing it in their list
140
+ - **SC-002**: Users can view their complete task list with all tasks loading and displaying within 2 seconds
141
+ - **SC-003**: Users can edit a task and see the updated information reflected immediately (within 1 second of saving)
142
+ - **SC-004**: Users can mark a task as complete and see the visual change instantly (within 500ms)
143
+ - **SC-005**: Users can delete a task and see it removed from the list within 1 second
144
+ - **SC-006**: System correctly isolates user data - 100% of API requests return only the authenticated user's tasks
145
+ - **SC-007**: System handles 100 concurrent users performing task operations without errors or data corruption
146
+ - **SC-008**: 95% of task operations (create, update, delete, complete) succeed on first attempt without errors
147
+ - **SC-009**: Users can successfully complete all core task operations (create, view, update, complete, delete) on mobile devices with touch interactions
148
+ - **SC-010**: System maintains data integrity - 100% of created tasks persist correctly and are retrievable after page refresh
149
+
150
+ ### User Experience Outcomes
151
+
152
+ - **SC-011**: Users can understand how to create, edit, and delete tasks without external documentation
153
+ - **SC-012**: Error messages clearly communicate what went wrong and how to fix it (e.g., "Title must be between 1 and 200 characters")
154
+ - **SC-013**: The interface provides immediate visual feedback for all user actions (loading states, success confirmations, error alerts)
155
+ - **SC-014**: Users can distinguish between completed and incomplete tasks at a glance through clear visual indicators
156
+
157
+ ## Out of Scope
158
+
159
+ The following items are explicitly excluded from this specification:
160
+
161
+ - User authentication and authorization implementation (covered in separate authentication spec)
162
+ - JWT token generation, validation, and refresh logic (covered in authentication spec)
163
+ - User registration and login flows (covered in authentication spec)
164
+ - Task sharing or collaboration features
165
+ - Task categories, tags, or labels
166
+ - Task due dates or reminders
167
+ - Task priority levels
168
+ - Task attachments or file uploads
169
+ - Task comments or notes beyond the description field
170
+ - Task history or audit trail
171
+ - Bulk operations (delete multiple tasks, mark multiple complete)
172
+ - Task search functionality
173
+ - Task export/import features
174
+ - Chatbot or AI-powered task suggestions
175
+ - Deployment configuration or environment setup
176
+ - Advanced UI animations or transitions beyond standard interactions
177
+
178
+ ## Dependencies
179
+
180
+ - **Authentication System**: This feature requires a functioning authentication system that provides JWT tokens and user identity
181
+ - **Database**: Requires Neon PostgreSQL database to be provisioned and accessible
182
+ - **Backend Framework**: Requires FastAPI backend with SQLModel ORM configured
183
+ - **Frontend Framework**: Requires Next.js 16+ with App Router configured
184
+
185
+ ## Technical Constraints
186
+
187
+ - **Frontend**: Must use Next.js 16+ (App Router), TypeScript, Tailwind CSS
188
+ - **Backend**: Must use Python FastAPI with SQLModel ORM
189
+ - **Database**: Must use Neon Serverless PostgreSQL
190
+ - **API Design**: Must follow REST principles with JSON request/response format
191
+ - **Authentication**: All task endpoints must require valid JWT token in Authorization header
192
+ - **Code Generation**: All implementation must be generated via Claude Code referencing this specification
193
+ - **File Structure**: Must follow monorepo organization with frontend/ and backend/ directories
194
+
195
+ ## References
196
+
197
+ This specification should be referenced during implementation planning and task generation:
198
+
199
+ - `@specs/001-task-crud/spec.md` (this file)
200
+ - `@specs/001-task-crud/plan.md` (to be created by `/sp.plan`)
201
+ - `@specs/001-task-crud/tasks.md` (to be created by `/sp.tasks`)
202
+ - `@specs/001-task-crud/contracts/` (API endpoint contracts to be defined in planning phase)
specs/001-task-crud/tasks.md ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+
3
+ description: "Task list for Task CRUD Operations feature implementation"
4
+ ---
5
+
6
+ # Tasks: Task CRUD Operations
7
+
8
+ **Input**: Design documents from `/specs/001-task-crud/`
9
+ **Prerequisites**: plan.md (required), spec.md (required for user stories), data-model.md, contracts/
10
+
11
+ **Tests**: Not requested in specification - implementation only
12
+
13
+ **Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
14
+
15
+ ## Format: `[ID] [P?] [Story] Description`
16
+
17
+ - **[P]**: Can run in parallel (different files, no dependencies)
18
+ - **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3, US4)
19
+ - Include exact file paths in descriptions
20
+
21
+ ## Path Conventions
22
+
23
+ - **Backend**: `backend/src/` for source code, `backend/tests/` for tests
24
+ - **Frontend**: `frontend/src/` for source code
25
+ - Paths shown below follow monorepo structure from plan.md
26
+
27
+ ## Phase 1: Setup (Shared Infrastructure)
28
+
29
+ **Purpose**: Project initialization and basic structure
30
+
31
+ - [x] T001 Create backend directory structure with src/, tests/, alembic/ folders
32
+ - [x] T002 Create frontend directory structure with src/app/, src/components/, src/lib/ folders
33
+ - [x] T003 [P] Initialize Python project with requirements.txt (FastAPI, SQLModel, Pydantic, uvicorn, alembic, psycopg2-binary, python-dotenv)
34
+ - [x] T004 [P] Initialize Node.js project with package.json (Next.js 16+, React 18+, TypeScript, Tailwind CSS)
35
+ - [x] T005 [P] Configure Tailwind CSS in frontend/tailwind.config.ts and frontend/src/styles/globals.css
36
+ - [x] T006 [P] Create backend/.env.example with DATABASE_URL, APP_NAME, DEBUG, CORS_ORIGINS placeholders
37
+ - [x] T007 [P] Create frontend/.env.local.example with NEXT_PUBLIC_API_URL placeholder
38
+
39
+ ---
40
+
41
+ ## Phase 2: Foundational (Blocking Prerequisites)
42
+
43
+ **Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
44
+
45
+ **⚠️ CRITICAL**: No user story work can begin until this phase is complete
46
+
47
+ - [x] T008 Create database configuration in backend/src/core/config.py with Settings class
48
+ - [x] T009 Create database connection setup in backend/src/core/database.py with engine and session
49
+ - [x] T010 [P] Create User model stub in backend/src/models/user.py (id, email, name, timestamps)
50
+ - [x] T011 [P] Create Task model in backend/src/models/task.py (id, user_id, title, description, completed, timestamps)
51
+ - [x] T012 Initialize Alembic in backend/alembic/ and configure env.py with SQLModel metadata
52
+ - [x] T013 Generate initial migration for users and tasks tables with indexes
53
+ - [x] T014 Create FastAPI application entry point in backend/src/main.py with CORS middleware
54
+ - [x] T015 [P] Create API dependencies in backend/src/api/deps.py (get_db session, get_current_user stub)
55
+ - [x] T016 [P] Create TypeScript types in frontend/src/lib/types.ts (Task, TaskCreate, TaskUpdate interfaces)
56
+ - [x] T017 [P] Create API client base in frontend/src/lib/api.ts with fetch wrapper and error handling
57
+
58
+ **Checkpoint**: Foundation ready - user story implementation can now begin in parallel
59
+
60
+ ---
61
+
62
+ ## Phase 3: User Story 1 - View and Create Tasks (Priority: P1) 🎯 MVP
63
+
64
+ **Goal**: Users can view their task list and create new tasks
65
+
66
+ **Independent Test**: Log in, view empty task list, create task with title, see it appear in list
67
+
68
+ ### Implementation for User Story 1
69
+
70
+ - [ ] T018 [P] [US1] Create TaskCreate Pydantic schema in backend/src/schemas/task.py
71
+ - [ ] T019 [P] [US1] Create TaskResponse Pydantic schema in backend/src/schemas/task.py
72
+ - [ ] T020 [P] [US1] Create TaskListResponse Pydantic schema in backend/src/schemas/task.py
73
+ - [ ] T021 [US1] Create TaskService with get_tasks() and create_task() methods in backend/src/services/task_service.py
74
+ - [ ] T022 [US1] Implement GET /api/tasks endpoint in backend/src/api/routes/tasks.py
75
+ - [ ] T023 [US1] Implement POST /api/tasks endpoint in backend/src/api/routes/tasks.py
76
+ - [ ] T024 [US1] Register task routes in backend/src/main.py
77
+ - [ ] T025 [P] [US1] Create TaskList server component in frontend/src/components/tasks/TaskList.tsx
78
+ - [ ] T026 [P] [US1] Create TaskForm client component in frontend/src/components/tasks/TaskForm.tsx
79
+ - [ ] T027 [P] [US1] Create TaskItem client component in frontend/src/components/tasks/TaskItem.tsx
80
+ - [ ] T028 [US1] Implement getTasks() API function in frontend/src/lib/api.ts
81
+ - [ ] T029 [US1] Implement createTask() API function in frontend/src/lib/api.ts
82
+ - [ ] T030 [US1] Create home page in frontend/src/app/page.tsx integrating TaskList and TaskForm
83
+
84
+ **Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
85
+
86
+ ---
87
+
88
+ ## Phase 4: User Story 2 - Update and Complete Tasks (Priority: P2)
89
+
90
+ **Goal**: Users can edit tasks and mark them as complete
91
+
92
+ **Independent Test**: Create task (from P1), edit title/description, toggle completion status
93
+
94
+ ### Implementation for User Story 2
95
+
96
+ - [ ] T031 [P] [US2] Create TaskUpdate Pydantic schema in backend/src/schemas/task.py
97
+ - [ ] T032 [P] [US2] Create TaskPatch Pydantic schema in backend/src/schemas/task.py
98
+ - [ ] T033 [US2] Add get_task(), update_task(), and patch_task() methods to TaskService in backend/src/services/task_service.py
99
+ - [ ] T034 [US2] Implement GET /api/tasks/{task_id} endpoint in backend/src/api/routes/tasks.py
100
+ - [ ] T035 [US2] Implement PUT /api/tasks/{task_id} endpoint in backend/src/api/routes/tasks.py
101
+ - [ ] T036 [US2] Implement PATCH /api/tasks/{task_id} endpoint in backend/src/api/routes/tasks.py
102
+ - [ ] T037 [US2] Add edit mode state and handlers to TaskItem component in frontend/src/components/tasks/TaskItem.tsx
103
+ - [ ] T038 [US2] Add completion toggle handler to TaskItem component in frontend/src/components/tasks/TaskItem.tsx
104
+ - [ ] T039 [US2] Implement updateTask() API function in frontend/src/lib/api.ts
105
+ - [ ] T040 [US2] Implement patchTask() API function in frontend/src/lib/api.ts
106
+
107
+ **Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
108
+
109
+ ---
110
+
111
+ ## Phase 5: User Story 3 - Delete Tasks (Priority: P3)
112
+
113
+ **Goal**: Users can delete tasks they no longer need
114
+
115
+ **Independent Test**: Create task (from P1), delete it, verify it no longer appears
116
+
117
+ ### Implementation for User Story 3
118
+
119
+ - [ ] T041 [US3] Add delete_task() method to TaskService in backend/src/services/task_service.py
120
+ - [ ] T042 [US3] Implement DELETE /api/tasks/{task_id} endpoint in backend/src/api/routes/tasks.py
121
+ - [ ] T043 [US3] Add delete button and confirmation dialog to TaskItem component in frontend/src/components/tasks/TaskItem.tsx
122
+ - [ ] T044 [US3] Implement deleteTask() API function in frontend/src/lib/api.ts
123
+
124
+ **Checkpoint**: All user stories 1, 2, and 3 should now be independently functional
125
+
126
+ ---
127
+
128
+ ## Phase 6: User Story 4 - Filter and Sort Tasks (Priority: P4)
129
+
130
+ **Goal**: Users can filter by completion status and sort by date
131
+
132
+ **Independent Test**: Create multiple tasks, apply filters (all/active/completed), verify correct subset displayed
133
+
134
+ ### Implementation for User Story 4
135
+
136
+ - [ ] T045 [US4] Add filtering and sorting logic to get_tasks() in TaskService (backend/src/services/task_service.py)
137
+ - [ ] T046 [US4] Update GET /api/tasks endpoint to accept query parameters (completed, sort, limit, offset) in backend/src/api/routes/tasks.py
138
+ - [ ] T047 [P] [US4] Create TaskFilters client component in frontend/src/components/tasks/TaskFilters.tsx
139
+ - [ ] T048 [US4] Update getTasks() API function to accept filter/sort parameters in frontend/src/lib/api.ts
140
+ - [ ] T049 [US4] Integrate TaskFilters component into home page in frontend/src/app/page.tsx
141
+
142
+ **Checkpoint**: All user stories should now be independently functional
143
+
144
+ ---
145
+
146
+ ## Phase 7: Polish & Cross-Cutting Concerns
147
+
148
+ **Purpose**: Improvements that affect multiple user stories
149
+
150
+ - [ ] T050 [P] Add error handling and user-friendly error messages across all API endpoints in backend/src/api/routes/tasks.py
151
+ - [ ] T051 [P] Add loading states and error displays to frontend components in frontend/src/components/tasks/
152
+ - [ ] T052 [P] Add input validation and error messages to TaskForm component in frontend/src/components/tasks/TaskForm.tsx
153
+ - [ ] T053 [P] Create reusable UI components (Button, Input, Checkbox) in frontend/src/components/ui/
154
+ - [ ] T054 [P] Add responsive design styles with Tailwind CSS breakpoints to all task components
155
+ - [ ] T055 [P] Add visual distinction for completed vs incomplete tasks in TaskItem component
156
+ - [ ] T056 Create backend README.md with setup instructions
157
+ - [ ] T057 Create frontend README.md with setup instructions
158
+
159
+ ---
160
+
161
+ ## Dependencies & Execution Order
162
+
163
+ ### Phase Dependencies
164
+
165
+ - **Setup (Phase 1)**: No dependencies - can start immediately
166
+ - **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
167
+ - **User Stories (Phase 3-6)**: All depend on Foundational phase completion
168
+ - User stories can then proceed in parallel (if staffed)
169
+ - Or sequentially in priority order (P1 → P2 → P3 → P4)
170
+ - **Polish (Phase 7)**: Depends on all desired user stories being complete
171
+
172
+ ### User Story Dependencies
173
+
174
+ - **User Story 1 (P1)**: Can start after Foundational (Phase 2) - No dependencies on other stories
175
+ - **User Story 2 (P2)**: Can start after Foundational (Phase 2) - Builds on US1 but independently testable
176
+ - **User Story 3 (P3)**: Can start after Foundational (Phase 2) - Builds on US1 but independently testable
177
+ - **User Story 4 (P4)**: Can start after Foundational (Phase 2) - Enhances US1 but independently testable
178
+
179
+ ### Within Each User Story
180
+
181
+ - Pydantic schemas before service methods
182
+ - Service methods before API endpoints
183
+ - API endpoints before frontend components
184
+ - API client functions alongside frontend components
185
+ - Core implementation before integration
186
+
187
+ ### Parallel Opportunities
188
+
189
+ - All Setup tasks marked [P] can run in parallel
190
+ - All Foundational tasks marked [P] can run in parallel (within Phase 2)
191
+ - Once Foundational phase completes, all user stories can start in parallel (if team capacity allows)
192
+ - Tasks within a user story marked [P] can run in parallel
193
+ - Different user stories can be worked on in parallel by different team members
194
+
195
+ ---
196
+
197
+ ## Parallel Example: User Story 1
198
+
199
+ ```bash
200
+ # Launch Pydantic schemas together:
201
+ Task: "Create TaskCreate schema in backend/src/schemas/task.py"
202
+ Task: "Create TaskResponse schema in backend/src/schemas/task.py"
203
+ Task: "Create TaskListResponse schema in backend/src/schemas/task.py"
204
+
205
+ # Launch frontend components together (after API is ready):
206
+ Task: "Create TaskList component in frontend/src/components/tasks/TaskList.tsx"
207
+ Task: "Create TaskForm component in frontend/src/components/tasks/TaskForm.tsx"
208
+ Task: "Create TaskItem component in frontend/src/components/tasks/TaskItem.tsx"
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Implementation Strategy
214
+
215
+ ### MVP First (User Story 1 Only)
216
+
217
+ 1. Complete Phase 1: Setup
218
+ 2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
219
+ 3. Complete Phase 3: User Story 1
220
+ 4. **STOP and VALIDATE**: Test User Story 1 independently
221
+ 5. Deploy/demo if ready
222
+
223
+ ### Incremental Delivery
224
+
225
+ 1. Complete Setup + Foundational → Foundation ready
226
+ 2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
227
+ 3. Add User Story 2 → Test independently → Deploy/Demo
228
+ 4. Add User Story 3 → Test independently → Deploy/Demo
229
+ 5. Add User Story 4 → Test independently → Deploy/Demo
230
+ 6. Each story adds value without breaking previous stories
231
+
232
+ ### Parallel Team Strategy
233
+
234
+ With multiple developers:
235
+
236
+ 1. Team completes Setup + Foundational together
237
+ 2. Once Foundational is done:
238
+ - Developer A: User Story 1
239
+ - Developer B: User Story 2
240
+ - Developer C: User Story 3
241
+ 3. Stories complete and integrate independently
242
+
243
+ ---
244
+
245
+ ## Notes
246
+
247
+ - [P] tasks = different files, no dependencies
248
+ - [Story] label maps task to specific user story for traceability
249
+ - Each user story should be independently completable and testable
250
+ - Commit after each task or logical group
251
+ - Stop at any checkpoint to validate story independently
252
+ - Avoid: vague tasks, same file conflicts, cross-story dependencies that break independence
253
+
254
+ ---
255
+
256
+ ## Task Summary
257
+
258
+ **Total Tasks**: 57
259
+ - Phase 1 (Setup): 7 tasks
260
+ - Phase 2 (Foundational): 10 tasks
261
+ - Phase 3 (User Story 1 - P1): 13 tasks
262
+ - Phase 4 (User Story 2 - P2): 10 tasks
263
+ - Phase 5 (User Story 3 - P3): 4 tasks
264
+ - Phase 6 (User Story 4 - P4): 5 tasks
265
+ - Phase 7 (Polish): 8 tasks
266
+
267
+ **Parallel Opportunities**: 23 tasks marked [P] can run in parallel within their phase
268
+
269
+ **MVP Scope**: Phases 1-3 (30 tasks) deliver User Story 1 - View and Create Tasks
270
+
271
+ **Independent Test Criteria**:
272
+ - US1: Create and view tasks in list
273
+ - US2: Edit task and toggle completion
274
+ - US3: Delete task from list
275
+ - US4: Filter and sort task list
specs/001-todo-ai-chatbot/contracts/chat-api.yaml ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Todo AI Chatbot API
4
+ description: |
5
+ API specification for the Todo AI Chatbot conversational interface.
6
+ This API enables stateless conversational AI interactions with database-persisted state.
7
+ version: 1.0.0
8
+ contact:
9
+ name: Phase III Development Team
10
+
11
+ servers:
12
+ - url: http://localhost:8000
13
+ description: Local development server
14
+ - url: https://api.example.com
15
+ description: Production server (TBD)
16
+
17
+ tags:
18
+ - name: chat
19
+ description: Conversational AI endpoints
20
+
21
+ paths:
22
+ /api/{user_id}/chat:
23
+ post:
24
+ tags:
25
+ - chat
26
+ summary: Send message to AI chatbot
27
+ description: |
28
+ Stateless endpoint for conversational AI interaction.
29
+
30
+ **Flow**:
31
+ 1. Load conversation history from database
32
+ 2. Execute AI agent with full message history
33
+ 3. Save user message and assistant response to database
34
+ 4. Return assistant response
35
+
36
+ **Authentication**: Requires valid JWT token in Authorization header.
37
+ The user_id in the path must match the authenticated user from the JWT.
38
+ operationId: sendChatMessage
39
+ parameters:
40
+ - name: user_id
41
+ in: path
42
+ required: true
43
+ description: Authenticated user ID (must match JWT token)
44
+ schema:
45
+ type: integer
46
+ example: 123
47
+ security:
48
+ - BearerAuth: []
49
+ requestBody:
50
+ required: true
51
+ content:
52
+ application/json:
53
+ schema:
54
+ $ref: '#/components/schemas/ChatRequest'
55
+ examples:
56
+ simpleMessage:
57
+ summary: Simple user message
58
+ value:
59
+ message: "Hello, can you help me with my tasks?"
60
+ taskIntent:
61
+ summary: Task-related intent
62
+ value:
63
+ message: "I need to add a new task for tomorrow"
64
+ responses:
65
+ '200':
66
+ description: Successful response from AI assistant
67
+ content:
68
+ application/json:
69
+ schema:
70
+ $ref: '#/components/schemas/ChatResponse'
71
+ examples:
72
+ greeting:
73
+ summary: Greeting response
74
+ value:
75
+ response: "Hello! I'm your AI assistant. I can help you manage your tasks through natural conversation. What would you like to do?"
76
+ conversation_id: 456
77
+ timestamp: "2026-01-14T10:30:00Z"
78
+ taskAcknowledgment:
79
+ summary: Task intent acknowledgment
80
+ value:
81
+ response: "I understand you want to add a new task for tomorrow. In Phase 1, I can acknowledge your intent, but task creation will be available in Phase 2. For now, I'm here to chat and help you plan!"
82
+ conversation_id: 456
83
+ timestamp: "2026-01-14T10:31:00Z"
84
+ '400':
85
+ description: Bad request (invalid input)
86
+ content:
87
+ application/json:
88
+ schema:
89
+ $ref: '#/components/schemas/ErrorResponse'
90
+ examples:
91
+ emptyMessage:
92
+ summary: Empty message error
93
+ value:
94
+ error: "Bad Request"
95
+ message: "Message content cannot be empty"
96
+ status_code: 400
97
+ '401':
98
+ description: Unauthorized (missing or invalid JWT token)
99
+ content:
100
+ application/json:
101
+ schema:
102
+ $ref: '#/components/schemas/ErrorResponse'
103
+ examples:
104
+ missingToken:
105
+ summary: Missing JWT token
106
+ value:
107
+ error: "Unauthorized"
108
+ message: "Missing or invalid authentication token"
109
+ status_code: 401
110
+ userIdMismatch:
111
+ summary: User ID mismatch
112
+ value:
113
+ error: "Unauthorized"
114
+ message: "User ID in path does not match authenticated user"
115
+ status_code: 401
116
+ '429':
117
+ description: Rate limit exceeded (AI provider rate limit)
118
+ content:
119
+ application/json:
120
+ schema:
121
+ $ref: '#/components/schemas/ErrorResponse'
122
+ examples:
123
+ rateLimitExceeded:
124
+ summary: Rate limit error
125
+ value:
126
+ error: "Rate Limit Exceeded"
127
+ message: "AI provider rate limit reached. Please wait a moment and try again."
128
+ status_code: 429
129
+ retry_after: 60
130
+ '500':
131
+ description: Internal server error
132
+ content:
133
+ application/json:
134
+ schema:
135
+ $ref: '#/components/schemas/ErrorResponse'
136
+ examples:
137
+ aiProviderError:
138
+ summary: AI provider error
139
+ value:
140
+ error: "Internal Server Error"
141
+ message: "Failed to generate AI response. Please try again."
142
+ status_code: 500
143
+
144
+ /api/{user_id}/conversations:
145
+ get:
146
+ tags:
147
+ - chat
148
+ summary: List user conversations
149
+ description: |
150
+ Retrieve all conversations for the authenticated user.
151
+ Conversations are ordered by most recent activity.
152
+
153
+ **Note**: This endpoint is optional for Phase 1 and may be deferred to Phase 2.
154
+ operationId: listConversations
155
+ parameters:
156
+ - name: user_id
157
+ in: path
158
+ required: true
159
+ description: Authenticated user ID
160
+ schema:
161
+ type: integer
162
+ example: 123
163
+ - name: limit
164
+ in: query
165
+ required: false
166
+ description: Maximum number of conversations to return
167
+ schema:
168
+ type: integer
169
+ default: 20
170
+ minimum: 1
171
+ maximum: 100
172
+ - name: offset
173
+ in: query
174
+ required: false
175
+ description: Number of conversations to skip (for pagination)
176
+ schema:
177
+ type: integer
178
+ default: 0
179
+ minimum: 0
180
+ security:
181
+ - BearerAuth: []
182
+ responses:
183
+ '200':
184
+ description: List of conversations
185
+ content:
186
+ application/json:
187
+ schema:
188
+ $ref: '#/components/schemas/ConversationListResponse'
189
+ '401':
190
+ description: Unauthorized
191
+ content:
192
+ application/json:
193
+ schema:
194
+ $ref: '#/components/schemas/ErrorResponse'
195
+
196
+ components:
197
+ securitySchemes:
198
+ BearerAuth:
199
+ type: http
200
+ scheme: bearer
201
+ bearerFormat: JWT
202
+ description: |
203
+ JWT token issued by Better Auth.
204
+ Include in Authorization header as: `Bearer <token>`
205
+
206
+ schemas:
207
+ ChatRequest:
208
+ type: object
209
+ required:
210
+ - message
211
+ properties:
212
+ message:
213
+ type: string
214
+ description: User message content
215
+ minLength: 1
216
+ maxLength: 10000
217
+ example: "Hello, can you help me with my tasks?"
218
+ conversation_id:
219
+ type: integer
220
+ description: |
221
+ Optional conversation ID to continue an existing conversation.
222
+ If not provided, the most recent conversation will be used or a new one created.
223
+ example: 456
224
+ example:
225
+ message: "I need to add a new task for tomorrow"
226
+
227
+ ChatResponse:
228
+ type: object
229
+ required:
230
+ - response
231
+ - conversation_id
232
+ - timestamp
233
+ properties:
234
+ response:
235
+ type: string
236
+ description: AI assistant response
237
+ example: "Hello! I'm your AI assistant. How can I help you today?"
238
+ conversation_id:
239
+ type: integer
240
+ description: Conversation ID for this exchange
241
+ example: 456
242
+ timestamp:
243
+ type: string
244
+ format: date-time
245
+ description: Response timestamp (ISO 8601)
246
+ example: "2026-01-14T10:30:00Z"
247
+ metadata:
248
+ type: object
249
+ description: Optional metadata about the response
250
+ properties:
251
+ model:
252
+ type: string
253
+ description: AI model used for response
254
+ example: "gemini-pro"
255
+ token_count:
256
+ type: integer
257
+ description: Estimated token count for this exchange
258
+ example: 150
259
+ example:
260
+ response: "I understand you want to add a task. Task management will be available in Phase 2!"
261
+ conversation_id: 456
262
+ timestamp: "2026-01-14T10:30:00Z"
263
+
264
+ ConversationListResponse:
265
+ type: object
266
+ required:
267
+ - conversations
268
+ - total
269
+ properties:
270
+ conversations:
271
+ type: array
272
+ items:
273
+ $ref: '#/components/schemas/ConversationSummary'
274
+ total:
275
+ type: integer
276
+ description: Total number of conversations for this user
277
+ example: 5
278
+ limit:
279
+ type: integer
280
+ description: Limit applied to this request
281
+ example: 20
282
+ offset:
283
+ type: integer
284
+ description: Offset applied to this request
285
+ example: 0
286
+
287
+ ConversationSummary:
288
+ type: object
289
+ required:
290
+ - id
291
+ - created_at
292
+ - updated_at
293
+ - message_count
294
+ properties:
295
+ id:
296
+ type: integer
297
+ description: Conversation ID
298
+ example: 456
299
+ title:
300
+ type: string
301
+ description: Optional conversation title
302
+ example: "Task Planning Discussion"
303
+ created_at:
304
+ type: string
305
+ format: date-time
306
+ description: Conversation creation timestamp
307
+ example: "2026-01-14T10:00:00Z"
308
+ updated_at:
309
+ type: string
310
+ format: date-time
311
+ description: Last message timestamp
312
+ example: "2026-01-14T10:30:00Z"
313
+ message_count:
314
+ type: integer
315
+ description: Number of messages in this conversation
316
+ example: 10
317
+ last_message_preview:
318
+ type: string
319
+ description: Preview of the last message (first 100 characters)
320
+ example: "I understand you want to add a task. Task management will be available in Phase 2!"
321
+
322
+ ErrorResponse:
323
+ type: object
324
+ required:
325
+ - error
326
+ - message
327
+ - status_code
328
+ properties:
329
+ error:
330
+ type: string
331
+ description: Error type
332
+ example: "Bad Request"
333
+ message:
334
+ type: string
335
+ description: Human-readable error message
336
+ example: "Message content cannot be empty"
337
+ status_code:
338
+ type: integer
339
+ description: HTTP status code
340
+ example: 400
341
+ details:
342
+ type: object
343
+ description: Optional additional error details
344
+ additionalProperties: true
345
+ retry_after:
346
+ type: integer
347
+ description: Seconds to wait before retrying (for rate limit errors)
348
+ example: 60
349
+ example:
350
+ error: "Rate Limit Exceeded"
351
+ message: "AI provider rate limit reached. Please wait a moment and try again."
352
+ status_code: 429
353
+ retry_after: 60
354
+
355
+ examples:
356
+ ChatRequestExample:
357
+ value:
358
+ message: "Hello, can you help me with my tasks?"
359
+
360
+ ChatResponseExample:
361
+ value:
362
+ response: "Hello! I'm your AI assistant. I can help you manage your tasks through natural conversation. What would you like to do?"
363
+ conversation_id: 456
364
+ timestamp: "2026-01-14T10:30:00Z"
specs/001-todo-ai-chatbot/data-model.md ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Model: Todo AI Chatbot - Phase 1
2
+
3
+ **Feature**: 001-todo-ai-chatbot
4
+ **Date**: 2026-01-14
5
+ **Phase**: Phase 1 - Design & Contracts
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ This document defines the database schema for the Todo AI Chatbot feature. The data model supports stateless conversational AI with database-persisted state, enabling conversation continuity across page refreshes and server restarts.
12
+
13
+ ---
14
+
15
+ ## Entity Relationship Diagram
16
+
17
+ ```
18
+ ┌─────────────┐
19
+ │ User │
20
+ │ (existing) │
21
+ └──────┬──────┘
22
+ │ 1
23
+
24
+ │ N
25
+ ┌──────▼──────────────┐
26
+ │ Conversation │
27
+ │ │
28
+ │ - id (PK) │
29
+ │ - user_id (FK) │
30
+ │ - created_at │
31
+ │ - updated_at │
32
+ │ - title (optional) │
33
+ └──────┬──────────────┘
34
+ │ 1
35
+
36
+ │ N
37
+ ┌──────▼──────────────┐
38
+ │ Message │
39
+ │ │
40
+ │ - id (PK) │
41
+ │ - conversation_id │
42
+ │ - role │
43
+ │ - content │
44
+ │ - timestamp │
45
+ │ - token_count │
46
+ └─────────────────────┘
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Entities
52
+
53
+ ### 1. Conversation
54
+
55
+ **Purpose**: Represents a conversation session between a user and the AI assistant.
56
+
57
+ **Table Name**: `conversation`
58
+
59
+ **Attributes**:
60
+
61
+ | Field | Type | Constraints | Description |
62
+ |-------|------|-------------|-------------|
63
+ | `id` | Integer | PRIMARY KEY, AUTO_INCREMENT | Unique conversation identifier |
64
+ | `user_id` | Integer | FOREIGN KEY (user.id), NOT NULL, INDEX | Reference to authenticated user |
65
+ | `created_at` | DateTime | NOT NULL, DEFAULT NOW() | Conversation creation timestamp |
66
+ | `updated_at` | DateTime | NOT NULL, DEFAULT NOW(), ON UPDATE NOW() | Last message timestamp |
67
+ | `title` | String(255) | NULLABLE | Optional conversation title (for future UI) |
68
+
69
+ **Relationships**:
70
+ - **User**: Many-to-One (Many conversations belong to one user)
71
+ - **Message**: One-to-Many (One conversation has many messages)
72
+
73
+ **Indexes**:
74
+ - PRIMARY KEY on `id`
75
+ - INDEX on `user_id` (for efficient user conversation queries)
76
+ - INDEX on `updated_at` (for sorting by recency)
77
+
78
+ **Validation Rules**:
79
+ - `user_id` must reference an existing user
80
+ - `created_at` must be <= `updated_at`
81
+ - `title` max length: 255 characters
82
+
83
+ **State Transitions**: None (conversations are created and persist indefinitely)
84
+
85
+ **SQLModel Implementation**:
86
+ ```python
87
+ from sqlmodel import SQLModel, Field, Relationship
88
+ from datetime import datetime
89
+ from typing import List, Optional
90
+
91
+ class Conversation(SQLModel, table=True):
92
+ __tablename__ = "conversation"
93
+
94
+ id: Optional[int] = Field(default=None, primary_key=True)
95
+ user_id: int = Field(foreign_key="user.id", index=True)
96
+ created_at: datetime = Field(default_factory=datetime.utcnow)
97
+ updated_at: datetime = Field(
98
+ default_factory=datetime.utcnow,
99
+ sa_column_kwargs={"onupdate": datetime.utcnow}
100
+ )
101
+ title: Optional[str] = Field(default=None, max_length=255)
102
+
103
+ # Relationships
104
+ messages: List["Message"] = Relationship(
105
+ back_populates="conversation",
106
+ sa_relationship_kwargs={"cascade": "all, delete-orphan"}
107
+ )
108
+ ```
109
+
110
+ ---
111
+
112
+ ### 2. Message
113
+
114
+ **Purpose**: Represents an individual message within a conversation (user or assistant).
115
+
116
+ **Table Name**: `message`
117
+
118
+ **Attributes**:
119
+
120
+ | Field | Type | Constraints | Description |
121
+ |-------|------|-------------|-------------|
122
+ | `id` | Integer | PRIMARY KEY, AUTO_INCREMENT | Unique message identifier |
123
+ | `conversation_id` | Integer | FOREIGN KEY (conversation.id), NOT NULL, INDEX | Reference to parent conversation |
124
+ | `role` | String(20) | NOT NULL, CHECK IN ('user', 'assistant') | Message sender role |
125
+ | `content` | Text | NOT NULL | Message content (unlimited length) |
126
+ | `timestamp` | DateTime | NOT NULL, DEFAULT NOW() | Message creation timestamp |
127
+ | `token_count` | Integer | NULLABLE | Estimated token count (for context management) |
128
+
129
+ **Relationships**:
130
+ - **Conversation**: Many-to-One (Many messages belong to one conversation)
131
+
132
+ **Indexes**:
133
+ - PRIMARY KEY on `id`
134
+ - INDEX on `conversation_id` (for efficient conversation message queries)
135
+ - INDEX on `timestamp` (for chronological ordering)
136
+ - COMPOSITE INDEX on `(conversation_id, timestamp)` (for efficient conversation history retrieval)
137
+
138
+ **Validation Rules**:
139
+ - `conversation_id` must reference an existing conversation
140
+ - `role` must be either 'user' or 'assistant'
141
+ - `content` must not be empty (min length: 1 character)
142
+ - `token_count` must be >= 0 if provided
143
+
144
+ **State Transitions**: None (messages are immutable once created)
145
+
146
+ **SQLModel Implementation**:
147
+ ```python
148
+ from sqlmodel import SQLModel, Field, Relationship
149
+ from datetime import datetime
150
+ from typing import Optional
151
+
152
+ class Message(SQLModel, table=True):
153
+ __tablename__ = "message"
154
+
155
+ id: Optional[int] = Field(default=None, primary_key=True)
156
+ conversation_id: int = Field(
157
+ foreign_key="conversation.id",
158
+ index=True
159
+ )
160
+ role: str = Field(max_length=20)
161
+ content: str = Field(sa_column=Column(Text))
162
+ timestamp: datetime = Field(default_factory=datetime.utcnow, index=True)
163
+ token_count: Optional[int] = Field(default=None, ge=0)
164
+
165
+ # Relationships
166
+ conversation: Conversation = Relationship(back_populates="messages")
167
+
168
+ # Validation
169
+ @validator("role")
170
+ def validate_role(cls, v):
171
+ if v not in ["user", "assistant"]:
172
+ raise ValueError("role must be 'user' or 'assistant'")
173
+ return v
174
+
175
+ @validator("content")
176
+ def validate_content(cls, v):
177
+ if not v or len(v.strip()) == 0:
178
+ raise ValueError("content must not be empty")
179
+ return v
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Database Constraints
185
+
186
+ ### Foreign Key Constraints
187
+
188
+ 1. **Conversation.user_id → User.id**
189
+ - ON DELETE: CASCADE (delete conversations when user is deleted)
190
+ - ON UPDATE: CASCADE
191
+
192
+ 2. **Message.conversation_id → Conversation.id**
193
+ - ON DELETE: CASCADE (delete messages when conversation is deleted)
194
+ - ON UPDATE: CASCADE
195
+
196
+ ### Check Constraints
197
+
198
+ 1. **Message.role**: Must be 'user' or 'assistant'
199
+ 2. **Message.token_count**: Must be >= 0 if not NULL
200
+ 3. **Conversation.created_at**: Must be <= updated_at
201
+
202
+ ---
203
+
204
+ ## Migration Strategy
205
+
206
+ ### Initial Migration (Phase 1)
207
+
208
+ **Migration File**: `backend/alembic/versions/001_add_conversation_tables.py`
209
+
210
+ **Operations**:
211
+ 1. Create `conversation` table
212
+ 2. Create `message` table
213
+ 3. Add foreign key constraints
214
+ 4. Add indexes
215
+ 5. Add check constraints
216
+
217
+ **Rollback Strategy**:
218
+ 1. Drop `message` table (cascade will handle foreign keys)
219
+ 2. Drop `conversation` table
220
+
221
+ **SQL Preview**:
222
+ ```sql
223
+ -- Create conversation table
224
+ CREATE TABLE conversation (
225
+ id SERIAL PRIMARY KEY,
226
+ user_id INTEGER NOT NULL REFERENCES user(id) ON DELETE CASCADE,
227
+ created_at TIMESTAMP NOT NULL DEFAULT NOW(),
228
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
229
+ title VARCHAR(255),
230
+ CONSTRAINT check_conversation_dates CHECK (created_at <= updated_at)
231
+ );
232
+
233
+ CREATE INDEX idx_conversation_user_id ON conversation(user_id);
234
+ CREATE INDEX idx_conversation_updated_at ON conversation(updated_at);
235
+
236
+ -- Create message table
237
+ CREATE TABLE message (
238
+ id SERIAL PRIMARY KEY,
239
+ conversation_id INTEGER NOT NULL REFERENCES conversation(id) ON DELETE CASCADE,
240
+ role VARCHAR(20) NOT NULL CHECK (role IN ('user', 'assistant')),
241
+ content TEXT NOT NULL,
242
+ timestamp TIMESTAMP NOT NULL DEFAULT NOW(),
243
+ token_count INTEGER CHECK (token_count >= 0),
244
+ CONSTRAINT check_message_content CHECK (LENGTH(TRIM(content)) > 0)
245
+ );
246
+
247
+ CREATE INDEX idx_message_conversation_id ON message(conversation_id);
248
+ CREATE INDEX idx_message_timestamp ON message(timestamp);
249
+ CREATE INDEX idx_message_conversation_timestamp ON message(conversation_id, timestamp);
250
+ ```
251
+
252
+ ---
253
+
254
+ ## Data Access Patterns
255
+
256
+ ### 1. Create New Conversation
257
+
258
+ **Use Case**: User starts a new chat session
259
+
260
+ **Query Pattern**:
261
+ ```python
262
+ conversation = Conversation(user_id=user_id)
263
+ session.add(conversation)
264
+ session.commit()
265
+ session.refresh(conversation)
266
+ ```
267
+
268
+ **Performance**: O(1) - Single INSERT
269
+
270
+ ---
271
+
272
+ ### 2. Get or Create Conversation
273
+
274
+ **Use Case**: Chat endpoint retrieves or creates conversation for user
275
+
276
+ **Query Pattern**:
277
+ ```python
278
+ conversation = session.exec(
279
+ select(Conversation)
280
+ .where(Conversation.user_id == user_id)
281
+ .order_by(Conversation.updated_at.desc())
282
+ ).first()
283
+
284
+ if not conversation:
285
+ conversation = Conversation(user_id=user_id)
286
+ session.add(conversation)
287
+ session.commit()
288
+ ```
289
+
290
+ **Performance**: O(1) with index on user_id
291
+
292
+ ---
293
+
294
+ ### 3. Load Conversation History
295
+
296
+ **Use Case**: Load all messages for a conversation (for AI context)
297
+
298
+ **Query Pattern**:
299
+ ```python
300
+ messages = session.exec(
301
+ select(Message)
302
+ .where(Message.conversation_id == conversation_id)
303
+ .order_by(Message.timestamp.asc())
304
+ ).all()
305
+ ```
306
+
307
+ **Performance**: O(N) where N = number of messages, optimized by composite index
308
+
309
+ ---
310
+
311
+ ### 4. Add Message to Conversation
312
+
313
+ **Use Case**: Save user or assistant message
314
+
315
+ **Query Pattern**:
316
+ ```python
317
+ message = Message(
318
+ conversation_id=conversation_id,
319
+ role=role,
320
+ content=content,
321
+ token_count=estimate_tokens(content)
322
+ )
323
+ session.add(message)
324
+
325
+ # Update conversation timestamp
326
+ conversation.updated_at = datetime.utcnow()
327
+ session.add(conversation)
328
+
329
+ session.commit()
330
+ ```
331
+
332
+ **Performance**: O(1) - Two UPDATEs
333
+
334
+ ---
335
+
336
+ ### 5. Trim Old Messages (Future Enhancement)
337
+
338
+ **Use Case**: Delete old messages to manage database size
339
+
340
+ **Query Pattern**:
341
+ ```python
342
+ # Keep only last N messages per conversation
343
+ subquery = (
344
+ select(Message.id)
345
+ .where(Message.conversation_id == conversation_id)
346
+ .order_by(Message.timestamp.desc())
347
+ .limit(MAX_MESSAGES)
348
+ )
349
+
350
+ session.exec(
351
+ delete(Message)
352
+ .where(Message.conversation_id == conversation_id)
353
+ .where(Message.id.not_in(subquery))
354
+ )
355
+ ```
356
+
357
+ **Performance**: O(N) where N = total messages in conversation
358
+
359
+ ---
360
+
361
+ ## Data Retention Policy
362
+
363
+ ### Phase 1 (Current)
364
+
365
+ - **Conversations**: Retained indefinitely
366
+ - **Messages**: Retained indefinitely
367
+ - **Rationale**: Hackathon scope; no retention policy needed
368
+
369
+ ### Phase 2 (Future Consideration)
370
+
371
+ - **Conversations**: Retain for 90 days of inactivity
372
+ - **Messages**: Retain last 100 messages per conversation
373
+ - **Archived Data**: Move to cold storage after 1 year
374
+
375
+ ---
376
+
377
+ ## Scalability Considerations
378
+
379
+ ### Current Scale (Phase 1)
380
+
381
+ - **Expected Users**: 10-100 (hackathon scope)
382
+ - **Expected Conversations**: 100-1,000
383
+ - **Expected Messages**: 1,000-10,000
384
+ - **Database Size**: <10 MB
385
+
386
+ ### Future Scale (Phase 2+)
387
+
388
+ - **Target Users**: 10,000+
389
+ - **Target Conversations**: 100,000+
390
+ - **Target Messages**: 1,000,000+
391
+ - **Database Size**: 1-10 GB
392
+
393
+ ### Optimization Strategies
394
+
395
+ 1. **Partitioning**: Partition `message` table by `conversation_id` or `timestamp`
396
+ 2. **Archiving**: Move old messages to archive table
397
+ 3. **Caching**: Cache recent conversation history in Redis
398
+ 4. **Read Replicas**: Use read replicas for conversation history queries
399
+
400
+ ---
401
+
402
+ ## Security Considerations
403
+
404
+ ### Data Access Control
405
+
406
+ 1. **User Isolation**: All queries MUST filter by authenticated `user_id`
407
+ 2. **JWT Verification**: Backend MUST verify JWT before accessing conversation data
408
+ 3. **Authorization**: Users can only access their own conversations and messages
409
+
410
+ ### Data Privacy
411
+
412
+ 1. **PII Handling**: Message content may contain PII; treat as sensitive data
413
+ 2. **Encryption**: Database connection MUST use SSL/TLS
414
+ 3. **Audit Logging**: Log all conversation access for security auditing (future)
415
+
416
+ ### SQL Injection Prevention
417
+
418
+ 1. **Parameterized Queries**: SQLModel uses parameterized queries by default
419
+ 2. **Input Validation**: Validate all user inputs before database operations
420
+ 3. **ORM Usage**: Use SQLModel ORM; avoid raw SQL queries
421
+
422
+ ---
423
+
424
+ ## Testing Strategy
425
+
426
+ ### Unit Tests
427
+
428
+ 1. **Model Validation**: Test Conversation and Message model validation rules
429
+ 2. **Relationship Tests**: Test cascade deletes and foreign key constraints
430
+ 3. **Timestamp Tests**: Test created_at and updated_at behavior
431
+
432
+ ### Integration Tests
433
+
434
+ 1. **CRUD Operations**: Test create, read, update, delete for both entities
435
+ 2. **Query Performance**: Test query performance with sample data
436
+ 3. **Constraint Enforcement**: Test foreign key and check constraints
437
+
438
+ ### Test Data
439
+
440
+ ```python
441
+ # Sample test data
442
+ test_user_id = 1
443
+
444
+ test_conversation = Conversation(
445
+ user_id=test_user_id,
446
+ title="Test Conversation"
447
+ )
448
+
449
+ test_messages = [
450
+ Message(
451
+ conversation_id=test_conversation.id,
452
+ role="user",
453
+ content="Hello, AI assistant!"
454
+ ),
455
+ Message(
456
+ conversation_id=test_conversation.id,
457
+ role="assistant",
458
+ content="Hello! How can I help you today?"
459
+ )
460
+ ]
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Summary
466
+
467
+ This data model provides:
468
+
469
+ ✅ **Stateless Architecture**: All state persisted to database
470
+ ✅ **Conversation Continuity**: History survives page refreshes and server restarts
471
+ ✅ **User Isolation**: Conversations scoped to authenticated users
472
+ ✅ **Scalability**: Indexed for efficient queries
473
+ ✅ **Simplicity**: Minimal schema for Phase 1 requirements
474
+ ✅ **Extensibility**: Easy to add fields for Phase 2 (e.g., tool calls, metadata)
475
+
476
+ **Next Steps**: Create API contracts (contracts/chat-api.yaml)
specs/001-todo-ai-chatbot/plan.md ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Plan: Todo AI Chatbot - Phase 1
2
+
3
+ **Branch**: `001-todo-ai-chatbot` | **Date**: 2026-01-14 | **Spec**: [spec.md](./spec.md)
4
+ **Input**: Feature specification from `/specs/001-todo-ai-chatbot/spec.md`
5
+
6
+ **Note**: This template is filled in by the `/sp.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
7
+
8
+ ## Summary
9
+
10
+ Build a conversational AI chatbot interface that enables users to interact with an AI assistant through natural language. This Phase 1 implementation focuses on establishing the chat UI, basic agent wiring, and conversation persistence, while explicitly deferring MCP tool execution and task CRUD operations to Spec-2. The system must work with free-tier AI API providers and maintain stateless backend architecture with database-persisted conversation state.
11
+
12
+ ## Technical Context
13
+
14
+ **Language/Version**: Python 3.11+ (backend), TypeScript/JavaScript (frontend with Next.js 16+)
15
+ **Primary Dependencies**:
16
+ - Backend: FastAPI, SQLModel, OpenAI Agents SDK (or compatible abstraction), Pydantic
17
+ - Frontend: Next.js 16+ (App Router), OpenAI ChatKit, React, Tailwind CSS
18
+ - Database: Neon Serverless PostgreSQL
19
+ - Authentication: Better Auth (JWT tokens)
20
+
21
+ **Storage**: Neon PostgreSQL (conversation and message persistence via SQLModel)
22
+ **Testing**: pytest (backend), Jest/React Testing Library (frontend - NEEDS CLARIFICATION on existing setup)
23
+ **Target Platform**: Web application (desktop and mobile responsive)
24
+ **Project Type**: Web (frontend + backend monorepo structure)
25
+ **Performance Goals**:
26
+ - <5 seconds AI response time under normal conditions
27
+ - Free-tier API compatibility (Gemini, OpenRouter, Cohere)
28
+ - Conversation history persistence with <1 second load time
29
+
30
+ **Constraints**:
31
+ - Stateless backend (no in-memory session storage)
32
+ - Free-tier API rate limits (aggressive context trimming required)
33
+ - No MCP tool execution in Phase 1 (deferred to Spec-2)
34
+ - No task CRUD operations in Phase 1 (deferred to Spec-2)
35
+ - Must preserve existing folder structure (frontend/, backend/)
36
+ - Must work with at least 3 free-tier AI providers
37
+
38
+ **Scale/Scope**:
39
+ - Hackathon project (Phase III of multi-phase development)
40
+ - Single-user conversations (multi-user via JWT authentication)
41
+ - 10+ message conversation history support
42
+ - Foundation for Spec-2 MCP integration
43
+
44
+ ## Constitution Check
45
+
46
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
47
+
48
+ ### Phase II Core Principles Compliance
49
+
50
+ | Principle | Status | Notes |
51
+ |-----------|--------|-------|
52
+ | **User-Centric Functionality** | ✅ PASS | Chat interface provides clear UX for natural language interaction; conversation persistence ensures data security |
53
+ | **Spec-Driven Development** | ✅ PASS | Following Spec-Kit Plus workflow; spec.md approved; plan.md in progress; tasks.md will follow |
54
+ | **Security & Data Privacy** | ✅ PASS | JWT authentication required for chat endpoint; user_id extracted from token; conversation data filtered by authenticated user |
55
+ | **Scalable Architecture** | ✅ PASS | Stateless API design; database-persisted state; no server-side sessions; horizontal scaling ready |
56
+ | **Maintainable & Consistent Code** | ✅ PASS | Following Next.js App Router patterns; FastAPI + SQLModel standards; Tailwind CSS for styling |
57
+
58
+ ### Phase III Constitutional Compliance
59
+
60
+ | Requirement | Status | Notes |
61
+ |-------------|--------|-------|
62
+ | **Mandatory Development Framework** | ✅ PASS | Using Agentic Dev Stack, Spec-Kit Plus, Claude Code with agent-skill alignment |
63
+ | **Stateless FastAPI Backend** | ✅ PASS | POST /api/{user_id}/chat endpoint is stateless; no in-memory session storage |
64
+ | **MCP Server Implementation** | ⚠️ DEFERRED | Explicitly deferred to Spec-2 per feature scope; Phase 1 establishes foundation only |
65
+ | **OpenAI Agents SDK** | ✅ PASS | Will be used for agent reasoning and orchestration (NEEDS CLARIFICATION on specific SDK choice) |
66
+ | **Database-Persisted State** | ✅ PASS | Conversation and Message models persist all state to Neon PostgreSQL |
67
+ | **ChatKit UI** | ✅ PASS | OpenAI ChatKit will be the sole frontend interface for Phase 1 |
68
+ | **Agent & Skill Governance** | ✅ PASS | Conversational AI Architect Agent (agent-behavior-reasoning) and Backend Systems Agent (backend-mcp-tools) will be used |
69
+ | **Stateless Request Cycle** | ✅ PASS | Load history → Execute agent → Store messages → Return response cycle implemented |
70
+ | **Server Restart Resilience** | ✅ PASS | All state persisted to database; no data loss on server restart |
71
+ | **Conversation Continuity** | ✅ PASS | Conversation history persists across page refreshes and server restarts |
72
+
73
+ ### Key Standards Compliance
74
+
75
+ | Standard | Status | Notes |
76
+ |----------|--------|-------|
77
+ | **API Compliance** | ✅ PASS | POST /api/{user_id}/chat endpoint; JSON responses; Pydantic validation; error handling |
78
+ | **Database Integrity** | ✅ PASS | Conversation and Message models with foreign keys; SQLModel ORM; migrations tracked |
79
+ | **Frontend Quality** | ✅ PASS | Next.js App Router; responsive design; Tailwind CSS; proper client/server separation |
80
+ | **Authentication** | ✅ PASS | Better Auth JWT tokens; Authorization header; backend JWT verification |
81
+ | **Spec Adherence** | ✅ PASS | All implementation references specs/001-todo-ai-chatbot/ |
82
+
83
+ ### Constitutional Violations Requiring Justification
84
+
85
+ **None identified.** All constitutional requirements are met or explicitly deferred per approved scope boundaries.
86
+
87
+ ## Project Structure
88
+
89
+ ### Documentation (this feature)
90
+
91
+ ```text
92
+ specs/001-todo-ai-chatbot/
93
+ ├── spec.md # Feature specification (COMPLETED)
94
+ ├── plan.md # This file (/sp.plan command output - IN PROGRESS)
95
+ ├── research.md # Phase 0 output (/sp.plan command - PENDING)
96
+ ├── data-model.md # Phase 1 output (/sp.plan command - PENDING)
97
+ ├── quickstart.md # Phase 1 output (/sp.plan command - PENDING)
98
+ ├── contracts/ # Phase 1 output (/sp.plan command - PENDING)
99
+ │ └── chat-api.yaml # OpenAPI spec for chat endpoint
100
+ └── tasks.md # Phase 2 output (/sp.tasks command - NOT created by /sp.plan)
101
+ ```
102
+
103
+ ### Source Code (repository root)
104
+
105
+ ```text
106
+ backend/
107
+ ├── src/
108
+ │ ├── models/
109
+ │ │ ├── conversation.py # NEW: Conversation SQLModel
110
+ │ │ └── message.py # NEW: Message SQLModel
111
+ │ ├── services/
112
+ │ │ ├── agent_runner.py # NEW: AI agent orchestration service
113
+ │ │ └── conversation_service.py # NEW: Conversation management service
114
+ │ ├── api/
115
+ │ │ └── chat.py # NEW: POST /api/{user_id}/chat endpoint
116
+ │ ├── schemas/
117
+ │ │ ├── chat_request.py # NEW: Pydantic request schema
118
+ │ │ └── chat_response.py # NEW: Pydantic response schema
119
+ │ └── core/
120
+ │ └── config.py # MODIFY: Add AI provider config
121
+ ├── tests/
122
+ │ ├── unit/
123
+ │ │ ├── test_conversation_service.py # NEW
124
+ │ │ └── test_agent_runner.py # NEW
125
+ │ └── integration/
126
+ │ └── test_chat_api.py # NEW
127
+ └── requirements.txt # MODIFY: Add OpenAI SDK, ChatKit dependencies
128
+
129
+ frontend/
130
+ ├── src/
131
+ │ ├── app/
132
+ │ │ └── chat/
133
+ │ │ └── page.tsx # NEW: Chat page (App Router)
134
+ │ ├── components/
135
+ │ │ ├── chat/
136
+ │ │ │ ├── ChatInterface.tsx # NEW: Main chat component
137
+ │ │ │ ├── MessageList.tsx # NEW: Message display
138
+ │ │ │ ├── MessageInput.tsx # NEW: Input field
139
+ │ │ │ └── TypingIndicator.tsx # NEW: Loading state
140
+ │ │ └── ui/ # Existing UI components
141
+ │ ├── services/
142
+ │ │ └── chatService.ts # NEW: API client for chat endpoint
143
+ │ └── types/
144
+ │ └── chat.ts # NEW: TypeScript types for chat
145
+ ├── tests/
146
+ │ └── components/
147
+ │ └── chat/
148
+ │ └── ChatInterface.test.tsx # NEW
149
+ └── package.json # MODIFY: Add ChatKit dependency
150
+ ```
151
+
152
+ **Structure Decision**: Web application structure (Option 2) selected. This is a monorepo with separate `backend/` and `frontend/` directories. All new chat-related code will be added within these existing directories, preserving the current folder structure as required by constraints TC-001, TC-002, and TC-003.
153
+
154
+ ## Complexity Tracking
155
+
156
+ > **Fill ONLY if Constitution Check has violations that must be justified**
157
+
158
+ **No violations identified.** All constitutional requirements are satisfied or explicitly deferred per approved scope boundaries. No complexity justification required.
159
+
160
+ ---
161
+
162
+ ## Phase 0: Research & Clarifications
163
+
164
+ ### Unknowns Requiring Research
165
+
166
+ Based on Technical Context analysis, the following items require clarification:
167
+
168
+ 1. **Frontend Testing Setup**: Current testing framework and configuration for frontend
169
+ 2. **AI Agent SDK Selection**: Specific SDK/abstraction for agent implementation (OpenAI Agents SDK vs alternatives)
170
+ 3. **OpenAI ChatKit Compatibility**: Verify ChatKit compatibility with Next.js 16+ App Router
171
+ 4. **Free-Tier AI Provider Integration**: Best practices for Gemini, OpenRouter, Cohere integration
172
+ 5. **Conversation History Trimming Strategy**: Algorithm for context window management with free-tier limits
173
+
174
+ ### Research Tasks
175
+
176
+ ✅ **COMPLETED** - See `research.md` for detailed findings.
177
+
178
+ **Key Decisions**:
179
+ 1. **AI Agent SDK**: Custom implementation with direct API calls (fastest, stateless, free-tier compatible)
180
+ 2. **Chat UI Library**: @assistant-ui/react (Next.js native, no CDN dependencies)
181
+ 3. **Primary AI Provider**: Google Gemini (gemini-pro) with OpenRouter fallback
182
+ 4. **History Trimming**: Hybrid approach (max 20 messages + 8000 token budget)
183
+
184
+ ---
185
+
186
+ ## Phase 1: Architectural Design
187
+
188
+ ### Technology Stack (Finalized)
189
+
190
+ | Layer | Technology | Version | Rationale |
191
+ |-------|-----------|---------|-----------|
192
+ | **Frontend Framework** | Next.js | 16+ | Existing stack, App Router support |
193
+ | **Chat UI Library** | @assistant-ui/react | Latest | Next.js native, Tailwind integration, no CDN |
194
+ | **Frontend State** | Vercel AI SDK | Latest | Streaming, React hooks, tool call support |
195
+ | **Backend Framework** | FastAPI | 0.104.1 | Existing stack, async support |
196
+ | **AI Provider** | Google Gemini | gemini-pro | Best free-tier (60 req/min, 32k context) |
197
+ | **AI Implementation** | Custom | N/A | Stateless, simple, fast, provider-agnostic |
198
+ | **Database** | Neon PostgreSQL | N/A | Existing stack, serverless |
199
+ | **ORM** | SQLModel | 0.0.14 | Existing stack, type-safe |
200
+ | **Authentication** | Better Auth | 1.0.0 | Existing stack, JWT tokens |
201
+
202
+ ### Backend Architecture
203
+
204
+ **AI Agent Implementation**:
205
+ - Custom implementation with provider abstraction pattern
206
+ - `LLMProvider` abstract base class for multi-provider support
207
+ - `GeminiProvider`, `OpenRouterProvider`, `CohereProvider` implementations
208
+ - `LLMService` factory for provider selection via environment variable
209
+
210
+ **Conversation Management**:
211
+ - Stateless request cycle: Load history → Execute agent → Save messages → Return response
212
+ - Database-persisted state (no in-memory sessions)
213
+ - `ConversationService` handles CRUD operations for conversations and messages
214
+ - Automatic conversation creation on first user message
215
+
216
+ **Provider Configuration**:
217
+ - Environment-based provider selection (`AI_PROVIDER=gemini`)
218
+ - API keys stored in environment variables
219
+ - No code changes required to switch providers
220
+
221
+ **File Structure**:
222
+ ```
223
+ backend/src/
224
+ ├── models/
225
+ │ ├── conversation.py # Conversation SQLModel
226
+ │ └── message.py # Message SQLModel
227
+ ├── services/
228
+ │ ├── providers/
229
+ │ │ ├── base.py # LLMProvider abstract class
230
+ │ │ ├── gemini.py # Gemini implementation
231
+ │ │ └── openrouter.py # OpenRouter implementation (future)
232
+ │ ├── llm_service.py # LLM service with provider factory
233
+ │ └── conversation_service.py # Conversation management
234
+ ├── api/routes/
235
+ │ └── chat.py # POST /api/{user_id}/chat endpoint
236
+ └── schemas/
237
+ ├── chat_request.py # Pydantic request schema
238
+ └── chat_response.py # Pydantic response schema
239
+ ```
240
+
241
+ ### Frontend Architecture
242
+
243
+ **Chat UI Library**: @assistant-ui/react
244
+ - Chosen over OpenAI ChatKit due to Next.js App Router compatibility
245
+ - No CDN dependencies, pure React components
246
+ - Native Tailwind CSS integration
247
+ - Vercel AI SDK compatibility for streaming and tool calls
248
+
249
+ **Component Structure**:
250
+ ```
251
+ frontend/src/
252
+ ├── app/chat/
253
+ │ └── page.tsx # Chat page (App Router)
254
+ ├── components/chat/
255
+ │ ├── ChatInterface.tsx # Main chat component (client)
256
+ │ ├── MessageList.tsx # Message display
257
+ │ ├── MessageInput.tsx # Input field
258
+ │ └── TypingIndicator.tsx # Loading state
259
+ ├── services/
260
+ │ └── chatService.ts # API client for chat endpoint
261
+ └── types/
262
+ └── chat.ts # TypeScript types
263
+ ```
264
+
265
+ **State Management**:
266
+ - React hooks for local state (messages, loading)
267
+ - Vercel AI SDK `useChat` hook for advanced features
268
+ - Optimistic UI updates for better UX
269
+
270
+ ### Database Schema
271
+
272
+ **Conversation Model**:
273
+ - `id` (PK), `user_id` (FK), `created_at`, `updated_at`, `title` (optional)
274
+ - One-to-Many relationship with Message
275
+ - Indexed on `user_id` and `updated_at`
276
+
277
+ **Message Model**:
278
+ - `id` (PK), `conversation_id` (FK), `role`, `content`, `timestamp`, `token_count`
279
+ - Many-to-One relationship with Conversation
280
+ - Indexed on `conversation_id` and `timestamp`
281
+ - Composite index on `(conversation_id, timestamp)` for efficient history retrieval
282
+
283
+ **See `data-model.md` for complete schema details.**
284
+
285
+ ### API Design
286
+
287
+ **Primary Endpoint**: `POST /api/{user_id}/chat`
288
+ - Stateless endpoint for conversational AI interaction
289
+ - Requires JWT authentication (Bearer token)
290
+ - Request: `{ message: string, conversation_id?: number }`
291
+ - Response: `{ response: string, conversation_id: number, timestamp: string }`
292
+
293
+ **Error Handling**:
294
+ - 400: Bad request (empty message, invalid input)
295
+ - 401: Unauthorized (missing/invalid JWT, user_id mismatch)
296
+ - 429: Rate limit exceeded (AI provider rate limit)
297
+ - 500: Internal server error (AI provider failure)
298
+
299
+ **See `contracts/chat-api.yaml` for complete API specification.**
300
+
301
+ ### Conversation History Management
302
+
303
+ **Trimming Strategy**: Hybrid approach
304
+ - Keep last 20 messages (fixed count)
305
+ - Enforce 8000 token budget (conservative for free-tier)
306
+ - Trim from oldest messages if exceeding budget
307
+ - Simple token estimation: 1 token ≈ 4 characters
308
+
309
+ **Implementation**:
310
+ ```python
311
+ MAX_MESSAGES = 20
312
+ MAX_TOKENS = 8000
313
+
314
+ def trim_conversation_history(messages: List[Message]) -> List[Dict]:
315
+ recent_messages = messages[-MAX_MESSAGES:]
316
+ formatted = [{"role": m.role, "content": m.content} for m in recent_messages]
317
+
318
+ while estimate_tokens(formatted) > MAX_TOKENS and len(formatted) > 1:
319
+ formatted.pop(0)
320
+
321
+ return formatted
322
+ ```
323
+
324
+ ### Agent-Skill Alignment
325
+
326
+ **Agents Required**:
327
+
328
+ 1. **Conversational AI Architect Agent**
329
+ - **Skill**: `agent-behavior-reasoning`
330
+ - **Responsibilities**: Agent design, intent detection, response quality
331
+ - **Usage**: Design conversational flow, optimize AI responses
332
+
333
+ 2. **Backend Systems Agent**
334
+ - **Skill**: `backend-mcp-tools`
335
+ - **Responsibilities**: API implementation, database operations, provider integration
336
+ - **Usage**: Implement chat endpoint, conversation service, LLM service
337
+
338
+ 3. **Frontend UI Builder Agent** (Next.js)
339
+ - **Skill**: `nextjs-ui-generator`
340
+ - **Responsibilities**: Chat page, components, API integration
341
+ - **Usage**: Build chat interface, message components, API client
342
+
343
+ 4. **Design & Theme Agent**
344
+ - **Skill**: `design-theme`
345
+ - **Responsibilities**: Chat UI styling, visual consistency
346
+ - **Usage**: Apply Tailwind CSS styling, ensure responsive design
347
+
348
+ ### Security Considerations
349
+
350
+ **Authentication**:
351
+ - JWT token verification on all chat endpoints
352
+ - User ID in path must match authenticated user from JWT
353
+ - Unauthorized requests return 401
354
+
355
+ **Data Isolation**:
356
+ - All conversation queries filtered by authenticated `user_id`
357
+ - Users cannot access other users' conversations
358
+ - Database foreign keys enforce referential integrity
359
+
360
+ **Input Validation**:
361
+ - Message content: 1-10,000 characters
362
+ - Pydantic schemas validate all inputs
363
+ - SQLModel validators enforce data integrity
364
+
365
+ **API Security**:
366
+ - Rate limiting (future enhancement)
367
+ - CORS configuration for production
368
+ - Environment variables for secrets (never committed)
369
+
370
+ ---
371
+
372
+ ## Phase 2: Constitution Check (Post-Design)
373
+
374
+ ### Re-evaluation After Design
375
+
376
+ | Requirement | Status | Notes |
377
+ |-------------|--------|-------|
378
+ | **Stateless Backend** | ✅ PASS | Confirmed: Load history → Process → Save → Return pattern |
379
+ | **Database-Persisted State** | ✅ PASS | Confirmed: Conversation and Message models with proper relationships |
380
+ | **Free-Tier Compatibility** | ✅ PASS | Confirmed: Gemini primary (60 req/min), OpenRouter fallback |
381
+ | **Agent-Skill Alignment** | ✅ PASS | Confirmed: Conversational AI Architect, Backend Systems, Frontend UI Builder, Design & Theme |
382
+ | **Next.js App Router** | ✅ PASS | Confirmed: @assistant-ui/react compatible, no CDN dependencies |
383
+ | **JWT Authentication** | ✅ PASS | Confirmed: Bearer token verification, user_id validation |
384
+ | **Conversation Continuity** | ✅ PASS | Confirmed: History persists across page refreshes and server restarts |
385
+
386
+ **All constitutional requirements remain satisfied after architectural design.**
specs/001-todo-ai-chatbot/quickstart.md ADDED
@@ -0,0 +1,729 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quickstart Guide: Todo AI Chatbot - Phase 1
2
+
3
+ **Feature**: 001-todo-ai-chatbot
4
+ **Date**: 2026-01-14
5
+ **Audience**: Developers implementing this feature
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ This guide provides step-by-step instructions for implementing the Todo AI Chatbot Phase 1 feature. Follow these steps in order to build a working conversational AI interface with database-persisted state.
12
+
13
+ ---
14
+
15
+ ## Prerequisites
16
+
17
+ ### Required Tools
18
+
19
+ - Python 3.11+
20
+ - Node.js 18+
21
+ - PostgreSQL (Neon Serverless)
22
+ - Git
23
+
24
+ ### Required Access
25
+
26
+ - Google Gemini API key (free tier)
27
+ - Database connection string (Neon PostgreSQL)
28
+ - Better Auth configuration (existing)
29
+
30
+ ### Existing Infrastructure
31
+
32
+ - ✅ FastAPI backend running
33
+ - ✅ Next.js frontend running
34
+ - ✅ Database connectivity established
35
+ - ✅ Better Auth JWT authentication working
36
+
37
+ ---
38
+
39
+ ## Implementation Steps
40
+
41
+ ### Day 1: Backend Foundation
42
+
43
+ #### Step 1.1: Install Dependencies
44
+
45
+ ```bash
46
+ cd backend
47
+ ```
48
+
49
+ Add to `requirements.txt`:
50
+
51
+ ```txt
52
+ google-generativeai==0.3.2 # Gemini API client
53
+ tiktoken==0.5.2 # Token counting (optional)
54
+ ```
55
+
56
+ Install:
57
+
58
+ ```bash
59
+ pip install -r requirements.txt
60
+ ```
61
+
62
+ #### Step 1.2: Configure Environment Variables
63
+
64
+ Add to `backend/.env`:
65
+
66
+ ```env
67
+ # AI Provider Configuration
68
+ AI_PROVIDER=gemini
69
+ GEMINI_API_KEY=your_gemini_api_key_here
70
+
71
+ # Conversation Settings
72
+ MAX_CONVERSATION_MESSAGES=20
73
+ MAX_CONVERSATION_TOKENS=8000
74
+ ```
75
+
76
+ #### Step 1.3: Create Database Models
77
+
78
+ **File**: `backend/src/models/conversation.py`
79
+
80
+ ```python
81
+ from sqlmodel import SQLModel, Field, Relationship
82
+ from datetime import datetime
83
+ from typing import List, Optional
84
+
85
+ class Conversation(SQLModel, table=True):
86
+ __tablename__ = "conversation"
87
+
88
+ id: Optional[int] = Field(default=None, primary_key=True)
89
+ user_id: int = Field(foreign_key="user.id", index=True)
90
+ created_at: datetime = Field(default_factory=datetime.utcnow)
91
+ updated_at: datetime = Field(
92
+ default_factory=datetime.utcnow,
93
+ sa_column_kwargs={"onupdate": datetime.utcnow}
94
+ )
95
+ title: Optional[str] = Field(default=None, max_length=255)
96
+
97
+ messages: List["Message"] = Relationship(
98
+ back_populates="conversation",
99
+ sa_relationship_kwargs={"cascade": "all, delete-orphan"}
100
+ )
101
+ ```
102
+
103
+ **File**: `backend/src/models/message.py`
104
+
105
+ ```python
106
+ from sqlmodel import SQLModel, Field, Relationship, Column, Text
107
+ from datetime import datetime
108
+ from typing import Optional
109
+ from pydantic import validator
110
+
111
+ class Message(SQLModel, table=True):
112
+ __tablename__ = "message"
113
+
114
+ id: Optional[int] = Field(default=None, primary_key=True)
115
+ conversation_id: int = Field(foreign_key="conversation.id", index=True)
116
+ role: str = Field(max_length=20)
117
+ content: str = Field(sa_column=Column(Text))
118
+ timestamp: datetime = Field(default_factory=datetime.utcnow, index=True)
119
+ token_count: Optional[int] = Field(default=None, ge=0)
120
+
121
+ conversation: "Conversation" = Relationship(back_populates="messages")
122
+
123
+ @validator("role")
124
+ def validate_role(cls, v):
125
+ if v not in ["user", "assistant"]:
126
+ raise ValueError("role must be 'user' or 'assistant'")
127
+ return v
128
+
129
+ @validator("content")
130
+ def validate_content(cls, v):
131
+ if not v or len(v.strip()) == 0:
132
+ raise ValueError("content must not be empty")
133
+ return v
134
+ ```
135
+
136
+ #### Step 1.4: Create Database Migration
137
+
138
+ ```bash
139
+ cd backend
140
+ alembic revision -m "Add conversation and message tables"
141
+ ```
142
+
143
+ Edit the generated migration file:
144
+
145
+ ```python
146
+ def upgrade():
147
+ op.create_table(
148
+ 'conversation',
149
+ sa.Column('id', sa.Integer(), nullable=False),
150
+ sa.Column('user_id', sa.Integer(), nullable=False),
151
+ sa.Column('created_at', sa.DateTime(), nullable=False),
152
+ sa.Column('updated_at', sa.DateTime(), nullable=False),
153
+ sa.Column('title', sa.String(length=255), nullable=True),
154
+ sa.ForeignKeyConstraint(['user_id'], ['user.id'], ondelete='CASCADE'),
155
+ sa.PrimaryKeyConstraint('id')
156
+ )
157
+ op.create_index('idx_conversation_user_id', 'conversation', ['user_id'])
158
+ op.create_index('idx_conversation_updated_at', 'conversation', ['updated_at'])
159
+
160
+ op.create_table(
161
+ 'message',
162
+ sa.Column('id', sa.Integer(), nullable=False),
163
+ sa.Column('conversation_id', sa.Integer(), nullable=False),
164
+ sa.Column('role', sa.String(length=20), nullable=False),
165
+ sa.Column('content', sa.Text(), nullable=False),
166
+ sa.Column('timestamp', sa.DateTime(), nullable=False),
167
+ sa.Column('token_count', sa.Integer(), nullable=True),
168
+ sa.ForeignKeyConstraint(['conversation_id'], ['conversation.id'], ondelete='CASCADE'),
169
+ sa.PrimaryKeyConstraint('id'),
170
+ sa.CheckConstraint("role IN ('user', 'assistant')", name='check_message_role')
171
+ )
172
+ op.create_index('idx_message_conversation_id', 'message', ['conversation_id'])
173
+ op.create_index('idx_message_timestamp', 'message', ['timestamp'])
174
+
175
+ def downgrade():
176
+ op.drop_table('message')
177
+ op.drop_table('conversation')
178
+ ```
179
+
180
+ Run migration:
181
+
182
+ ```bash
183
+ alembic upgrade head
184
+ ```
185
+
186
+ #### Step 1.5: Create LLM Provider Abstraction
187
+
188
+ **File**: `backend/src/services/providers/base.py`
189
+
190
+ ```python
191
+ from abc import ABC, abstractmethod
192
+ from typing import List, Dict
193
+
194
+ class LLMProvider(ABC):
195
+ @abstractmethod
196
+ async def generate_response(
197
+ self,
198
+ messages: List[Dict[str, str]]
199
+ ) -> str:
200
+ """Generate a response from the LLM."""
201
+ pass
202
+ ```
203
+
204
+ **File**: `backend/src/services/providers/gemini.py`
205
+
206
+ ```python
207
+ import google.generativeai as genai
208
+ from typing import List, Dict
209
+ from .base import LLMProvider
210
+
211
+ class GeminiProvider(LLMProvider):
212
+ def __init__(self, api_key: str):
213
+ genai.configure(api_key=api_key)
214
+ self.model = genai.GenerativeModel('gemini-pro')
215
+
216
+ async def generate_response(self, messages: List[Dict[str, str]]) -> str:
217
+ # Convert messages to Gemini format
218
+ prompt = self._format_messages(messages)
219
+
220
+ # Generate response
221
+ response = await self.model.generate_content_async(prompt)
222
+ return response.text
223
+
224
+ def _format_messages(self, messages: List[Dict[str, str]]) -> str:
225
+ # Format conversation history as a single prompt
226
+ formatted = []
227
+ for msg in messages:
228
+ role = "User" if msg["role"] == "user" else "Assistant"
229
+ formatted.append(f"{role}: {msg['content']}")
230
+ return "\n\n".join(formatted)
231
+ ```
232
+
233
+ #### Step 1.6: Create LLM Service
234
+
235
+ **File**: `backend/src/services/llm_service.py`
236
+
237
+ ```python
238
+ from typing import List, Dict
239
+ from ..core.config import settings
240
+ from .providers.base import LLMProvider
241
+ from .providers.gemini import GeminiProvider
242
+
243
+ class LLMService:
244
+ def __init__(self):
245
+ self.provider = self._get_provider()
246
+
247
+ def _get_provider(self) -> LLMProvider:
248
+ provider_name = settings.AI_PROVIDER.lower()
249
+
250
+ if provider_name == "gemini":
251
+ return GeminiProvider(api_key=settings.GEMINI_API_KEY)
252
+ else:
253
+ raise ValueError(f"Unsupported AI provider: {provider_name}")
254
+
255
+ async def generate_response(self, messages: List[Dict[str, str]]) -> str:
256
+ return await self.provider.generate_response(messages)
257
+ ```
258
+
259
+ #### Step 1.7: Create Conversation Service
260
+
261
+ **File**: `backend/src/services/conversation_service.py`
262
+
263
+ ```python
264
+ from sqlmodel import Session, select
265
+ from typing import List, Dict, Optional
266
+ from ..models.conversation import Conversation
267
+ from ..models.message import Message
268
+ from datetime import datetime
269
+
270
+ class ConversationService:
271
+ def __init__(self, session: Session):
272
+ self.session = session
273
+
274
+ def get_or_create_conversation(self, user_id: int) -> Conversation:
275
+ # Get most recent conversation for user
276
+ conversation = self.session.exec(
277
+ select(Conversation)
278
+ .where(Conversation.user_id == user_id)
279
+ .order_by(Conversation.updated_at.desc())
280
+ ).first()
281
+
282
+ if not conversation:
283
+ conversation = Conversation(user_id=user_id)
284
+ self.session.add(conversation)
285
+ self.session.commit()
286
+ self.session.refresh(conversation)
287
+
288
+ return conversation
289
+
290
+ def load_conversation_history(
291
+ self,
292
+ conversation_id: int,
293
+ max_messages: int = 20
294
+ ) -> List[Dict[str, str]]:
295
+ messages = self.session.exec(
296
+ select(Message)
297
+ .where(Message.conversation_id == conversation_id)
298
+ .order_by(Message.timestamp.desc())
299
+ .limit(max_messages)
300
+ ).all()
301
+
302
+ # Reverse to chronological order
303
+ messages = list(reversed(messages))
304
+
305
+ return [
306
+ {"role": msg.role, "content": msg.content}
307
+ for msg in messages
308
+ ]
309
+
310
+ def add_message(
311
+ self,
312
+ conversation_id: int,
313
+ role: str,
314
+ content: str
315
+ ) -> Message:
316
+ message = Message(
317
+ conversation_id=conversation_id,
318
+ role=role,
319
+ content=content
320
+ )
321
+ self.session.add(message)
322
+
323
+ # Update conversation timestamp
324
+ conversation = self.session.get(Conversation, conversation_id)
325
+ conversation.updated_at = datetime.utcnow()
326
+ self.session.add(conversation)
327
+
328
+ self.session.commit()
329
+ self.session.refresh(message)
330
+ return message
331
+ ```
332
+
333
+ #### Step 1.8: Create Pydantic Schemas
334
+
335
+ **File**: `backend/src/schemas/chat_request.py`
336
+
337
+ ```python
338
+ from pydantic import BaseModel, Field
339
+
340
+ class ChatRequest(BaseModel):
341
+ message: str = Field(..., min_length=1, max_length=10000)
342
+ conversation_id: Optional[int] = None
343
+ ```
344
+
345
+ **File**: `backend/src/schemas/chat_response.py`
346
+
347
+ ```python
348
+ from pydantic import BaseModel
349
+ from datetime import datetime
350
+
351
+ class ChatResponse(BaseModel):
352
+ response: str
353
+ conversation_id: int
354
+ timestamp: datetime
355
+ ```
356
+
357
+ #### Step 1.9: Create Chat API Endpoint
358
+
359
+ **File**: `backend/src/api/routes/chat.py`
360
+
361
+ ```python
362
+ from fastapi import APIRouter, Depends, HTTPException
363
+ from sqlmodel import Session
364
+ from ...core.database import get_session
365
+ from ...core.security import get_current_user
366
+ from ...schemas.chat_request import ChatRequest
367
+ from ...schemas.chat_response import ChatResponse
368
+ from ...services.conversation_service import ConversationService
369
+ from ...services.llm_service import LLMService
370
+ from datetime import datetime
371
+
372
+ router = APIRouter()
373
+
374
+ @router.post("/api/{user_id}/chat", response_model=ChatResponse)
375
+ async def chat(
376
+ user_id: int,
377
+ request: ChatRequest,
378
+ session: Session = Depends(get_session),
379
+ current_user = Depends(get_current_user)
380
+ ):
381
+ # Verify user_id matches authenticated user
382
+ if current_user.id != user_id:
383
+ raise HTTPException(status_code=401, detail="Unauthorized")
384
+
385
+ # Initialize services
386
+ conversation_service = ConversationService(session)
387
+ llm_service = LLMService()
388
+
389
+ # Get or create conversation
390
+ conversation = conversation_service.get_or_create_conversation(user_id)
391
+
392
+ # Load conversation history
393
+ history = conversation_service.load_conversation_history(conversation.id)
394
+
395
+ # Add user message to history
396
+ history.append({"role": "user", "content": request.message})
397
+
398
+ # Generate AI response
399
+ try:
400
+ ai_response = await llm_service.generate_response(history)
401
+ except Exception as e:
402
+ raise HTTPException(status_code=500, detail="Failed to generate AI response")
403
+
404
+ # Save messages to database
405
+ conversation_service.add_message(conversation.id, "user", request.message)
406
+ conversation_service.add_message(conversation.id, "assistant", ai_response)
407
+
408
+ return ChatResponse(
409
+ response=ai_response,
410
+ conversation_id=conversation.id,
411
+ timestamp=datetime.utcnow()
412
+ )
413
+ ```
414
+
415
+ Register the router in `backend/src/main.py`:
416
+
417
+ ```python
418
+ from .api.routes import chat
419
+
420
+ app.include_router(chat.router)
421
+ ```
422
+
423
+ ---
424
+
425
+ ### Day 2: Frontend Integration
426
+
427
+ #### Step 2.1: Install Dependencies
428
+
429
+ ```bash
430
+ cd frontend
431
+ npm install @assistant-ui/react ai
432
+ ```
433
+
434
+ #### Step 2.2: Create Chat Service
435
+
436
+ **File**: `frontend/src/services/chatService.ts`
437
+
438
+ ```typescript
439
+ export interface ChatMessage {
440
+ role: "user" | "assistant";
441
+ content: string;
442
+ }
443
+
444
+ export interface ChatResponse {
445
+ response: string;
446
+ conversation_id: number;
447
+ timestamp: string;
448
+ }
449
+
450
+ export async function sendChatMessage(
451
+ userId: number,
452
+ message: string,
453
+ token: string
454
+ ): Promise<ChatResponse> {
455
+ const response = await fetch(`/api/${userId}/chat`, {
456
+ method: "POST",
457
+ headers: {
458
+ "Content-Type": "application/json",
459
+ Authorization: `Bearer ${token}`,
460
+ },
461
+ body: JSON.stringify({ message }),
462
+ });
463
+
464
+ if (!response.ok) {
465
+ throw new Error("Failed to send message");
466
+ }
467
+
468
+ return response.json();
469
+ }
470
+ ```
471
+
472
+ #### Step 2.3: Create Chat Components
473
+
474
+ **File**: `frontend/src/components/chat/ChatInterface.tsx`
475
+
476
+ ```tsx
477
+ "use client";
478
+
479
+ import { useState } from "react";
480
+ import { MessageList } from "./MessageList";
481
+ import { MessageInput } from "./MessageInput";
482
+ import { TypingIndicator } from "./TypingIndicator";
483
+ import { sendChatMessage } from "@/services/chatService";
484
+
485
+ interface Message {
486
+ role: "user" | "assistant";
487
+ content: string;
488
+ }
489
+
490
+ export function ChatInterface({
491
+ userId,
492
+ token,
493
+ }: {
494
+ userId: number;
495
+ token: string;
496
+ }) {
497
+ const [messages, setMessages] = useState<Message[]>([]);
498
+ const [isLoading, setIsLoading] = useState(false);
499
+
500
+ const handleSendMessage = async (content: string) => {
501
+ // Add user message optimistically
502
+ const userMessage: Message = { role: "user", content };
503
+ setMessages((prev) => [...prev, userMessage]);
504
+ setIsLoading(true);
505
+
506
+ try {
507
+ const response = await sendChatMessage(userId, content, token);
508
+
509
+ // Add assistant response
510
+ const assistantMessage: Message = {
511
+ role: "assistant",
512
+ content: response.response,
513
+ };
514
+ setMessages((prev) => [...prev, assistantMessage]);
515
+ } catch (error) {
516
+ console.error("Failed to send message:", error);
517
+ // Handle error (show toast, etc.)
518
+ } finally {
519
+ setIsLoading(false);
520
+ }
521
+ };
522
+
523
+ return (
524
+ <div className="flex flex-col h-[600px] w-full max-w-2xl mx-auto border rounded-lg">
525
+ <MessageList messages={messages} />
526
+ {isLoading && <TypingIndicator />}
527
+ <MessageInput onSend={handleSendMessage} disabled={isLoading} />
528
+ </div>
529
+ );
530
+ }
531
+ ```
532
+
533
+ **File**: `frontend/src/components/chat/MessageList.tsx`
534
+
535
+ ```tsx
536
+ interface Message {
537
+ role: "user" | "assistant";
538
+ content: string;
539
+ }
540
+
541
+ export function MessageList({ messages }: { messages: Message[] }) {
542
+ return (
543
+ <div className="flex-1 overflow-y-auto p-4 space-y-4">
544
+ {messages.map((message, index) => (
545
+ <div
546
+ key={index}
547
+ className={`flex ${
548
+ message.role === "user" ? "justify-end" : "justify-start"
549
+ }`}
550
+ >
551
+ <div
552
+ className={`max-w-[70%] rounded-lg p-3 ${
553
+ message.role === "user"
554
+ ? "bg-blue-500 text-white"
555
+ : "bg-gray-200 text-gray-900"
556
+ }`}
557
+ >
558
+ {message.content}
559
+ </div>
560
+ </div>
561
+ ))}
562
+ </div>
563
+ );
564
+ }
565
+ ```
566
+
567
+ **File**: `frontend/src/components/chat/MessageInput.tsx`
568
+
569
+ ```tsx
570
+ "use client";
571
+
572
+ import { useState } from "react";
573
+
574
+ export function MessageInput({
575
+ onSend,
576
+ disabled,
577
+ }: {
578
+ onSend: (message: string) => void;
579
+ disabled: boolean;
580
+ }) {
581
+ const [input, setInput] = useState("");
582
+
583
+ const handleSubmit = (e: React.FormEvent) => {
584
+ e.preventDefault();
585
+ if (input.trim() && !disabled) {
586
+ onSend(input);
587
+ setInput("");
588
+ }
589
+ };
590
+
591
+ return (
592
+ <form onSubmit={handleSubmit} className="border-t p-4">
593
+ <div className="flex gap-2">
594
+ <input
595
+ type="text"
596
+ value={input}
597
+ onChange={(e) => setInput(e.target.value)}
598
+ placeholder="Type your message..."
599
+ disabled={disabled}
600
+ className="flex-1 px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
601
+ />
602
+ <button
603
+ type="submit"
604
+ disabled={disabled || !input.trim()}
605
+ className="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:opacity-50"
606
+ >
607
+ Send
608
+ </button>
609
+ </div>
610
+ </form>
611
+ );
612
+ }
613
+ ```
614
+
615
+ **File**: `frontend/src/components/chat/TypingIndicator.tsx`
616
+
617
+ ```tsx
618
+ export function TypingIndicator() {
619
+ return <div className="px-4 py-2 text-gray-500 text-sm">AI is typing...</div>;
620
+ }
621
+ ```
622
+
623
+ #### Step 2.4: Create Chat Page
624
+
625
+ **File**: `frontend/src/app/chat/page.tsx`
626
+
627
+ ```tsx
628
+ import { ChatInterface } from "@/components/chat/ChatInterface";
629
+ import { auth } from "@/lib/auth"; // Your Better Auth instance
630
+ import { redirect } from "next/navigation";
631
+
632
+ export default async function ChatPage() {
633
+ const session = await auth();
634
+
635
+ if (!session) {
636
+ redirect("/auth/signin");
637
+ }
638
+
639
+ return (
640
+ <main className="container mx-auto py-8">
641
+ <h1 className="text-3xl font-bold mb-8">AI Chat Assistant</h1>
642
+ <ChatInterface userId={session.user.id} token={session.token} />
643
+ </main>
644
+ );
645
+ }
646
+ ```
647
+
648
+ ---
649
+
650
+ ### Day 3: Testing & Polish
651
+
652
+ #### Step 3.1: Test Backend
653
+
654
+ ```bash
655
+ cd backend
656
+ pytest tests/integration/test_chat_api.py -v
657
+ ```
658
+
659
+ #### Step 3.2: Test Frontend
660
+
661
+ ```bash
662
+ cd frontend
663
+ npm run dev
664
+ ```
665
+
666
+ Navigate to `http://localhost:3000/chat` and test:
667
+
668
+ - ✅ Send a message
669
+ - ✅ Receive AI response
670
+ - ✅ Conversation persists on page refresh
671
+ - ✅ Multiple messages maintain context
672
+
673
+ #### Step 3.3: Test Error Handling
674
+
675
+ - Test with invalid JWT token (should return 401)
676
+ - Test with empty message (should return 400)
677
+ - Test with rate limit exceeded (should return 429)
678
+
679
+ ---
680
+
681
+ ## Verification Checklist
682
+
683
+ - [ ] Database tables created (conversation, message)
684
+ - [ ] Backend API endpoint responds at POST /api/{user_id}/chat
685
+ - [ ] Frontend chat interface renders correctly
686
+ - [ ] Messages persist to database
687
+ - [ ] Conversation history loads on page refresh
688
+ - [ ] AI responses are generated successfully
689
+ - [ ] JWT authentication works correctly
690
+ - [ ] Error handling works for common scenarios
691
+
692
+ ---
693
+
694
+ ## Troubleshooting
695
+
696
+ ### Issue: "Gemini API key invalid"
697
+
698
+ **Solution**: Verify GEMINI_API_KEY in backend/.env
699
+
700
+ ### Issue: "Database connection failed"
701
+
702
+ **Solution**: Check DATABASE_URL in backend/.env
703
+
704
+ ### Issue: "401 Unauthorized"
705
+
706
+ **Solution**: Verify JWT token is being sent in Authorization header
707
+
708
+ ### Issue: "Chat interface not rendering"
709
+
710
+ **Solution**: Ensure 'use client' directive is present in client components
711
+
712
+ ---
713
+
714
+ ## Next Steps
715
+
716
+ After completing Phase 1:
717
+
718
+ 1. Review implementation against spec.md acceptance criteria
719
+ 2. Create PHR (Prompt History Record) documenting implementation
720
+ 3. Prepare for Phase 2 (Spec-2): MCP tools and task CRUD operations
721
+
722
+ ---
723
+
724
+ ## Resources
725
+
726
+ - [Gemini API Documentation](https://ai.google.dev/docs)
727
+ - [FastAPI Documentation](https://fastapi.tiangolo.com/)
728
+ - [Next.js App Router](https://nextjs.org/docs/app)
729
+ - [SQLModel Documentation](https://sqlmodel.tiangolo.com/)
specs/001-todo-ai-chatbot/research.md ADDED
@@ -0,0 +1,398 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research Findings: Todo AI Chatbot - Phase 1
2
+
3
+ **Feature**: 001-todo-ai-chatbot
4
+ **Date**: 2026-01-14
5
+ **Phase**: Phase 0 - Research & Clarifications
6
+
7
+ ---
8
+
9
+ ## Research Questions
10
+
11
+ This document consolidates research findings for unknowns identified in the Technical Context:
12
+
13
+ 1. Frontend Testing Setup
14
+ 2. AI Agent SDK Selection
15
+ 3. OpenAI ChatKit Compatibility
16
+ 4. Free-Tier AI Provider Integration
17
+ 5. Conversation History Trimming Strategy
18
+
19
+ ---
20
+
21
+ ## 1. Frontend Testing Setup
22
+
23
+ ### Current State
24
+
25
+ **Findings from package.json analysis:**
26
+ - No testing framework currently installed
27
+ - No test scripts defined in package.json
28
+ - Frontend uses Next.js 16+ with TypeScript
29
+
30
+ ### Decision
31
+
32
+ **DEFERRED TO IMPLEMENTATION**: Testing setup will be configured during implementation phase. Recommended stack:
33
+ - Jest + React Testing Library for component tests
34
+ - Playwright or Cypress for E2E tests (if needed)
35
+
36
+ **Rationale**: Testing infrastructure is not blocking for Phase 1 planning. Can be added incrementally during implementation.
37
+
38
+ ---
39
+
40
+ ## 2. AI Agent SDK Selection
41
+
42
+ ### Research Summary
43
+
44
+ Evaluated four options for AI agent implementation:
45
+
46
+ | Option | Free-Tier Support | Stateless | FastAPI Integration | Tool Calling | Complexity |
47
+ |--------|------------------|-----------|---------------------|--------------|------------|
48
+ | OpenAI Agents SDK | ❌ No | ⚠️ Custom | ⚠️ Moderate | ✅ Excellent | Low |
49
+ | LangChain | ✅ Yes | ⚠️ Custom | ✅ Good | ✅ Excellent | High |
50
+ | LlamaIndex | ✅ Yes | ⚠️ Custom | ✅ Good | ✅ Good | High |
51
+ | Custom Implementation | ✅ Yes | ✅ Native | ✅ Excellent | ⚠️ Manual | Low |
52
+
53
+ ### Decision
54
+
55
+ **SELECTED: Custom Implementation with Direct API Calls**
56
+
57
+ **Rationale**:
58
+ 1. **Meets all Phase 1 requirements**: Supports free-tier providers (Gemini, OpenRouter, Cohere), stateless operation, FastAPI integration
59
+ 2. **Fastest implementation**: Can build working chat in 1-2 days (critical for hackathon timeline)
60
+ 3. **Minimal complexity**: No framework abstractions to learn; transparent behavior
61
+ 4. **Perfect for stateless requirement**: Native database-driven state management (FR-018)
62
+ 5. **Aligns with constraints**: TC-007 (free-tier), BC-001 (time constraints)
63
+
64
+ **Implementation Approach**:
65
+ ```python
66
+ # Abstract provider interface
67
+ class LLMProvider(ABC):
68
+ @abstractmethod
69
+ async def generate_response(
70
+ self,
71
+ messages: List[Dict[str, str]]
72
+ ) -> str:
73
+ pass
74
+
75
+ # Provider implementations
76
+ class GeminiProvider(LLMProvider): ...
77
+ class CohereProvider(LLMProvider): ...
78
+ class OpenRouterProvider(LLMProvider): ...
79
+ ```
80
+
81
+ **Phase 2 Consideration**: If tool orchestration becomes complex in Spec-2, re-evaluate migration to LangChain for built-in agent patterns.
82
+
83
+ ### Alternatives Considered
84
+
85
+ **LangChain**:
86
+ - **Pros**: Excellent tool calling, large ecosystem, multi-provider support
87
+ - **Cons**: Steep learning curve, requires custom stateless implementation, may be over-engineered for Phase 1
88
+ - **Verdict**: Good for Phase 2 if tool complexity justifies it
89
+
90
+ **OpenAI Agents SDK**:
91
+ - **Pros**: Excellent documentation, native tool calling
92
+ - **Cons**: No free-tier support (critical blocker), OpenAI-only
93
+ - **Verdict**: Rejected due to FR-025 violation
94
+
95
+ **LlamaIndex**:
96
+ - **Pros**: Multi-provider support, good tool calling
97
+ - **Cons**: Focused on RAG/document search (not pure chat), less mature chat features
98
+ - **Verdict**: Misaligned with requirements
99
+
100
+ ---
101
+
102
+ ## 3. OpenAI ChatKit Compatibility
103
+
104
+ ### Research Summary
105
+
106
+ **OpenAI ChatKit (@openai/chatkit-react v1.4.1)**:
107
+ - ✅ React 18.2.0 compatible
108
+ - ✅ TypeScript support
109
+ - ⚠️ **CRITICAL ISSUE**: Web component architecture incompatible with Next.js App Router
110
+ - ❌ Requires CDN script loading
111
+ - ❌ Cannot be used in Server Components
112
+ - ❌ No official Next.js documentation
113
+
114
+ **Compatibility Issues**:
115
+ 1. Uses custom web component (`<openai-chatkit>`) requiring browser APIs
116
+ 2. Requires external CDN script: `https://cdn.platform.openai.com/deployments/chatkit/chatkit.js`
117
+ 3. All official examples use Vite, not Next.js
118
+ 4. Potential SSR/hydration issues
119
+
120
+ ### Decision
121
+
122
+ **REJECTED: OpenAI ChatKit**
123
+ **SELECTED: @assistant-ui/react**
124
+
125
+ **Rationale**:
126
+ 1. **Next.js App Router native**: Built specifically for Next.js with full SSR support
127
+ 2. **No CDN dependencies**: Pure React components, no external scripts
128
+ 3. **Tailwind CSS integration**: Matches existing frontend stack
129
+ 4. **Vercel AI SDK compatible**: Enables streaming responses and tool calls
130
+ 5. **Shadcn UI style**: Compatible with existing Radix UI components
131
+ 6. **Active development**: Well-maintained with strong community support
132
+
133
+ **Implementation Approach**:
134
+ ```bash
135
+ npm install @assistant-ui/react ai
136
+ ```
137
+
138
+ ```tsx
139
+ // app/chat/page.tsx
140
+ 'use client';
141
+ import { Thread } from '@assistant-ui/react';
142
+ import { useChat } from 'ai/react';
143
+
144
+ export default function ChatPage() {
145
+ const chat = useChat({ api: '/api/chat' });
146
+ return <Thread />;
147
+ }
148
+ ```
149
+
150
+ ### Alternatives Considered
151
+
152
+ **@chatscope/chat-ui-kit-react**:
153
+ - **Pros**: Pure React, extensive customization
154
+ - **Cons**: Less Next.js-specific, more manual setup
155
+ - **Verdict**: Good alternative but @assistant-ui/react is better fit
156
+
157
+ **stream-chat-react**:
158
+ - **Pros**: Enterprise-grade, real-time messaging
159
+ - **Cons**: Overkill for requirements, external service dependency
160
+ - **Verdict**: Too complex for hackathon scope
161
+
162
+ ---
163
+
164
+ ## 4. Free-Tier AI Provider Integration
165
+
166
+ ### Research Summary
167
+
168
+ **Supported Providers**:
169
+
170
+ | Provider | Free Tier | Rate Limits | Context Window | Best For |
171
+ |----------|-----------|-------------|----------------|----------|
172
+ | **Google Gemini** | ✅ Yes | 60 req/min | 32k tokens | General chat, fast responses |
173
+ | **OpenRouter** | ✅ Yes (some models) | Varies by model | Varies | Model flexibility, fallback |
174
+ | **Cohere** | ✅ Yes (trial) | 100 req/min | 4k tokens | Command models, structured output |
175
+
176
+ ### Decision
177
+
178
+ **PRIMARY: Google Gemini (gemini-pro)**
179
+ **FALLBACK: OpenRouter (free models)**
180
+
181
+ **Rationale**:
182
+ 1. **Gemini**: Best free-tier offering (60 req/min, 32k context, no credit card required)
183
+ 2. **OpenRouter**: Good fallback with multiple free models
184
+ 3. **Cohere**: Trial-based, less suitable for long-term development
185
+
186
+ **Implementation Strategy**:
187
+ ```python
188
+ # backend/src/core/config.py
189
+ class Settings(BaseSettings):
190
+ AI_PROVIDER: str = "gemini" # gemini | openrouter | cohere
191
+ GEMINI_API_KEY: Optional[str] = None
192
+ OPENROUTER_API_KEY: Optional[str] = None
193
+ COHERE_API_KEY: Optional[str] = None
194
+ ```
195
+
196
+ **Provider Selection Logic**:
197
+ - Environment variable determines active provider
198
+ - Easy switching for testing and rate limit management
199
+ - No code changes required to switch providers
200
+
201
+ ---
202
+
203
+ ## 5. Conversation History Trimming Strategy
204
+
205
+ ### Research Summary
206
+
207
+ **Free-Tier Context Limits**:
208
+ - Gemini: 32k tokens (~24k words)
209
+ - OpenRouter: Varies (4k-32k depending on model)
210
+ - Cohere: 4k tokens (~3k words)
211
+
212
+ **Trimming Strategies Evaluated**:
213
+
214
+ 1. **Fixed Message Count**: Keep last N messages
215
+ - **Pros**: Simple, predictable
216
+ - **Cons**: Doesn't account for message length variance
217
+
218
+ 2. **Token-Based Trimming**: Keep messages within token budget
219
+ - **Pros**: Precise, maximizes context usage
220
+ - **Cons**: Requires token counting library
221
+
222
+ 3. **Sliding Window**: Keep recent messages + system prompt
223
+ - **Pros**: Balances context and recency
224
+ - **Cons**: May lose important context
225
+
226
+ 4. **Summarization**: Summarize old messages
227
+ - **Pros**: Preserves context semantically
228
+ - **Cons**: Requires additional API calls, complexity
229
+
230
+ ### Decision
231
+
232
+ **SELECTED: Hybrid Approach (Fixed Count + Token Budget)**
233
+
234
+ **Implementation**:
235
+ ```python
236
+ MAX_MESSAGES = 20 # Keep last 20 messages
237
+ MAX_TOKENS = 8000 # Conservative limit for free-tier
238
+
239
+ def trim_conversation_history(messages: List[Message]) -> List[Dict]:
240
+ # Step 1: Keep only last MAX_MESSAGES
241
+ recent_messages = messages[-MAX_MESSAGES:]
242
+
243
+ # Step 2: Estimate tokens (rough: 1 token ≈ 4 chars)
244
+ formatted = [{"role": m.role, "content": m.content} for m in recent_messages]
245
+
246
+ # Step 3: Trim from oldest if exceeding token budget
247
+ while estimate_tokens(formatted) > MAX_TOKENS and len(formatted) > 1:
248
+ formatted.pop(0) # Remove oldest message
249
+
250
+ return formatted
251
+ ```
252
+
253
+ **Rationale**:
254
+ 1. **Simple to implement**: No external token counting library needed
255
+ 2. **Conservative limits**: Ensures compatibility with all providers
256
+ 3. **Predictable behavior**: Users understand "last 20 messages" concept
257
+ 4. **Room for growth**: Can add token counting library later if needed
258
+
259
+ **Phase 2 Enhancement**: Consider adding conversation summarization for long-running conversations.
260
+
261
+ ---
262
+
263
+ ## Architectural Decisions Summary
264
+
265
+ ### Backend Architecture
266
+
267
+ **AI Agent Implementation**: Custom implementation with provider abstraction
268
+ - `backend/src/services/providers/base.py` - Abstract provider interface
269
+ - `backend/src/services/providers/gemini.py` - Gemini implementation
270
+ - `backend/src/services/providers/openrouter.py` - OpenRouter implementation
271
+ - `backend/src/services/llm_service.py` - LLM service layer with provider factory
272
+
273
+ **Conversation Management**: Stateless with database persistence
274
+ - Load conversation history from database on each request
275
+ - Execute AI agent with full history
276
+ - Save new messages to database
277
+ - Return response to frontend
278
+
279
+ **Provider Configuration**: Environment-based selection
280
+ - `AI_PROVIDER` environment variable determines active provider
281
+ - API keys stored in environment variables
282
+ - No code changes required to switch providers
283
+
284
+ ### Frontend Architecture
285
+
286
+ **Chat UI Library**: @assistant-ui/react
287
+ - Native Next.js App Router support
288
+ - Tailwind CSS integration
289
+ - Vercel AI SDK compatibility
290
+ - No CDN dependencies
291
+
292
+ **Component Structure**:
293
+ - `frontend/src/app/chat/page.tsx` - Chat page (App Router)
294
+ - `frontend/src/components/chat/ChatInterface.tsx` - Main chat component
295
+ - `frontend/src/services/chatService.ts` - API client
296
+
297
+ **State Management**: React hooks + Vercel AI SDK
298
+ - `useChat` hook for message state
299
+ - Streaming responses support
300
+ - Optimistic UI updates
301
+
302
+ ### Database Schema
303
+
304
+ **Conversation Model**:
305
+ ```python
306
+ class Conversation(SQLModel, table=True):
307
+ id: Optional[int] = Field(default=None, primary_key=True)
308
+ user_id: int = Field(foreign_key="user.id")
309
+ created_at: datetime
310
+ updated_at: datetime
311
+ messages: List["Message"] = Relationship(back_populates="conversation")
312
+ ```
313
+
314
+ **Message Model**:
315
+ ```python
316
+ class Message(SQLModel, table=True):
317
+ id: Optional[int] = Field(default=None, primary_key=True)
318
+ conversation_id: int = Field(foreign_key="conversation.id")
319
+ role: str # "user" or "assistant"
320
+ content: str
321
+ timestamp: datetime
322
+ conversation: Conversation = Relationship(back_populates="messages")
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Technology Stack Finalized
328
+
329
+ | Layer | Technology | Version | Rationale |
330
+ |-------|-----------|---------|-----------|
331
+ | **Frontend Framework** | Next.js | 16+ | Existing stack, App Router support |
332
+ | **Frontend UI** | @assistant-ui/react | Latest | Next.js native, Tailwind integration |
333
+ | **Frontend State** | Vercel AI SDK | Latest | Streaming, tool calls, React hooks |
334
+ | **Backend Framework** | FastAPI | 0.104.1 | Existing stack, async support |
335
+ | **AI Provider** | Google Gemini | gemini-pro | Best free-tier offering |
336
+ | **AI Implementation** | Custom | N/A | Stateless, simple, fast |
337
+ | **Database** | Neon PostgreSQL | N/A | Existing stack, serverless |
338
+ | **ORM** | SQLModel | 0.0.14 | Existing stack, type-safe |
339
+ | **Authentication** | Better Auth | 1.0.0 | Existing stack, JWT tokens |
340
+
341
+ ---
342
+
343
+ ## Implementation Priorities
344
+
345
+ ### Phase 1 (Current Spec) - Days 1-3
346
+
347
+ 1. **Day 1: Backend Foundation**
348
+ - Create Conversation and Message models
349
+ - Implement Gemini provider
350
+ - Create LLM service layer
351
+ - Build chat API endpoint
352
+
353
+ 2. **Day 2: Frontend Integration**
354
+ - Install @assistant-ui/react
355
+ - Create chat page and components
356
+ - Integrate with backend API
357
+ - Implement conversation persistence
358
+
359
+ 3. **Day 3: Testing & Polish**
360
+ - Test with Gemini API
361
+ - Add error handling
362
+ - Implement history trimming
363
+ - Test responsive design
364
+
365
+ ### Phase 2 (Spec-2) - Future
366
+
367
+ - MCP server implementation
368
+ - Task CRUD tools
369
+ - Tool execution capabilities
370
+ - Advanced agent orchestration
371
+
372
+ ---
373
+
374
+ ## Risks & Mitigations
375
+
376
+ | Risk | Impact | Mitigation |
377
+ |------|--------|------------|
378
+ | **Gemini API rate limits** | High | Implement OpenRouter fallback, aggressive history trimming |
379
+ | **@assistant-ui/react learning curve** | Medium | Allocate time for documentation review, use examples |
380
+ | **Custom AI implementation complexity** | Medium | Start simple, iterate based on needs |
381
+ | **Conversation history growth** | Low | Implement trimming from day 1, monitor database size |
382
+
383
+ ---
384
+
385
+ ## Open Questions
386
+
387
+ **None remaining.** All critical unknowns have been resolved through research.
388
+
389
+ ---
390
+
391
+ ## Next Steps
392
+
393
+ 1. ✅ Research complete
394
+ 2. ⏭️ Update plan.md with architectural decisions
395
+ 3. ⏭️ Create data-model.md
396
+ 4. ⏭️ Create API contracts (contracts/chat-api.yaml)
397
+ 5. ⏭️ Create quickstart.md
398
+ 6. ⏭️ Generate tasks.md (/sp.tasks command)
specs/001-todo-ai-chatbot/spec.md ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Feature Specification: Todo AI Chatbot - Phase 1 (Conversational UI + Basic Agent Wiring)
2
+
3
+ **Feature Branch**: `001-todo-ai-chatbot`
4
+ **Created**: 2026-01-13
5
+ **Status**: Draft
6
+ **Input**: User description: "Todo-AI-Chatbot – Spec 1 (Conversational UI + Basic Agent Wiring) - Building the Todo AI Chatbot user-facing experience and basic AI agent wiring. This spec focuses on frontend UI, conversational flow, and initial agent integration, while strictly preserving the existing project folder structure."
7
+
8
+ ## User Scenarios & Testing *(mandatory)*
9
+
10
+ ### User Story 1 - Basic Chat Interaction (Priority: P1)
11
+
12
+ As a user, I want to interact with an AI chatbot through a conversational interface so that I can communicate naturally about my todo tasks without learning complex UI patterns.
13
+
14
+ **Why this priority**: This is the foundational capability that enables all other features. Without a working chat interface, users cannot interact with the AI assistant at all. This represents the minimum viable product.
15
+
16
+ **Independent Test**: Can be fully tested by opening the chat page, sending a message, and receiving a response from the AI agent. Delivers immediate value by establishing the conversational interaction pattern.
17
+
18
+ **Acceptance Scenarios**:
19
+
20
+ 1. **Given** I am on the chat page, **When** I type a message and press send, **Then** my message appears in the chat history and the AI responds with a relevant reply
21
+ 2. **Given** I have sent a message, **When** the AI is processing my request, **Then** I see a typing indicator showing the AI is working
22
+ 3. **Given** I am using a mobile device, **When** I access the chat interface, **Then** the UI adapts responsively to my screen size
23
+ 4. **Given** I have an active conversation, **When** I refresh the page, **Then** my conversation history persists and I can continue where I left off
24
+
25
+ ---
26
+
27
+ ### User Story 2 - Todo Intent Recognition (Priority: P2)
28
+
29
+ As a user, I want the AI to understand and acknowledge my todo-related requests so that I know the system recognizes my intent even if it cannot execute actions yet.
30
+
31
+ **Why this priority**: This validates that the AI agent can interpret user intent correctly, which is essential before adding tool execution capabilities in Spec-2. It provides user confidence that the system understands their needs.
32
+
33
+ **Independent Test**: Can be tested by sending various todo-related messages (e.g., "add a task", "show my tasks", "mark task as done") and verifying the AI acknowledges the intent with appropriate responses.
34
+
35
+ **Acceptance Scenarios**:
36
+
37
+ 1. **Given** I am chatting with the AI, **When** I say "I need to add a new task", **Then** the AI acknowledges my intent and explains what it can do
38
+ 2. **Given** I ask about my existing tasks, **When** the AI responds, **Then** it provides a friendly explanation that task management will be available soon
39
+ 3. **Given** I use ambiguous language, **When** the AI is unsure of my intent, **Then** it asks clarifying questions to better understand my needs
40
+ 4. **Given** I make a general inquiry, **When** the AI responds, **Then** it maintains a conversational and helpful tone
41
+
42
+ ---
43
+
44
+ ### User Story 3 - Multi-Turn Conversations (Priority: P3)
45
+
46
+ As a user, I want to have multi-turn conversations with the AI where it remembers context from earlier messages so that I can have natural, flowing discussions without repeating myself.
47
+
48
+ **Why this priority**: This enhances the conversational experience by making interactions feel more natural and human-like. While important for user experience, it's not critical for the initial MVP.
49
+
50
+ **Independent Test**: Can be tested by having a conversation with multiple back-and-forth exchanges and verifying the AI maintains context throughout the conversation.
51
+
52
+ **Acceptance Scenarios**:
53
+
54
+ 1. **Given** I have mentioned a specific task in a previous message, **When** I refer to "that task" in a follow-up message, **Then** the AI understands the reference from context
55
+ 2. **Given** I am in the middle of a conversation, **When** I ask a follow-up question, **Then** the AI responds based on the full conversation history
56
+ 3. **Given** I have a long conversation history, **When** the context window limit is approached, **Then** the system gracefully trims older messages while preserving recent context
57
+
58
+ ---
59
+
60
+ ### User Story 4 - Free-Tier API Compatibility (Priority: P1)
61
+
62
+ As a developer/user, I want the system to work reliably with free-tier AI API providers so that I can use the chatbot without incurring significant costs.
63
+
64
+ **Why this priority**: This is a critical constraint for the hackathon project and ensures accessibility. Without this, the system would be too expensive to run during development and testing.
65
+
66
+ **Independent Test**: Can be tested by configuring different free-tier providers (Gemini, OpenRouter, Cohere) and verifying the chatbot works correctly with each, respecting rate limits and handling failures gracefully.
67
+
68
+ **Acceptance Scenarios**:
69
+
70
+ 1. **Given** I am using a free-tier API key, **When** I send messages to the chatbot, **Then** the system respects rate limits and does not exceed free-tier quotas
71
+ 2. **Given** the API rate limit is reached, **When** I send a new message, **Then** the system displays a user-friendly error message and suggests waiting
72
+ 3. **Given** I switch between different AI providers, **When** I configure the system, **Then** the chatbot works consistently across all supported providers
73
+ 4. **Given** the conversation history is growing, **When** the context window approaches the limit, **Then** the system automatically trims history to stay within free-tier constraints
74
+
75
+ ---
76
+
77
+ ### Edge Cases
78
+
79
+ - What happens when the user sends an empty message?
80
+ - How does the system handle network failures during message transmission?
81
+ - What happens when the AI API is temporarily unavailable?
82
+ - How does the system handle extremely long user messages that exceed API limits?
83
+ - What happens when the user rapidly sends multiple messages in quick succession?
84
+ - How does the system handle special characters, emojis, and non-English text in messages?
85
+ - What happens when the conversation history grows very large (100+ messages)?
86
+ - How does the system handle concurrent requests from the same user?
87
+
88
+ ## Requirements *(mandatory)*
89
+
90
+ ### Functional Requirements
91
+
92
+ #### Frontend Requirements
93
+
94
+ - **FR-001**: System MUST provide a chat interface using OpenAI ChatKit integrated within the existing Next.js app structure
95
+ - **FR-002**: System MUST display a message input field, message list, typing indicator, and loading states
96
+ - **FR-003**: System MUST render the chat UI responsively for both desktop and mobile devices
97
+ - **FR-004**: System MUST display user messages and AI responses in a clear, visually distinct manner
98
+ - **FR-005**: System MUST show a typing indicator when the AI is processing a response
99
+ - **FR-006**: System MUST persist conversation history across page refreshes
100
+ - **FR-007**: System MUST allow users to scroll through conversation history
101
+ - **FR-008**: System MUST provide visual feedback when a message is being sent
102
+ - **FR-009**: Frontend MUST NOT include direct task manipulation UI (deferred to Spec-2)
103
+
104
+ #### Backend Requirements
105
+
106
+ - **FR-010**: System MUST provide a stateless chat endpoint at POST /api/{user_id}/chat
107
+ - **FR-011**: System MUST accept user messages through the chat endpoint
108
+ - **FR-012**: System MUST create or retrieve conversation records for each user
109
+ - **FR-013**: System MUST persist both user and assistant messages using SQLModel
110
+ - **FR-014**: System MUST implement a Conversation model to track conversation metadata
111
+ - **FR-015**: System MUST implement a Message model to store individual messages with role (user/assistant), content, and timestamp
112
+ - **FR-016**: System MUST call the AI agent runner to generate responses
113
+ - **FR-017**: System MUST return assistant responses to the frontend in a structured format
114
+ - **FR-018**: Backend MUST remain stateless between requests (no in-memory session storage)
115
+
116
+ #### AI Agent Requirements
117
+
118
+ - **FR-019**: System MUST use OpenAI Agents SDK or a compatible abstraction for agent implementation
119
+ - **FR-020**: AI agent MUST maintain a conversational and friendly tone in all responses
120
+ - **FR-021**: AI agent MUST ask clarifying questions when user intent is ambiguous
121
+ - **FR-022**: AI agent MUST acknowledge user requests related to todos with natural language confirmations
122
+ - **FR-023**: AI agent MUST provide friendly guidance about its current capabilities
123
+ - **FR-024**: AI agent MUST NOT execute tool calls or task CRUD operations (deferred to Spec-2)
124
+ - **FR-025**: System MUST support configuration for multiple free-tier AI providers (Gemini, OpenRouter, Cohere)
125
+ - **FR-026**: System MUST respect free-tier API rate limits and avoid long context windows
126
+ - **FR-027**: System MUST fail gracefully when rate-limited, providing user-friendly error messages
127
+ - **FR-028**: System MUST trim conversation history when approaching context window limits
128
+
129
+ #### Conversation Flow Requirements
130
+
131
+ - **FR-029**: System MUST load conversation history from the database when a user sends a message
132
+ - **FR-030**: System MUST append new user messages to the conversation history
133
+ - **FR-031**: System MUST run the AI agent with the full message history as context
134
+ - **FR-032**: System MUST store assistant replies in the database before returning them to the frontend
135
+ - **FR-033**: System MUST handle errors at each step of the conversation flow and provide meaningful feedback
136
+
137
+ ### Key Entities *(include if feature involves data)*
138
+
139
+ - **Conversation**: Represents a conversation session between a user and the AI assistant. Key attributes include conversation ID, user ID, creation timestamp, last updated timestamp, and conversation metadata (e.g., title, status).
140
+
141
+ - **Message**: Represents an individual message within a conversation. Key attributes include message ID, conversation ID (foreign key), role (user or assistant), content (message text), timestamp, and optional metadata (e.g., token count, model used).
142
+
143
+ - **User**: Represents the authenticated user interacting with the chatbot. Relationship: One user can have many conversations.
144
+
145
+ ## Success Criteria *(mandatory)*
146
+
147
+ ### Measurable Outcomes
148
+
149
+ - **SC-001**: Users can send a message and receive an AI response within 5 seconds under normal conditions
150
+ - **SC-002**: Conversation history persists correctly across page refreshes with 100% accuracy
151
+ - **SC-003**: The chat interface renders correctly on mobile devices (320px width) and desktop devices (1920px width)
152
+ - **SC-004**: The system successfully handles at least 3 different free-tier AI providers (Gemini, OpenRouter, Cohere) without code changes
153
+ - **SC-005**: The system gracefully handles rate limiting with user-friendly error messages in 100% of rate-limit scenarios
154
+ - **SC-006**: Users can complete a basic chat interaction (send message, receive response) in under 30 seconds
155
+ - **SC-007**: The AI agent correctly acknowledges todo-related intent in at least 90% of test cases
156
+ - **SC-008**: The system maintains conversation context across at least 10 consecutive message exchanges
157
+ - **SC-009**: The existing folder structure remains unchanged (all frontend code in frontend/, all backend code in backend/)
158
+ - **SC-010**: The implementation provides a clear foundation for Spec-2 MCP integration with well-defined extension points
159
+
160
+ ## Scope Boundaries *(mandatory)*
161
+
162
+ ### In Scope
163
+
164
+ - Chat-based UI using OpenAI ChatKit
165
+ - Stateless chat API endpoint (POST /api/{user_id}/chat)
166
+ - AI agent configuration compatible with free-tier API keys
167
+ - Conversation and message persistence using SQLModel
168
+ - End-to-end conversational loop (UI → API → Agent → UI)
169
+ - Basic intent recognition and acknowledgment
170
+ - Responsive UI design for desktop and mobile
171
+ - Error handling and graceful degradation
172
+
173
+ ### Out of Scope (Explicitly Deferred to Spec-2)
174
+
175
+ - MCP server implementation
176
+ - Task CRUD tools (add_task, list_tasks, update_task, delete_task)
177
+ - Tool execution capabilities for the AI agent
178
+ - Advanced backend orchestration and tool chaining
179
+ - Performance optimizations and production hardening
180
+ - User authentication and authorization (assumes existing auth system)
181
+ - Multi-user conversation support
182
+ - Conversation search and filtering
183
+ - Export/import conversation history
184
+
185
+ ## Constraints *(mandatory)*
186
+
187
+ ### Technical Constraints
188
+
189
+ - **TC-001**: All frontend work MUST be implemented within the existing `frontend/` folder
190
+ - **TC-002**: All backend work MUST be implemented within the existing `backend/` folder
191
+ - **TC-003**: No restructuring or relocation of existing files is allowed
192
+ - **TC-004**: Must use FastAPI for backend (already structured)
193
+ - **TC-005**: Must use Next.js for frontend (already structured)
194
+ - **TC-006**: Must use SQLModel for database models
195
+ - **TC-007**: Must be compatible with free-tier AI API providers (Gemini, OpenRouter, Cohere)
196
+ - **TC-008**: Must respect free-tier API rate limits
197
+ - **TC-009**: Must avoid long context windows to minimize API costs
198
+
199
+ ### Development Constraints
200
+
201
+ - **DC-001**: No manual coding outside Claude Code execution
202
+ - **DC-002**: Must follow constitution and CLAUDE.md rules
203
+ - **DC-003**: Must adhere to Spec-Driven Development workflow
204
+ - **DC-004**: Must create PHR (Prompt History Record) after completion
205
+
206
+ ### Business Constraints
207
+
208
+ - **BC-001**: This is Phase III of a hackathon project with time constraints
209
+ - **BC-002**: Must provide a clear foundation for Spec-2 implementation
210
+ - **BC-003**: Must demonstrate working end-to-end functionality for hackathon evaluation
211
+
212
+ ## Assumptions *(mandatory)*
213
+
214
+ - **A-001**: The existing Next.js frontend and FastAPI backend are functional and properly configured
215
+ - **A-002**: Database connectivity is already established and working
216
+ - **A-003**: User authentication is already implemented and provides user_id for API calls
217
+ - **A-004**: OpenAI ChatKit library is compatible with the existing Next.js version
218
+ - **A-005**: Free-tier API keys for at least one provider (Gemini, OpenRouter, or Cohere) are available
219
+ - **A-006**: The existing database supports SQLModel and can store conversation/message data
220
+ - **A-007**: Network connectivity is reliable for API calls to AI providers
221
+ - **A-008**: The OpenAI Agents SDK or compatible abstraction is available and documented
222
+
223
+ ## Dependencies *(mandatory)*
224
+
225
+ ### External Dependencies
226
+
227
+ - **ED-001**: OpenAI ChatKit library for chat UI components
228
+ - **ED-002**: OpenAI Agents SDK or compatible abstraction for agent implementation
229
+ - **ED-003**: Free-tier AI API providers (Gemini, OpenRouter, Cohere)
230
+ - **ED-004**: SQLModel library for database models
231
+ - **ED-005**: FastAPI framework for backend API
232
+ - **ED-006**: Next.js framework for frontend
233
+
234
+ ### Internal Dependencies
235
+
236
+ - **ID-001**: Existing authentication system to provide user_id
237
+ - **ID-002**: Existing database infrastructure
238
+ - **ID-003**: Existing frontend and backend folder structures
239
+ - **ID-004**: Existing task management data models (for future Spec-2 integration)
240
+
241
+ ### Blocking Dependencies
242
+
243
+ - **BD-001**: Access to at least one free-tier AI API key (Gemini, OpenRouter, or Cohere)
244
+ - **BD-002**: Confirmation that OpenAI ChatKit is compatible with the current Next.js version
245
+
246
+ ## Risks *(mandatory)*
247
+
248
+ ### Technical Risks
249
+
250
+ - **TR-001**: OpenAI ChatKit may have compatibility issues with the existing Next.js setup
251
+ - **Mitigation**: Test ChatKit integration early; have fallback plan to use alternative chat UI library
252
+
253
+ - **TR-002**: Free-tier API rate limits may be too restrictive for development and testing
254
+ - **Mitigation**: Implement aggressive conversation history trimming; use multiple API keys for testing
255
+
256
+ - **TR-003**: AI agent responses may be inconsistent across different providers
257
+ - **Mitigation**: Implement provider-agnostic response handling; test with all three providers early
258
+
259
+ - **TR-004**: Conversation history may grow too large and impact performance
260
+ - **Mitigation**: Implement automatic history trimming; set maximum conversation length limits
261
+
262
+ ### Project Risks
263
+
264
+ - **PR-001**: Scope creep may lead to implementing Spec-2 features prematurely
265
+ - **Mitigation**: Strictly adhere to scope boundaries; defer all tool execution to Spec-2
266
+
267
+ - **PR-002**: Integration with existing codebase may reveal unexpected issues
268
+ - **Mitigation**: Conduct early integration testing; document all assumptions about existing code
269
+
270
+ ## Notes for Next Spec (Spec-2)
271
+
272
+ Spec-2 will introduce:
273
+ - MCP server implementation for tool execution
274
+ - Task CRUD tools (add_task, list_tasks, update_task, delete_task, complete_task)
275
+ - Tool-driven agent behavior with function calling
276
+ - Full todo functionality integrated with the conversational interface
277
+ - Advanced backend orchestration and tool chaining
278
+ - Performance optimizations and production hardening
specs/001-todo-ai-chatbot/tasks.md ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Tasks: Todo AI Chatbot - Phase 1
2
+
3
+ **Feature**: 001-todo-ai-chatbot
4
+ **Branch**: `001-todo-ai-chatbot`
5
+ **Spec**: [spec.md](./spec.md) | **Plan**: [plan.md](./plan.md)
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ This document defines the implementation tasks for the Todo AI Chatbot Phase 1 feature. Tasks are organized by user story to enable independent implementation and testing.
12
+
13
+ **Total Tasks**: 28
14
+ **Estimated Timeline**: 2-3 days
15
+
16
+ ---
17
+
18
+ ## Task Summary by User Story
19
+
20
+ | User Story | Priority | Task Count | Parallel Opportunities |
21
+ |------------|----------|------------|------------------------|
22
+ | Setup | N/A | 5 | 2 parallel tasks |
23
+ | Foundational | N/A | 4 | 3 parallel tasks |
24
+ | US1 + US4: Basic Chat + Free-Tier | P1 | 11 | 6 parallel tasks |
25
+ | US2: Intent Recognition | P2 | 3 | 2 parallel tasks |
26
+ | US3: Multi-Turn Conversations | P3 | 2 | 1 parallel task |
27
+ | Polish & Cross-Cutting | N/A | 3 | 2 parallel tasks |
28
+
29
+ ---
30
+
31
+ ## Dependencies & Execution Order
32
+
33
+ ```
34
+ Phase 1: Setup
35
+
36
+ Phase 2: Foundational (Models & Base Abstractions)
37
+
38
+ Phase 3: US1 + US4 (Basic Chat + Free-Tier) ← MVP Scope
39
+
40
+ Phase 4: US2 (Intent Recognition)
41
+
42
+ Phase 5: US3 (Multi-Turn Conversations)
43
+
44
+ Phase 6: Polish & Cross-Cutting
45
+ ```
46
+
47
+ **MVP Recommendation**: Complete Phase 1-3 only (Setup + Foundational + US1+US4) for minimum viable product.
48
+
49
+ ---
50
+
51
+ ## Phase 1: Setup
52
+
53
+ **Goal**: Configure project dependencies and environment for AI chatbot development.
54
+
55
+ **Agent**: Backend Systems Agent (`backend-mcp-tools`)
56
+
57
+ ### Tasks
58
+
59
+ - [X] T001 Install backend dependencies in backend/requirements.txt (google-generativeai==0.3.2, tiktoken==0.5.2)
60
+ - [X] T002 [P] Install frontend dependencies in frontend/package.json (@assistant-ui/react, ai)
61
+ - [X] T003 Configure environment variables in backend/.env (AI_PROVIDER, GEMINI_API_KEY, MAX_CONVERSATION_MESSAGES, MAX_CONVERSATION_TOKENS)
62
+ - [X] T004 Create database migration for conversation and message tables in backend/alembic/versions/
63
+ - [X] T005 Run database migration with alembic upgrade head
64
+
65
+ **Parallel Execution**: T002 can run in parallel with T001.
66
+
67
+ ---
68
+
69
+ ## Phase 2: Foundational (Blocking Prerequisites)
70
+
71
+ **Goal**: Implement core database models and base abstractions required by all user stories.
72
+
73
+ **Agent**: Backend Systems Agent (`backend-mcp-tools`)
74
+
75
+ ### Tasks
76
+
77
+ - [X] T006 [P] Create Conversation SQLModel in backend/src/models/conversation.py
78
+ - [X] T007 [P] Create Message SQLModel in backend/src/models/message.py
79
+ - [X] T008 [P] Create LLMProvider abstract base class in backend/src/services/providers/base.py
80
+ - [X] T009 Create GeminiProvider implementation in backend/src/services/providers/gemini.py
81
+
82
+ **Parallel Execution**: T006, T007, T008 can run in parallel (different files, no dependencies).
83
+
84
+ ---
85
+
86
+ ## Phase 3: User Story 1 + 4 - Basic Chat Interaction + Free-Tier API Compatibility (P1)
87
+
88
+ **Story Goal**: Enable users to interact with an AI chatbot through a conversational interface that works reliably with free-tier AI providers.
89
+
90
+ **Why Combined**: Both are P1 priority and tightly coupled - basic chat requires free-tier provider integration from the start.
91
+
92
+ **Independent Test Criteria**:
93
+ - ✅ User can open chat page and send a message
94
+ - ✅ AI responds with relevant reply using Gemini free-tier API
95
+ - ✅ Conversation history persists across page refreshes
96
+ - ✅ Typing indicator shows while AI is processing
97
+ - ✅ UI is responsive on mobile and desktop
98
+ - ✅ System respects rate limits and handles errors gracefully
99
+
100
+ **Agents**:
101
+ - Backend Systems Agent (`backend-mcp-tools`) - Backend implementation
102
+ - Frontend UI Builder Agent (`nextjs-ui-generator`) - Frontend components
103
+ - Design & Theme Agent (`design-theme`) - UI styling
104
+
105
+ ### Backend Tasks
106
+
107
+ - [X] T010 [P] [US1] Create LLMService with provider factory in backend/src/services/llm_service.py
108
+ - [X] T011 [P] [US1] Create ConversationService for CRUD operations in backend/src/services/conversation_service.py
109
+ - [X] T012 [P] [US1] Create ChatRequest Pydantic schema in backend/src/schemas/chat_request.py
110
+ - [X] T013 [P] [US1] Create ChatResponse Pydantic schema in backend/src/schemas/chat_response.py
111
+ - [X] T014 [US1] Create chat API endpoint POST /api/{user_id}/chat in backend/src/api/routes/chat.py
112
+ - [X] T015 [US1] Register chat router in backend/src/main.py
113
+
114
+ ### Frontend Tasks
115
+
116
+ - [X] T016 [P] [US1] Create chat service API client in frontend/src/services/chatService.ts
117
+ - [X] T017 [P] [US1] Create TypeScript types for chat in frontend/src/types/chat.ts
118
+ - [X] T018 [US1] Create ChatInterface component in frontend/src/components/chat/ChatInterface.tsx
119
+ - [X] T019 [US1] Create MessageList component in frontend/src/components/chat/MessageList.tsx
120
+ - [X] T020 [US1] Create MessageInput component in frontend/src/components/chat/MessageInput.tsx
121
+ - [X] T021 [US1] Create TypingIndicator component in frontend/src/components/chat/TypingIndicator.tsx
122
+ - [X] T022 [US1] Create chat page in frontend/src/app/chat/page.tsx
123
+
124
+ **Parallel Execution**:
125
+ - Backend: T010, T011, T012, T013 can run in parallel
126
+ - Frontend: T016, T017 can run in parallel
127
+ - After T014-T015 complete (backend), all frontend tasks T016-T022 can proceed in parallel
128
+
129
+ ---
130
+
131
+ ## Phase 4: User Story 2 - Todo Intent Recognition (P2)
132
+
133
+ **Story Goal**: AI understands and acknowledges todo-related requests, providing user confidence that the system recognizes their intent.
134
+
135
+ **Independent Test Criteria**:
136
+ - ✅ AI acknowledges "add a task" intent with appropriate response
137
+ - ✅ AI explains task management will be available in Phase 2
138
+ - ✅ AI asks clarifying questions for ambiguous requests
139
+ - ✅ AI maintains conversational and helpful tone
140
+
141
+ **Agent**: Conversational AI Architect Agent (`agent-behavior-reasoning`)
142
+
143
+ ### Tasks
144
+
145
+ - [X] T023 [P] [US2] Add intent detection prompt engineering to GeminiProvider in backend/src/services/providers/gemini.py
146
+ - [X] T024 [P] [US2] Create system prompt for todo intent recognition in backend/src/services/llm_service.py
147
+ - [X] T025 [US2] Add intent acknowledgment response templates in backend/src/services/llm_service.py
148
+
149
+ **Parallel Execution**: T023 and T024 can run in parallel (different concerns).
150
+
151
+ ---
152
+
153
+ ## Phase 5: User Story 3 - Multi-Turn Conversations (P3)
154
+
155
+ **Story Goal**: Enable multi-turn conversations where AI remembers context from earlier messages for natural, flowing discussions.
156
+
157
+ **Independent Test Criteria**:
158
+ - ✅ AI understands references to previous messages ("that task")
159
+ - ✅ AI responds based on full conversation history
160
+ - ✅ System gracefully trims older messages when approaching context limit
161
+
162
+ **Agent**: Backend Systems Agent (`backend-mcp-tools`)
163
+
164
+ ### Tasks
165
+
166
+ - [X] T026 [P] [US3] Implement conversation history trimming logic in backend/src/services/conversation_service.py
167
+ - [X] T027 [US3] Add context window management to LLMService in backend/src/services/llm_service.py
168
+
169
+ **Parallel Execution**: T026 can be implemented independently and integrated in T027.
170
+
171
+ ---
172
+
173
+ ## Phase 6: Polish & Cross-Cutting Concerns
174
+
175
+ **Goal**: Enhance error handling, responsive design, and documentation.
176
+
177
+ **Agents**:
178
+ - Backend Systems Agent (`backend-mcp-tools`) - Error handling
179
+ - Design & Theme Agent (`design-theme`) - Responsive design
180
+
181
+ ### Tasks
182
+
183
+ - [X] T028 [P] Add comprehensive error handling to chat endpoint in backend/src/api/routes/chat.py (400, 401, 429, 500 errors)
184
+ - [X] T029 [P] Verify responsive design for mobile (320px) and desktop (1920px) in frontend/src/components/chat/
185
+ - [X] T030 Update README with setup instructions and API documentation in backend/README.md
186
+
187
+ **Parallel Execution**: T028 and T029 can run in parallel (backend vs frontend).
188
+
189
+ ---
190
+
191
+ ## Parallel Execution Examples
192
+
193
+ ### Phase 1: Setup
194
+ ```bash
195
+ # Terminal 1: Backend dependencies
196
+ cd backend && pip install -r requirements.txt
197
+
198
+ # Terminal 2: Frontend dependencies (parallel)
199
+ cd frontend && npm install
200
+ ```
201
+
202
+ ### Phase 2: Foundational
203
+ ```bash
204
+ # All three models can be created in parallel
205
+ # Terminal 1: Conversation model
206
+ # Terminal 2: Message model
207
+ # Terminal 3: LLMProvider base class
208
+ ```
209
+
210
+ ### Phase 3: User Story 1 + 4
211
+ ```bash
212
+ # Backend tasks T010-T013 in parallel
213
+ # Then T014-T015 sequentially
214
+ # Then all frontend tasks T016-T022 in parallel
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Implementation Strategy
220
+
221
+ ### MVP Scope (Phases 1-3)
222
+
223
+ **Recommended for initial delivery**:
224
+ - Phase 1: Setup (T001-T005)
225
+ - Phase 2: Foundational (T006-T009)
226
+ - Phase 3: US1 + US4 (T010-T022)
227
+
228
+ **Delivers**:
229
+ - Working chat interface
230
+ - AI responses via Gemini free-tier
231
+ - Conversation persistence
232
+ - Responsive UI
233
+ - Basic error handling
234
+
235
+ **Timeline**: 2 days
236
+
237
+ ### Full Feature Scope (All Phases)
238
+
239
+ **Includes MVP + enhancements**:
240
+ - Phase 4: US2 - Intent Recognition (T023-T025)
241
+ - Phase 5: US3 - Multi-Turn Conversations (T026-T027)
242
+ - Phase 6: Polish (T028-T030)
243
+
244
+ **Timeline**: 3 days
245
+
246
+ ---
247
+
248
+ ## Acceptance Criteria
249
+
250
+ ### Phase 1-3 (MVP) Acceptance
251
+
252
+ - [ ] User can navigate to /chat page
253
+ - [ ] User can send a message and receive AI response
254
+ - [ ] Conversation history persists on page refresh
255
+ - [ ] Typing indicator shows during AI processing
256
+ - [ ] UI is responsive on mobile and desktop
257
+ - [ ] System works with Gemini free-tier API
258
+ - [ ] JWT authentication protects chat endpoint
259
+ - [ ] Errors are handled gracefully
260
+
261
+ ### Phase 4-6 (Full Feature) Acceptance
262
+
263
+ - [ ] AI acknowledges todo-related intents
264
+ - [ ] AI maintains context across multiple messages
265
+ - [ ] System trims conversation history appropriately
266
+ - [ ] All error scenarios return user-friendly messages
267
+ - [ ] Documentation is complete and accurate
268
+
269
+ ---
270
+
271
+ ## Risk Mitigation
272
+
273
+ | Risk | Mitigation Task |
274
+ |------|----------------|
275
+ | Gemini API rate limits | T003 (configure rate limit handling), T028 (error handling) |
276
+ | Frontend-backend integration issues | T016 (API client with proper error handling) |
277
+ | Conversation history growth | T026 (history trimming logic) |
278
+ | Mobile responsiveness issues | T029 (responsive design verification) |
279
+
280
+ ---
281
+
282
+ ## Next Steps After Task Completion
283
+
284
+ 1. Run full integration test (send message, verify response, check persistence)
285
+ 2. Test with different free-tier providers (Gemini, OpenRouter)
286
+ 3. Verify responsive design on actual mobile devices
287
+ 4. Create PHR documenting implementation
288
+ 5. Prepare for Phase 2 (Spec-2): MCP tools and task CRUD operations
289
+
290
+ ---
291
+
292
+ ## Notes
293
+
294
+ - **No tests requested**: Spec does not explicitly request TDD approach, so test tasks are omitted
295
+ - **Agent-skill alignment**: All tasks reference appropriate agents from Agent-Skill Enforcement Matrix
296
+ - **File paths**: All tasks include specific file paths for implementation
297
+ - **Parallelization**: 15 tasks marked [P] for parallel execution opportunities
298
+ - **User story mapping**: All implementation tasks mapped to user stories for traceability
specs/002-fullstack-ui-integration/checklists/requirements.md ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Specification Quality Checklist: Full-Stack Integration & UI Experience
2
+
3
+ **Purpose**: Validate specification completeness and quality before proceeding to planning
4
+ **Created**: 2026-01-09
5
+ **Feature**: [spec.md](../spec.md)
6
+
7
+ ## Content Quality
8
+
9
+ - [x] No implementation details (languages, frameworks, APIs)
10
+ - [x] Focused on user value and business needs
11
+ - [x] Written for non-technical stakeholders
12
+ - [x] All mandatory sections completed
13
+
14
+ ## Requirement Completeness
15
+
16
+ - [x] No [NEEDS CLARIFICATION] markers remain
17
+ - [x] Requirements are testable and unambiguous
18
+ - [x] Success criteria are measurable
19
+ - [x] Success criteria are technology-agnostic (no implementation details)
20
+ - [x] All acceptance scenarios are defined
21
+ - [x] Edge cases are identified
22
+ - [x] Scope is clearly bounded
23
+ - [x] Dependencies and assumptions identified
24
+
25
+ ## Feature Readiness
26
+
27
+ - [x] All functional requirements have clear acceptance criteria
28
+ - [x] User scenarios cover primary flows
29
+ - [x] Feature meets measurable outcomes defined in Success Criteria
30
+ - [x] No implementation details leak into specification
31
+
32
+ ## Validation Results
33
+
34
+ ### Content Quality Assessment
35
+
36
+ ✅ **Pass**: The specification focuses on user experience and integration outcomes without prescribing implementation details. While it mentions existing technologies (Next.js, FastAPI, etc.) in the constraints and dependencies sections, these are appropriately documented as context rather than requirements.
37
+
38
+ ✅ **Pass**: The specification is written for business stakeholders and hackathon reviewers, focusing on "what" users need rather than "how" to build it.
39
+
40
+ ✅ **Pass**: All mandatory sections are complete: User Scenarios, Requirements, Success Criteria, Assumptions, Dependencies, Out of Scope, and References.
41
+
42
+ ### Requirement Completeness Assessment
43
+
44
+ ✅ **Pass**: No [NEEDS CLARIFICATION] markers present. All requirements are specific and actionable.
45
+
46
+ ✅ **Pass**: All 20 functional requirements are testable with clear acceptance criteria. Each requirement uses "MUST" and describes a specific, verifiable capability.
47
+
48
+ ✅ **Pass**: All 10 success criteria are measurable with specific metrics:
49
+ - SC-001: "under 3 minutes" (time-based)
50
+ - SC-002: "within 100ms" (performance-based)
51
+ - SC-003: "80% of new users" (percentage-based)
52
+ - SC-004: "90% of the time" (percentage-based)
53
+ - SC-005: "320px to 1920px" (range-based)
54
+ - SC-006: "zero accidental clicks" (count-based)
55
+ - SC-007: "zero application crashes" (count-based)
56
+ - SC-008: "zero unhandled promise rejections" (count-based)
57
+ - SC-009: "under 10 minutes" (time-based)
58
+ - SC-010: "works end-to-end" (binary outcome)
59
+
60
+ ✅ **Pass**: Success criteria are technology-agnostic and focus on user outcomes rather than implementation details.
61
+
62
+ ✅ **Pass**: All 5 user stories have detailed acceptance scenarios with Given-When-Then format. Total of 30 acceptance scenarios across all stories.
63
+
64
+ ✅ **Pass**: 8 edge cases identified covering token expiration, rapid API calls, server errors, special characters, unauthorized access, navigation, localStorage availability, and concurrent edits.
65
+
66
+ ✅ **Pass**: Scope is clearly bounded with comprehensive "Out of Scope" section listing 15 explicitly excluded items.
67
+
68
+ ✅ **Pass**: Dependencies section lists both internal (Spec 1, Spec 2, Backend API, Database) and external (Next.js, React, TypeScript, etc.) dependencies. Assumptions section lists 10 clear assumptions.
69
+
70
+ ### Feature Readiness Assessment
71
+
72
+ ✅ **Pass**: Each of the 20 functional requirements maps to specific acceptance scenarios in the user stories.
73
+
74
+ ✅ **Pass**: 5 user stories cover the complete integration flow from authentication (P1) through UI states (P2), responsive design (P3), API communication (P4), and environment setup (P5).
75
+
76
+ ✅ **Pass**: The feature delivers measurable outcomes that can be verified without knowing implementation details. All success criteria focus on user experience and system behavior.
77
+
78
+ ✅ **Pass**: The specification maintains separation between requirements (what) and implementation (how). Technology mentions are appropriately scoped to constraints and dependencies sections.
79
+
80
+ ## Notes
81
+
82
+ **Strengths**:
83
+ 1. Comprehensive coverage of integration and UI experience concerns
84
+ 2. Clear prioritization with P1-P5 user stories
85
+ 3. Detailed acceptance scenarios (30 total) provide excellent testability
86
+ 4. Success criteria are specific and measurable
87
+ 5. Well-defined scope boundaries with explicit out-of-scope items
88
+ 6. Strong focus on user experience and feedback mechanisms
89
+
90
+ **Observations**:
91
+ 1. This is an integration/polish spec rather than a new feature spec, which is appropriate for Phase II
92
+ 2. The spec correctly builds on Specs 1 and 2 without duplicating their functionality
93
+ 3. The focus on loading states, error handling, and responsive design demonstrates maturity
94
+ 4. The environment coordination story (P5) ensures the application is reviewable by hackathon judges
95
+
96
+ **Recommendation**: ✅ **APPROVED** - Specification is ready for planning phase (`/sp.plan`)
97
+
98
+ All checklist items pass validation. The specification is complete, testable, and ready for implementation planning.
specs/002-fullstack-ui-integration/contracts/existing-api-reference.yaml ADDED
@@ -0,0 +1,611 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Phase II Todo Web App - API Reference
4
+ description: |
5
+ Complete API reference for the Full-Stack Todo Web Application.
6
+ This document references existing endpoints from Specs 1 (Task CRUD) and 2 (Authentication & API Security).
7
+
8
+ **Base URL**: http://localhost:8000
9
+
10
+ **Authentication**: All task endpoints require JWT Bearer token in Authorization header.
11
+
12
+ **Note**: This is a reference document for integration purposes. No new endpoints are introduced in Spec 002.
13
+ version: 1.0.0
14
+ contact:
15
+ name: Phase II Todo Web App
16
+
17
+ servers:
18
+ - url: http://localhost:8000
19
+ description: Local development server
20
+
21
+ tags:
22
+ - name: Authentication
23
+ description: User signup, signin, and profile endpoints (Spec 2)
24
+ - name: Tasks
25
+ description: Task CRUD operations (Spec 1)
26
+
27
+ security:
28
+ - BearerAuth: []
29
+
30
+ paths:
31
+ /api/auth/signup:
32
+ post:
33
+ tags:
34
+ - Authentication
35
+ summary: Register new user account
36
+ description: Creates a new user account with email, password, and name. Password is hashed with bcrypt before storage.
37
+ operationId: signup
38
+ security: []
39
+ requestBody:
40
+ required: true
41
+ content:
42
+ application/json:
43
+ schema:
44
+ $ref: '#/components/schemas/SignupRequest'
45
+ example:
46
+ email: user@example.com
47
+ password: SecurePass123
48
+ name: John Doe
49
+ responses:
50
+ '201':
51
+ description: User created successfully
52
+ content:
53
+ application/json:
54
+ schema:
55
+ $ref: '#/components/schemas/SignupResponse'
56
+ example:
57
+ id: 1
58
+ email: user@example.com
59
+ name: John Doe
60
+ created_at: "2026-01-09T10:00:00Z"
61
+ '400':
62
+ description: Validation error (invalid email, weak password)
63
+ content:
64
+ application/json:
65
+ schema:
66
+ $ref: '#/components/schemas/ErrorResponse'
67
+ example:
68
+ detail: Password must be at least 8 characters with uppercase, lowercase, and number
69
+ error_code: VALIDATION_ERROR
70
+ '409':
71
+ description: Email already registered
72
+ content:
73
+ application/json:
74
+ schema:
75
+ $ref: '#/components/schemas/ErrorResponse'
76
+ example:
77
+ detail: Email already registered
78
+ error_code: EMAIL_EXISTS
79
+
80
+ /api/auth/signin:
81
+ post:
82
+ tags:
83
+ - Authentication
84
+ summary: Authenticate user and issue JWT token
85
+ description: Verifies email and password, returns JWT token with 7-day expiration.
86
+ operationId: signin
87
+ security: []
88
+ requestBody:
89
+ required: true
90
+ content:
91
+ application/json:
92
+ schema:
93
+ $ref: '#/components/schemas/SigninRequest'
94
+ example:
95
+ email: user@example.com
96
+ password: SecurePass123
97
+ responses:
98
+ '200':
99
+ description: Authentication successful
100
+ content:
101
+ application/json:
102
+ schema:
103
+ $ref: '#/components/schemas/TokenResponse'
104
+ example:
105
+ access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
106
+ token_type: bearer
107
+ expires_in: 604800
108
+ user:
109
+ id: 1
110
+ email: user@example.com
111
+ name: John Doe
112
+ created_at: "2026-01-09T10:00:00Z"
113
+ '401':
114
+ description: Invalid credentials
115
+ content:
116
+ application/json:
117
+ schema:
118
+ $ref: '#/components/schemas/ErrorResponse'
119
+ example:
120
+ detail: Invalid email or password
121
+ error_code: INVALID_CREDENTIALS
122
+
123
+ /api/auth/me:
124
+ get:
125
+ tags:
126
+ - Authentication
127
+ summary: Get current user profile
128
+ description: Returns profile information for the authenticated user.
129
+ operationId: getCurrentUser
130
+ responses:
131
+ '200':
132
+ description: User profile retrieved successfully
133
+ content:
134
+ application/json:
135
+ schema:
136
+ $ref: '#/components/schemas/UserProfile'
137
+ example:
138
+ id: 1
139
+ email: user@example.com
140
+ name: John Doe
141
+ created_at: "2026-01-09T10:00:00Z"
142
+ '401':
143
+ description: Not authenticated or invalid token
144
+ content:
145
+ application/json:
146
+ schema:
147
+ $ref: '#/components/schemas/ErrorResponse'
148
+ example:
149
+ detail: Not authenticated
150
+ error_code: TOKEN_MISSING
151
+
152
+ /api/tasks:
153
+ get:
154
+ tags:
155
+ - Tasks
156
+ summary: List user's tasks with filtering and sorting
157
+ description: Returns all tasks for the authenticated user. Supports filtering by completion status and sorting.
158
+ operationId: getTasks
159
+ parameters:
160
+ - name: completed
161
+ in: query
162
+ description: Filter by completion status (true/false/null for all)
163
+ required: false
164
+ schema:
165
+ type: boolean
166
+ nullable: true
167
+ - name: sort
168
+ in: query
169
+ description: Sort field
170
+ required: false
171
+ schema:
172
+ type: string
173
+ enum: [created_at, updated_at]
174
+ default: created_at
175
+ - name: order
176
+ in: query
177
+ description: Sort order
178
+ required: false
179
+ schema:
180
+ type: string
181
+ enum: [asc, desc]
182
+ default: desc
183
+ - name: limit
184
+ in: query
185
+ description: Maximum number of results
186
+ required: false
187
+ schema:
188
+ type: integer
189
+ minimum: 1
190
+ maximum: 100
191
+ default: 50
192
+ - name: offset
193
+ in: query
194
+ description: Number of results to skip
195
+ required: false
196
+ schema:
197
+ type: integer
198
+ minimum: 0
199
+ default: 0
200
+ responses:
201
+ '200':
202
+ description: Tasks retrieved successfully
203
+ content:
204
+ application/json:
205
+ schema:
206
+ $ref: '#/components/schemas/TaskListResponse'
207
+ example:
208
+ tasks:
209
+ - id: 1
210
+ user_id: 1
211
+ title: Buy groceries
212
+ description: Milk, eggs, bread
213
+ completed: false
214
+ created_at: "2026-01-09T10:00:00Z"
215
+ updated_at: "2026-01-09T10:00:00Z"
216
+ - id: 2
217
+ user_id: 1
218
+ title: Finish project
219
+ description: null
220
+ completed: true
221
+ created_at: "2026-01-08T15:30:00Z"
222
+ updated_at: "2026-01-09T09:00:00Z"
223
+ total: 2
224
+ limit: 50
225
+ offset: 0
226
+ '401':
227
+ $ref: '#/components/responses/UnauthorizedError'
228
+
229
+ post:
230
+ tags:
231
+ - Tasks
232
+ summary: Create new task
233
+ description: Creates a new task for the authenticated user.
234
+ operationId: createTask
235
+ requestBody:
236
+ required: true
237
+ content:
238
+ application/json:
239
+ schema:
240
+ $ref: '#/components/schemas/TaskCreate'
241
+ example:
242
+ title: Buy groceries
243
+ description: Milk, eggs, bread
244
+ responses:
245
+ '201':
246
+ description: Task created successfully
247
+ content:
248
+ application/json:
249
+ schema:
250
+ $ref: '#/components/schemas/Task'
251
+ example:
252
+ id: 1
253
+ user_id: 1
254
+ title: Buy groceries
255
+ description: Milk, eggs, bread
256
+ completed: false
257
+ created_at: "2026-01-09T10:00:00Z"
258
+ updated_at: "2026-01-09T10:00:00Z"
259
+ '400':
260
+ description: Validation error
261
+ content:
262
+ application/json:
263
+ schema:
264
+ $ref: '#/components/schemas/ErrorResponse'
265
+ example:
266
+ detail: Title is required
267
+ error_code: VALIDATION_ERROR
268
+ '401':
269
+ $ref: '#/components/responses/UnauthorizedError'
270
+
271
+ /api/tasks/{task_id}:
272
+ get:
273
+ tags:
274
+ - Tasks
275
+ summary: Get single task
276
+ description: Returns a specific task if it belongs to the authenticated user.
277
+ operationId: getTask
278
+ parameters:
279
+ - name: task_id
280
+ in: path
281
+ required: true
282
+ schema:
283
+ type: integer
284
+ responses:
285
+ '200':
286
+ description: Task retrieved successfully
287
+ content:
288
+ application/json:
289
+ schema:
290
+ $ref: '#/components/schemas/Task'
291
+ '401':
292
+ $ref: '#/components/responses/UnauthorizedError'
293
+ '404':
294
+ description: Task not found or doesn't belong to user
295
+ content:
296
+ application/json:
297
+ schema:
298
+ $ref: '#/components/schemas/ErrorResponse'
299
+ example:
300
+ detail: Task not found
301
+ error_code: NOT_FOUND
302
+
303
+ put:
304
+ tags:
305
+ - Tasks
306
+ summary: Update task (replace all fields)
307
+ description: Replaces all task fields. All fields are required.
308
+ operationId: updateTask
309
+ parameters:
310
+ - name: task_id
311
+ in: path
312
+ required: true
313
+ schema:
314
+ type: integer
315
+ requestBody:
316
+ required: true
317
+ content:
318
+ application/json:
319
+ schema:
320
+ $ref: '#/components/schemas/TaskUpdate'
321
+ example:
322
+ title: Buy groceries (updated)
323
+ description: Milk, eggs, bread, cheese
324
+ completed: false
325
+ responses:
326
+ '200':
327
+ description: Task updated successfully
328
+ content:
329
+ application/json:
330
+ schema:
331
+ $ref: '#/components/schemas/Task'
332
+ '400':
333
+ description: Validation error
334
+ content:
335
+ application/json:
336
+ schema:
337
+ $ref: '#/components/schemas/ErrorResponse'
338
+ '401':
339
+ $ref: '#/components/responses/UnauthorizedError'
340
+ '404':
341
+ $ref: '#/components/responses/NotFoundError'
342
+
343
+ patch:
344
+ tags:
345
+ - Tasks
346
+ summary: Partially update task
347
+ description: Updates only the provided fields. Other fields remain unchanged.
348
+ operationId: patchTask
349
+ parameters:
350
+ - name: task_id
351
+ in: path
352
+ required: true
353
+ schema:
354
+ type: integer
355
+ requestBody:
356
+ required: true
357
+ content:
358
+ application/json:
359
+ schema:
360
+ $ref: '#/components/schemas/TaskPatch'
361
+ example:
362
+ completed: true
363
+ responses:
364
+ '200':
365
+ description: Task updated successfully
366
+ content:
367
+ application/json:
368
+ schema:
369
+ $ref: '#/components/schemas/Task'
370
+ '400':
371
+ description: Validation error
372
+ content:
373
+ application/json:
374
+ schema:
375
+ $ref: '#/components/schemas/ErrorResponse'
376
+ '401':
377
+ $ref: '#/components/responses/UnauthorizedError'
378
+ '404':
379
+ $ref: '#/components/responses/NotFoundError'
380
+
381
+ delete:
382
+ tags:
383
+ - Tasks
384
+ summary: Delete task
385
+ description: Permanently deletes a task if it belongs to the authenticated user.
386
+ operationId: deleteTask
387
+ parameters:
388
+ - name: task_id
389
+ in: path
390
+ required: true
391
+ schema:
392
+ type: integer
393
+ responses:
394
+ '204':
395
+ description: Task deleted successfully
396
+ '401':
397
+ $ref: '#/components/responses/UnauthorizedError'
398
+ '404':
399
+ $ref: '#/components/responses/NotFoundError'
400
+
401
+ components:
402
+ securitySchemes:
403
+ BearerAuth:
404
+ type: http
405
+ scheme: bearer
406
+ bearerFormat: JWT
407
+ description: JWT token obtained from /api/auth/signin
408
+
409
+ schemas:
410
+ SignupRequest:
411
+ type: object
412
+ required:
413
+ - email
414
+ - password
415
+ - name
416
+ properties:
417
+ email:
418
+ type: string
419
+ format: email
420
+ description: Valid email address (RFC 5322)
421
+ password:
422
+ type: string
423
+ minLength: 8
424
+ maxLength: 100
425
+ description: Min 8 chars with uppercase, lowercase, and number
426
+ name:
427
+ type: string
428
+ minLength: 1
429
+ maxLength: 100
430
+ description: User's display name
431
+
432
+ SignupResponse:
433
+ type: object
434
+ properties:
435
+ id:
436
+ type: integer
437
+ email:
438
+ type: string
439
+ name:
440
+ type: string
441
+ created_at:
442
+ type: string
443
+ format: date-time
444
+
445
+ SigninRequest:
446
+ type: object
447
+ required:
448
+ - email
449
+ - password
450
+ properties:
451
+ email:
452
+ type: string
453
+ format: email
454
+ password:
455
+ type: string
456
+
457
+ TokenResponse:
458
+ type: object
459
+ properties:
460
+ access_token:
461
+ type: string
462
+ description: JWT token
463
+ token_type:
464
+ type: string
465
+ enum: [bearer]
466
+ expires_in:
467
+ type: integer
468
+ description: Token expiration in seconds (604800 = 7 days)
469
+ user:
470
+ $ref: '#/components/schemas/UserProfile'
471
+
472
+ UserProfile:
473
+ type: object
474
+ properties:
475
+ id:
476
+ type: integer
477
+ email:
478
+ type: string
479
+ name:
480
+ type: string
481
+ created_at:
482
+ type: string
483
+ format: date-time
484
+
485
+ Task:
486
+ type: object
487
+ properties:
488
+ id:
489
+ type: integer
490
+ user_id:
491
+ type: integer
492
+ title:
493
+ type: string
494
+ maxLength: 200
495
+ description:
496
+ type: string
497
+ maxLength: 1000
498
+ nullable: true
499
+ completed:
500
+ type: boolean
501
+ created_at:
502
+ type: string
503
+ format: date-time
504
+ updated_at:
505
+ type: string
506
+ format: date-time
507
+
508
+ TaskCreate:
509
+ type: object
510
+ required:
511
+ - title
512
+ properties:
513
+ title:
514
+ type: string
515
+ minLength: 1
516
+ maxLength: 200
517
+ description:
518
+ type: string
519
+ maxLength: 1000
520
+ nullable: true
521
+
522
+ TaskUpdate:
523
+ type: object
524
+ required:
525
+ - title
526
+ - completed
527
+ properties:
528
+ title:
529
+ type: string
530
+ minLength: 1
531
+ maxLength: 200
532
+ description:
533
+ type: string
534
+ maxLength: 1000
535
+ nullable: true
536
+ completed:
537
+ type: boolean
538
+
539
+ TaskPatch:
540
+ type: object
541
+ properties:
542
+ title:
543
+ type: string
544
+ minLength: 1
545
+ maxLength: 200
546
+ description:
547
+ type: string
548
+ maxLength: 1000
549
+ nullable: true
550
+ completed:
551
+ type: boolean
552
+
553
+ TaskListResponse:
554
+ type: object
555
+ properties:
556
+ tasks:
557
+ type: array
558
+ items:
559
+ $ref: '#/components/schemas/Task'
560
+ total:
561
+ type: integer
562
+ limit:
563
+ type: integer
564
+ offset:
565
+ type: integer
566
+
567
+ ErrorResponse:
568
+ type: object
569
+ properties:
570
+ detail:
571
+ type: string
572
+ description: Human-readable error message
573
+ error_code:
574
+ type: string
575
+ description: Machine-readable error code
576
+ enum:
577
+ - VALIDATION_ERROR
578
+ - EMAIL_EXISTS
579
+ - INVALID_CREDENTIALS
580
+ - TOKEN_MISSING
581
+ - TOKEN_EXPIRED
582
+ - TOKEN_INVALID
583
+ - NOT_FOUND
584
+ field_errors:
585
+ type: object
586
+ additionalProperties:
587
+ type: array
588
+ items:
589
+ type: string
590
+ description: Field-specific validation errors
591
+
592
+ responses:
593
+ UnauthorizedError:
594
+ description: Not authenticated or invalid token
595
+ content:
596
+ application/json:
597
+ schema:
598
+ $ref: '#/components/schemas/ErrorResponse'
599
+ example:
600
+ detail: Not authenticated
601
+ error_code: TOKEN_MISSING
602
+
603
+ NotFoundError:
604
+ description: Resource not found or doesn't belong to user
605
+ content:
606
+ application/json:
607
+ schema:
608
+ $ref: '#/components/schemas/ErrorResponse'
609
+ example:
610
+ detail: Task not found
611
+ error_code: NOT_FOUND
specs/002-fullstack-ui-integration/data-model.md ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Model: Full-Stack Integration & UI Experience
2
+
3
+ **Feature**: 002-fullstack-ui-integration
4
+ **Date**: 2026-01-09
5
+ **Status**: Reference Only (No New Entities)
6
+
7
+ ## Overview
8
+
9
+ This feature does not introduce new data entities. It integrates and polishes existing functionality from Specs 1 (Task CRUD) and 2 (Authentication & API Security). This document references the existing data model for completeness.
10
+
11
+ ## Existing Entities
12
+
13
+ ### User (from Spec 2: Authentication & API Security)
14
+
15
+ **Purpose**: Represents an authenticated user with task management capabilities
16
+
17
+ **Attributes**:
18
+ - `id` (integer, primary key): Unique identifier for the user
19
+ - `email` (string, unique, required): User's email address for authentication
20
+ - `name` (string, required): User's display name
21
+ - `password_hash` (string, required): Bcrypt-hashed password (never exposed in API)
22
+ - `created_at` (datetime, auto): Timestamp of account creation
23
+ - `updated_at` (datetime, auto): Timestamp of last profile update
24
+
25
+ **Relationships**:
26
+ - One-to-Many with Task: A user can have multiple tasks
27
+
28
+ **Validation Rules**:
29
+ - Email must be valid RFC 5322 format
30
+ - Email must be unique across all users
31
+ - Password must be at least 8 characters with uppercase, lowercase, and number
32
+ - Name must be 1-100 characters
33
+
34
+ **Security**:
35
+ - Password is hashed with bcrypt (cost factor 12) before storage
36
+ - Password hash is never returned in API responses
37
+ - User ID is extracted from JWT token for all authenticated requests
38
+
39
+ **Database Table**: `users`
40
+
41
+ **Indexes**:
42
+ - Primary key on `id`
43
+ - Unique index on `email`
44
+
45
+ **Source**: `backend/src/models/user.py`
46
+
47
+ ---
48
+
49
+ ### Task (from Spec 1: Task CRUD)
50
+
51
+ **Purpose**: Represents a todo item belonging to a specific user
52
+
53
+ **Attributes**:
54
+ - `id` (integer, primary key): Unique identifier for the task
55
+ - `user_id` (integer, foreign key, required): Owner of the task (references User.id)
56
+ - `title` (string, required): Task title (max 200 characters)
57
+ - `description` (string, optional): Task description (max 1000 characters)
58
+ - `completed` (boolean, default false): Completion status
59
+ - `created_at` (datetime, auto): Timestamp of task creation
60
+ - `updated_at` (datetime, auto): Timestamp of last task update
61
+
62
+ **Relationships**:
63
+ - Many-to-One with User: Each task belongs to exactly one user
64
+
65
+ **Validation Rules**:
66
+ - Title is required and must be 1-200 characters
67
+ - Description is optional, max 1000 characters
68
+ - Completed defaults to false
69
+ - User ID must reference an existing user
70
+
71
+ **Business Rules**:
72
+ - Users can only access their own tasks (enforced by JWT authentication)
73
+ - Tasks are automatically filtered by authenticated user_id in all queries
74
+ - Deleting a user cascades to delete all their tasks
75
+
76
+ **Database Table**: `tasks`
77
+
78
+ **Indexes**:
79
+ - Primary key on `id`
80
+ - Index on `user_id` (for filtering by user)
81
+ - Index on `completed` (for filtering by status)
82
+ - Composite index on `(user_id, completed)` (for combined filtering)
83
+ - Index on `created_at` (for sorting)
84
+
85
+ **Source**: `backend/src/models/task.py`
86
+
87
+ ---
88
+
89
+ ### AuthSession (Frontend Only - from Spec 2)
90
+
91
+ **Purpose**: Client-side session state for authenticated users
92
+
93
+ **Attributes**:
94
+ - `token` (string, nullable): JWT token from backend
95
+ - `user` (object, nullable): User profile information
96
+ - `id` (integer): User ID
97
+ - `email` (string): User email
98
+ - `name` (string): User display name
99
+
100
+ **Storage**: Browser localStorage (key: `auth_session`)
101
+
102
+ **Lifecycle**:
103
+ - Created on successful signin (POST /api/auth/signin)
104
+ - Persisted across page refreshes
105
+ - Cleared on signout or 401 Unauthorized response
106
+ - Expires when JWT token expires (7 days)
107
+
108
+ **Security**:
109
+ - Token is included in Authorization header for all API requests
110
+ - Session is cleared on any authentication error
111
+ - No sensitive data stored (password never stored client-side)
112
+
113
+ **Source**: `frontend/src/lib/auth.ts`
114
+
115
+ ---
116
+
117
+ ## Entity Relationships
118
+
119
+ ```
120
+ User (1) ----< (Many) Task
121
+ |
122
+ | JWT Token (stateless)
123
+ |
124
+ v
125
+ AuthSession (Frontend)
126
+ ```
127
+
128
+ **Relationship Details**:
129
+
130
+ 1. **User → Task** (One-to-Many):
131
+ - A user can have zero or more tasks
132
+ - Each task belongs to exactly one user
133
+ - Foreign key: `Task.user_id` references `User.id`
134
+ - Cascade delete: Deleting a user deletes all their tasks
135
+
136
+ 2. **User → AuthSession** (Stateless):
137
+ - JWT token contains user_id and email
138
+ - No server-side session storage
139
+ - Frontend stores token and user profile in localStorage
140
+ - Token is verified on every API request
141
+
142
+ ## Data Flow
143
+
144
+ ### Authentication Flow
145
+
146
+ ```
147
+ 1. User signs up/signs in
148
+
149
+ 2. Backend creates JWT token with user_id
150
+
151
+ 3. Frontend stores token + user profile in AuthSession
152
+
153
+ 4. Frontend includes token in Authorization header
154
+
155
+ 5. Backend verifies token and extracts user_id
156
+
157
+ 6. Backend filters all queries by user_id
158
+ ```
159
+
160
+ ### Task Management Flow
161
+
162
+ ```
163
+ 1. User creates/updates/deletes task
164
+
165
+ 2. Frontend sends request with JWT token
166
+
167
+ 3. Backend verifies token → extracts user_id
168
+
169
+ 4. Backend performs operation (filtered by user_id)
170
+
171
+ 5. Backend returns result
172
+
173
+ 6. Frontend updates UI (optimistic or after response)
174
+ ```
175
+
176
+ ## Data Isolation
177
+
178
+ **Critical Security Requirement**: All task queries MUST be filtered by authenticated user_id
179
+
180
+ **Implementation**:
181
+ - JWT token contains user_id in 'sub' claim
182
+ - `get_current_user()` dependency extracts user_id from token
183
+ - All task endpoints use `current_user_id = Depends(get_current_user)`
184
+ - SQLModel queries include `.where(Task.user_id == current_user_id)`
185
+
186
+ **Verification**:
187
+ - User A cannot access User B's tasks
188
+ - API returns 404 (not 403) for unauthorized task access
189
+ - No data leakage through error messages
190
+
191
+ ## State Transitions
192
+
193
+ ### Task State Transitions
194
+
195
+ ```
196
+ [New Task]
197
+
198
+ [Active] ←→ [Completed]
199
+
200
+ [Deleted]
201
+ ```
202
+
203
+ **Transitions**:
204
+ - New → Active: Task created with `completed=false`
205
+ - Active → Completed: User marks task as done (`completed=true`)
206
+ - Completed → Active: User marks task as not done (`completed=false`)
207
+ - Any → Deleted: User deletes task (hard delete from database)
208
+
209
+ **No Soft Deletes**: Tasks are permanently deleted (no `deleted_at` field)
210
+
211
+ ### User State Transitions
212
+
213
+ ```
214
+ [New User]
215
+
216
+ [Active]
217
+
218
+ [Deleted] (future - not implemented)
219
+ ```
220
+
221
+ **Current Implementation**:
222
+ - New → Active: User signs up successfully
223
+ - No user deletion implemented yet (out of scope)
224
+
225
+ ## Schema Migrations
226
+
227
+ **Existing Migrations**:
228
+ 1. `001_initial.py`: Created users and tasks tables (Spec 1)
229
+ 2. `002_add_user_password.py`: Added password_hash to users table (Spec 2)
230
+
231
+ **No New Migrations Required**: This feature does not modify the database schema
232
+
233
+ ## Data Validation
234
+
235
+ ### Backend Validation (Pydantic Schemas)
236
+
237
+ **User Validation** (`backend/src/schemas/auth.py`):
238
+ - Email: RFC 5322 format validation
239
+ - Password: Min 8 chars, uppercase, lowercase, number
240
+ - Name: 1-100 characters
241
+
242
+ **Task Validation** (`backend/src/schemas/task.py`):
243
+ - Title: Required, 1-200 characters
244
+ - Description: Optional, max 1000 characters
245
+ - Completed: Boolean (defaults to false)
246
+
247
+ ### Frontend Validation
248
+
249
+ **Client-Side Validation**:
250
+ - Email format validation (regex)
251
+ - Password strength validation (min 8 chars, complexity)
252
+ - Form field required/optional indicators
253
+ - Inline error messages
254
+
255
+ **Note**: Backend validation is authoritative - frontend validation is for UX only
256
+
257
+ ## Performance Considerations
258
+
259
+ **Indexes** (already implemented):
260
+ - `users.email` (unique): Fast user lookup during signin
261
+ - `tasks.user_id`: Fast filtering of user's tasks
262
+ - `tasks.completed`: Fast filtering by completion status
263
+ - `tasks.(user_id, completed)`: Fast combined filtering
264
+ - `tasks.created_at`: Fast sorting by creation date
265
+
266
+ **Query Patterns**:
267
+ - Most common: Get all tasks for user (filtered by user_id)
268
+ - Second most common: Get active/completed tasks for user
269
+ - Sorting: By created_at or updated_at
270
+
271
+ **No N+1 Queries**: All queries are direct (no nested loops)
272
+
273
+ ## Summary
274
+
275
+ This feature reuses the existing data model from Specs 1 and 2:
276
+ - **User**: Authentication and ownership
277
+ - **Task**: Todo items with user isolation
278
+ - **AuthSession**: Frontend session state
279
+
280
+ No new entities, relationships, or migrations are required. The focus is on UI integration and polish rather than data model changes.
specs/002-fullstack-ui-integration/plan.md ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Plan: Full-Stack Integration & UI Experience
2
+
3
+ **Branch**: `002-fullstack-ui-integration` | **Date**: 2026-01-09 | **Spec**: [spec.md](./spec.md)
4
+ **Input**: Feature specification from `/specs/002-fullstack-ui-integration/spec.md`
5
+
6
+ **Note**: This template is filled in by the `/sp.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
7
+
8
+ ## Summary
9
+
10
+ This feature focuses on integrating and polishing existing functionality from Specs 1 (Task CRUD) and 2 (Authentication & API Security) into a cohesive, professional user experience. The primary requirement is to ensure seamless end-to-end flows with proper UI feedback (loading states, empty states, error handling), responsive design across devices, and centralized API communication. The technical approach emphasizes frontend refinement, consistent error handling patterns, and responsive layout implementation using existing Next.js App Router and Tailwind CSS infrastructure.
11
+
12
+ ## Technical Context
13
+
14
+ **Language/Version**:
15
+ - Frontend: TypeScript 5.x with Next.js 16+ (App Router)
16
+ - Backend: Python 3.11+ with FastAPI (already implemented)
17
+
18
+ **Primary Dependencies**:
19
+ - Frontend: Next.js 16+, React 18+, TypeScript 5.x, Tailwind CSS 3.x, Better Auth
20
+ - Backend: FastAPI, SQLModel, PyJWT, passlib (already implemented in Specs 1 & 2)
21
+
22
+ **Storage**: PostgreSQL (Neon Serverless) - already configured with User and Task tables
23
+
24
+ **Testing**:
25
+ - Frontend: Manual testing of UI states, responsive layouts, and user flows
26
+ - Backend: Existing API endpoints already tested in Specs 1 & 2
27
+ - Integration: End-to-end testing of authentication → task management flow
28
+
29
+ **Target Platform**:
30
+ - Web browsers (Chrome, Firefox, Safari, Edge - latest 2 versions)
31
+ - Responsive design for mobile (320px), tablet (768px), and desktop (1920px)
32
+
33
+ **Project Type**: Web application (frontend + backend monorepo)
34
+
35
+ **Performance Goals**:
36
+ - Loading states appear within 100ms of user action
37
+ - Page transitions complete within 500ms
38
+ - API responses within 200ms (backend already optimized in Spec 1)
39
+ - Smooth 60fps animations and transitions
40
+
41
+ **Constraints**:
42
+ - No new backend endpoints (reuse existing from Spec 1)
43
+ - No new authentication mechanisms (reuse JWT from Spec 2)
44
+ - Tailwind CSS only (no inline styles or CSS files)
45
+ - Next.js App Router patterns (server components by default)
46
+ - Must work in local development environment
47
+
48
+ **Scale/Scope**:
49
+ - 5 user stories (P1-P5) focused on integration and polish
50
+ - ~10-15 frontend component refinements
51
+ - Responsive layouts for 3 breakpoints (mobile, tablet, desktop)
52
+ - Centralized API client with error handling
53
+ - Environment configuration documentation
54
+
55
+ ## Constitution Check
56
+
57
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
58
+
59
+ ### Principle I: User-Centric Functionality ✅ PASS
60
+
61
+ **Evaluation**: This feature directly serves end-users by improving UX through clear feedback mechanisms (loading, empty, error states), responsive design, and seamless authentication flows. All 5 user stories focus on user experience improvements.
62
+
63
+ **Alignment**:
64
+ - P1 (Authentication Flow): Ensures users can easily sign up and sign in
65
+ - P2 (UI States): Provides clear feedback during all operations
66
+ - P3 (Responsive Design): Makes app accessible on all devices
67
+ - P4 (API Communication): Ensures reliable backend communication
68
+ - P5 (Environment Setup): Enables developers/reviewers to run the app
69
+
70
+ **Verdict**: ✅ Fully aligned - all features directly benefit end-users
71
+
72
+ ### Principle II: Spec-Driven Development ✅ PASS
73
+
74
+ **Evaluation**: This implementation follows the Spec-Kit Plus workflow. The specification (spec.md) defines 5 prioritized user stories with 30 acceptance scenarios. This plan.md will generate research.md, data-model.md, contracts/, and quickstart.md before tasks.md generation.
75
+
76
+ **Alignment**:
77
+ - Specification created via `/sp.specify` command
78
+ - Planning via `/sp.plan` command (this document)
79
+ - Tasks will be generated via `/sp.tasks` command
80
+ - Implementation via `/sp.implement` command
81
+ - All code references specs in `/specs/002-fullstack-ui-integration/`
82
+
83
+ **Verdict**: ✅ Fully aligned - follows spec-driven workflow
84
+
85
+ ### Principle III: Security & Data Privacy ✅ PASS
86
+
87
+ **Evaluation**: This feature builds on Spec 2 (Authentication & API Security) which already implements JWT authentication, user data isolation, and secure token handling. No new security mechanisms are introduced - this feature focuses on UI integration of existing security.
88
+
89
+ **Alignment**:
90
+ - JWT authentication already implemented (Spec 2)
91
+ - User data isolation already enforced (Spec 2)
92
+ - API client will include JWT tokens automatically (FR-012)
93
+ - 401 errors trigger signin redirect (FR-014)
94
+ - No hardcoded secrets (uses environment variables)
95
+
96
+ **Verification**:
97
+ - ✅ No new authentication mechanisms
98
+ - ✅ Reuses existing JWT verification from Spec 2
99
+ - ✅ Frontend API client includes Authorization headers
100
+ - ✅ Error handling preserves security (generic error messages)
101
+
102
+ **Verdict**: ✅ Fully aligned - builds on existing security implementation
103
+
104
+ ### Principle IV: Scalable Architecture ✅ PASS
105
+
106
+ **Evaluation**: This feature maintains the stateless architecture established in Specs 1 & 2. The centralized API client (P4) improves maintainability without changing the stateless JWT-based design. Responsive design (P3) ensures the frontend scales across devices.
107
+
108
+ **Alignment**:
109
+ - Stateless API design maintained (JWT-based)
110
+ - No server-side sessions introduced
111
+ - Frontend components remain reusable
112
+ - API client centralizes communication logic
113
+ - Responsive design supports multiple devices
114
+
115
+ **Verification**:
116
+ - ✅ No state stored on backend (JWT tokens only)
117
+ - ✅ Frontend components are composable
118
+ - ✅ API client is a shared utility (not per-component)
119
+ - ✅ Responsive layouts use Tailwind breakpoints
120
+
121
+ **Verdict**: ✅ Fully aligned - maintains scalable architecture
122
+
123
+ ### Principle V: Maintainable & Consistent Code ✅ PASS
124
+
125
+ **Evaluation**: This feature enforces consistency through centralized API communication (P4), standardized error handling, and Tailwind CSS usage. The focus on loading/empty/error states creates consistent patterns across all components.
126
+
127
+ **Alignment**:
128
+ - Centralized API client (fetchAPI function)
129
+ - Consistent error handling across all API calls
130
+ - Tailwind CSS utilities for all styling (FR-020)
131
+ - Reusable loading/empty/error state components
132
+ - Next.js App Router patterns maintained
133
+
134
+ **Verification**:
135
+ - ✅ All API calls use centralized fetchAPI function
136
+ - ✅ Error responses formatted consistently
137
+ - ✅ Loading states follow same pattern
138
+ - ✅ Tailwind CSS only (no inline styles)
139
+
140
+ **Verdict**: ✅ Fully aligned - improves code consistency
141
+
142
+ ### Key Standards Compliance
143
+
144
+ **API Compliance** ✅ PASS
145
+ - Reuses existing REST endpoints from Spec 1
146
+ - No new endpoints introduced
147
+ - API client handles errors consistently (FR-013)
148
+ - 401 responses trigger signin redirect (FR-014)
149
+
150
+ **Database Integrity** ✅ PASS
151
+ - No database changes required
152
+ - Reuses existing User and Task tables from Specs 1 & 2
153
+ - No new migrations needed
154
+
155
+ **Frontend Quality** ✅ PASS
156
+ - Next.js App Router patterns (server components by default)
157
+ - Client components for interactivity (forms, buttons)
158
+ - Responsive design for mobile, tablet, desktop (P3)
159
+ - Tailwind CSS for all styling (FR-020)
160
+
161
+ **Authentication** ✅ PASS
162
+ - Better Auth already implemented (Spec 2)
163
+ - JWT tokens already issued and verified (Spec 2)
164
+ - Frontend includes JWT in Authorization header (FR-012)
165
+ - Token expiry handled with signin redirect (FR-006)
166
+
167
+ **Spec Adherence** ✅ PASS
168
+ - Implementation references spec.md
169
+ - All 20 functional requirements documented
170
+ - 5 user stories with acceptance criteria
171
+ - No implementation without spec
172
+
173
+ ### Constraints Compliance
174
+
175
+ **Tech Stack** ✅ PASS
176
+ - Frontend: Next.js 16+ (App Router), TypeScript, Tailwind CSS ✅
177
+ - Backend: FastAPI, SQLModel ✅ (no changes)
178
+ - Database: Neon PostgreSQL ✅ (no changes)
179
+ - Authentication: Better Auth (JWT) ✅ (no changes)
180
+
181
+ **Endpoint Authorization** ✅ PASS
182
+ - All task endpoints already require JWT (Spec 2)
183
+ - No new endpoints introduced
184
+ - API client includes JWT automatically (FR-012)
185
+
186
+ **Monorepo Structure** ✅ PASS
187
+ - Maintains existing structure
188
+ - CLAUDE.md files already in place
189
+ - specs/002-fullstack-ui-integration/ created
190
+ - No structural changes required
191
+
192
+ **No Manual Coding** ✅ PASS
193
+ - All implementation via Claude Code
194
+ - References specifications
195
+ - Follows spec-driven workflow
196
+
197
+ **Security** ✅ PASS
198
+ - JWT token expiry already implemented (7 days, Spec 2)
199
+ - BETTER_AUTH_SECRET shared via environment variables
200
+ - No new security mechanisms introduced
201
+
202
+ ### Constitution Check Summary
203
+
204
+ **Overall Verdict**: ✅ **APPROVED** - All principles, standards, and constraints satisfied
205
+
206
+ **Justification**: This is an integration and polish feature that builds on existing implementations from Specs 1 and 2. It introduces no new architectural patterns, security mechanisms, or backend logic. The focus is entirely on frontend refinement and user experience improvements, which aligns perfectly with constitutional principles.
207
+
208
+ **No Violations**: No complexity justification required.
209
+
210
+ ## Project Structure
211
+
212
+ ### Documentation (this feature)
213
+
214
+ ```text
215
+ specs/002-fullstack-ui-integration/
216
+ ├── spec.md # Feature specification (completed)
217
+ ├── plan.md # This file (in progress)
218
+ ├── research.md # Phase 0 output (to be generated)
219
+ ├── data-model.md # Phase 1 output (to be generated)
220
+ ├── quickstart.md # Phase 1 output (to be generated)
221
+ ├── contracts/ # Phase 1 output (to be generated)
222
+ │ └── existing-api-reference.yaml
223
+ ├── checklists/
224
+ │ └── requirements.md # Specification validation (completed)
225
+ └── tasks.md # Phase 2 output (NOT created by /sp.plan)
226
+ ```
227
+
228
+ ### Source Code (repository root)
229
+
230
+ ```text
231
+ # Web application structure (frontend + backend monorepo)
232
+
233
+ backend/
234
+ ├── src/
235
+ │ ├── api/
236
+ │ │ ├── deps.py # JWT verification (Spec 2) ✅
237
+ │ │ └── routes/
238
+ │ │ ├── auth.py # Auth endpoints (Spec 2) ✅
239
+ │ │ └── tasks.py # Task CRUD (Spec 1) ✅
240
+ │ ├── core/
241
+ │ │ ├── config.py # Environment config ✅
242
+ │ │ ├── database.py # DB connection ✅
243
+ │ │ └── security.py # JWT & password hashing (Spec 2) ✅
244
+ │ ├── models/
245
+ │ │ ├── user.py # User model (Spec 2) ✅
246
+ │ │ └── task.py # Task model (Spec 1) ✅
247
+ │ ├── schemas/
248
+ │ │ ├── auth.py # Auth schemas (Spec 2) ✅
249
+ │ │ └── task.py # Task schemas (Spec 1) ✅
250
+ │ ├── services/
251
+ │ │ ├── auth_service.py # Auth logic (Spec 2) ✅
252
+ │ │ └── task_service.py # Task logic (Spec 1) ✅
253
+ │ └── main.py # FastAPI app ✅
254
+ ├── alembic/
255
+ │ └── versions/ # Migrations (Specs 1 & 2) ✅
256
+ ├── tests/ # Backend tests (future)
257
+ ├── .env # Backend environment variables ✅
258
+ └── requirements.txt # Python dependencies ✅
259
+
260
+ frontend/
261
+ ├── src/
262
+ │ ├── app/
263
+ │ │ ├── layout.tsx # Root layout with AuthProvider ✅
264
+ │ │ ├── page.tsx # Home page (protected) ✅
265
+ │ │ ├── auth/
266
+ │ │ │ ├── signin/
267
+ │ │ │ │ └── page.tsx # Signin page (Spec 2) ✅
268
+ │ │ │ └── signup/
269
+ │ │ │ └── page.tsx # Signup page (Spec 2) ✅
270
+ │ │ └── globals.css # Global Tailwind styles ✅
271
+ │ ├── components/
272
+ │ │ ├── auth/
273
+ │ │ │ ├── SignInForm.tsx # Signin form (Spec 2) ✅
274
+ │ │ │ └── SignUpForm.tsx # Signup form (Spec 2) ✅
275
+ │ │ └── tasks/
276
+ │ │ ├── TaskForm.tsx # Create task (Spec 1) ✅
277
+ │ │ ├── TaskItem.tsx # Task display (Spec 1) ✅
278
+ │ │ ├── TaskList.tsx # Task list (Spec 1) ✅
279
+ │ │ └── TaskFilters.tsx # Filters (Spec 1) ✅
280
+ │ ├── lib/
281
+ │ │ ├── api.ts # API client (needs refinement) 🔄
282
+ │ │ ├── auth.ts # Auth session (Spec 2) ✅
283
+ │ │ └── types.ts # TypeScript types ✅
284
+ │ └── providers/
285
+ │ └── AuthProvider.tsx # Auth context (Spec 2) ✅
286
+ ├── public/ # Static assets
287
+ ├── .env.local # Frontend environment variables ✅
288
+ ├── package.json # Node dependencies ✅
289
+ ├── tailwind.config.ts # Tailwind configuration ✅
290
+ └── tsconfig.json # TypeScript configuration ✅
291
+
292
+ specs/
293
+ ├── 001-auth-security/ # Spec 2 (Authentication) ✅
294
+ └── 002-fullstack-ui-integration/ # This feature (in progress)
295
+ ```
296
+
297
+ **Structure Decision**: The existing web application structure is maintained. This feature focuses on refining frontend components and the API client rather than adding new files. Key areas of work:
298
+
299
+ 1. **API Client Refinement** (`frontend/src/lib/api.ts`):
300
+ - Already includes JWT token injection ✅
301
+ - Already handles 401 redirects ✅
302
+ - Needs: Consistent error formatting, loading state management
303
+
304
+ 2. **Component Enhancements**:
305
+ - Add loading states to all async operations
306
+ - Add empty states to TaskList
307
+ - Add error states with retry buttons
308
+ - Improve responsive layouts
309
+
310
+ 3. **Responsive Design**:
311
+ - Refine Tailwind breakpoints in existing components
312
+ - Ensure 44x44px touch targets
313
+ - Test layouts at 320px, 768px, 1920px
314
+
315
+ 4. **Documentation**:
316
+ - Update README files with setup instructions
317
+ - Create quickstart guide for reviewers
318
+
319
+ **No new directories or major structural changes required.**
320
+
321
+ ## Complexity Tracking
322
+
323
+ > **Fill ONLY if Constitution Check has violations that must be justified**
324
+
325
+ **No violations detected** - Complexity tracking not required.
326
+
327
+ This feature maintains existing architecture and focuses on polish/integration. All constitutional principles are satisfied without introducing additional complexity.
328
+
329
+ ---
330
+
331
+ ## Post-Design Constitution Check
332
+
333
+ *Re-evaluation after Phase 0 (Research) and Phase 1 (Design) completion*
334
+
335
+ ### Design Artifacts Generated
336
+
337
+ 1. **research.md**: 10 technical decisions documented
338
+ - UI state management patterns (React hooks)
339
+ - Loading/empty/error state designs
340
+ - Responsive design breakpoints (Tailwind defaults)
341
+ - Touch target sizing (44x44px minimum)
342
+ - API client error handling (existing implementation)
343
+ - Form validation patterns (existing implementation)
344
+ - Optimistic UI updates
345
+ - Environment configuration
346
+
347
+ 2. **data-model.md**: Reference to existing entities
348
+ - User (from Spec 2)
349
+ - Task (from Spec 1)
350
+ - AuthSession (frontend only)
351
+ - No new entities introduced
352
+
353
+ 3. **contracts/existing-api-reference.yaml**: OpenAPI 3.0 specification
354
+ - Authentication endpoints (Spec 2)
355
+ - Task CRUD endpoints (Spec 1)
356
+ - No new endpoints introduced
357
+
358
+ 4. **quickstart.md**: Testing and validation guide
359
+ - Setup instructions (5 minutes)
360
+ - Test scenarios for all 5 user stories
361
+ - Common issues and solutions
362
+ - Performance benchmarks
363
+ - Validation checklist
364
+
365
+ ### Re-evaluation Results
366
+
367
+ **Principle I: User-Centric Functionality** ✅ PASS
368
+ - Research confirms focus on user feedback (loading, empty, error states)
369
+ - Responsive design ensures accessibility across devices
370
+ - No changes to core functionality
371
+
372
+ **Principle II: Spec-Driven Development** ✅ PASS
373
+ - All design artifacts generated via spec-driven workflow
374
+ - Research documents existing patterns and decisions
375
+ - No ad-hoc implementations
376
+
377
+ **Principle III: Security & Data Privacy** ✅ PASS
378
+ - No new security mechanisms introduced
379
+ - Reuses existing JWT authentication
380
+ - API client maintains Authorization header inclusion
381
+ - No changes to data isolation logic
382
+
383
+ **Principle IV: Scalable Architecture** ✅ PASS
384
+ - Maintains stateless architecture
385
+ - No new backend state introduced
386
+ - Responsive design scales across devices
387
+ - Centralized API client improves maintainability
388
+
389
+ **Principle V: Maintainable & Consistent Code** ✅ PASS
390
+ - Research documents consistent patterns (loading states, error handling)
391
+ - Tailwind CSS usage enforced
392
+ - Reusable component patterns identified
393
+ - No new complexity introduced
394
+
395
+ ### Key Standards Compliance (Post-Design)
396
+
397
+ **API Compliance** ✅ PASS
398
+ - OpenAPI specification documents all existing endpoints
399
+ - No new endpoints introduced
400
+ - Error handling patterns documented
401
+
402
+ **Database Integrity** ✅ PASS
403
+ - No database changes
404
+ - Existing schema maintained
405
+ - No new migrations required
406
+
407
+ **Frontend Quality** ✅ PASS
408
+ - Responsive design patterns documented
409
+ - Tailwind CSS usage confirmed
410
+ - Component enhancement patterns identified
411
+
412
+ **Authentication** ✅ PASS
413
+ - Existing Better Auth + JWT maintained
414
+ - No changes to authentication flow
415
+ - Token handling patterns documented
416
+
417
+ **Spec Adherence** ✅ PASS
418
+ - All design artifacts reference spec.md
419
+ - Implementation will reference plan.md, research.md, data-model.md
420
+ - No deviations from specification
421
+
422
+ ### Post-Design Verdict
423
+
424
+ **Overall Verdict**: ✅ **APPROVED** - All principles and standards remain satisfied after design phase
425
+
426
+ **Confirmation**: The design phase (research, data model, contracts, quickstart) confirms that this feature:
427
+ 1. Introduces no new architectural complexity
428
+ 2. Maintains all existing security mechanisms
429
+ 3. Focuses entirely on UI polish and integration
430
+ 4. Follows established patterns from Specs 1 & 2
431
+ 5. Requires no database or backend changes
432
+
433
+ **Ready for Task Generation**: Proceed to `/sp.tasks` command to generate implementation tasks
434
+
435
+ ---
436
+
437
+ ## Planning Summary
438
+
439
+ ### Artifacts Generated
440
+
441
+ | Artifact | Status | Purpose |
442
+ |----------|--------|---------|
443
+ | spec.md | ✅ Complete | Feature specification with 5 user stories |
444
+ | plan.md | ✅ Complete | This file - implementation plan |
445
+ | research.md | ✅ Complete | 10 technical decisions documented |
446
+ | data-model.md | ✅ Complete | Reference to existing entities |
447
+ | contracts/existing-api-reference.yaml | ✅ Complete | OpenAPI 3.0 specification |
448
+ | quickstart.md | ✅ Complete | Testing and validation guide |
449
+ | checklists/requirements.md | ✅ Complete | Specification validation (all passed) |
450
+
451
+ ### Next Steps
452
+
453
+ 1. **Generate tasks.md**: Run `/sp.tasks` command to create implementation tasks
454
+ 2. **Implement**: Run `/sp.implement` command to execute tasks
455
+ 3. **Test**: Follow quickstart.md to validate all user stories
456
+ 4. **Document**: Update README files with any new patterns
457
+
458
+ **Status**: ✅ Planning complete - Ready for task generation
specs/002-fullstack-ui-integration/quickstart.md ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quickstart Guide: Full-Stack Integration & UI Experience
2
+
3
+ **Feature**: 002-fullstack-ui-integration
4
+ **Date**: 2026-01-09
5
+ **Purpose**: Testing and validation guide for integration and UI polish
6
+
7
+ ## Overview
8
+
9
+ This guide helps developers and reviewers quickly set up, test, and validate the Full-Stack Integration & UI Experience feature. Since this feature builds on existing implementations (Specs 1 & 2), most setup is already complete.
10
+
11
+ ## Prerequisites
12
+
13
+ Before testing this feature, ensure:
14
+
15
+ 1. **Specs 1 & 2 are complete**:
16
+ - ✅ Task CRUD endpoints working (Spec 1)
17
+ - ✅ Authentication & JWT working (Spec 2)
18
+ - ✅ Database migrations applied
19
+ - ✅ Environment variables configured
20
+
21
+ 2. **Development environment**:
22
+ - Node.js 18+ installed
23
+ - Python 3.11+ installed
24
+ - PostgreSQL database accessible (Neon or local)
25
+ - Git repository cloned
26
+
27
+ ## Quick Setup (5 minutes)
28
+
29
+ ### 1. Backend Setup
30
+
31
+ ```bash
32
+ # Navigate to backend directory
33
+ cd backend
34
+
35
+ # Install dependencies (if not already done)
36
+ pip install -r requirements.txt
37
+
38
+ # Verify environment variables
39
+ cat .env
40
+ # Should contain:
41
+ # - DATABASE_URL
42
+ # - BETTER_AUTH_SECRET
43
+ # - JWT_ALGORITHM=HS256
44
+ # - JWT_EXPIRATION_DAYS=7
45
+
46
+ # Apply migrations (if not already done)
47
+ python -m alembic upgrade head
48
+
49
+ # Start backend server
50
+ python -m uvicorn src.main:app --reload
51
+
52
+ # Server should start at http://localhost:8000
53
+ # Verify: Open http://localhost:8000/docs (Swagger UI)
54
+ ```
55
+
56
+ ### 2. Frontend Setup
57
+
58
+ ```bash
59
+ # Navigate to frontend directory (in new terminal)
60
+ cd frontend
61
+
62
+ # Install dependencies (if not already done)
63
+ npm install
64
+
65
+ # Verify environment variables
66
+ cat .env.local
67
+ # Should contain:
68
+ # - NEXT_PUBLIC_API_URL=http://localhost:8000
69
+ # - BETTER_AUTH_SECRET (same as backend)
70
+
71
+ # Start frontend server
72
+ npm run dev
73
+
74
+ # Server should start at http://localhost:3000
75
+ # Verify: Open http://localhost:3000
76
+ ```
77
+
78
+ ### 3. Verify Setup
79
+
80
+ **Backend Health Check**:
81
+ ```bash
82
+ curl http://localhost:8000/health
83
+ # Expected: {"status":"healthy"}
84
+ ```
85
+
86
+ **Frontend Access**:
87
+ - Open http://localhost:3000
88
+ - Should redirect to http://localhost:3000/auth/signin
89
+ - Signin page should load without errors
90
+
91
+ ## Testing User Stories
92
+
93
+ ### P1: Complete Authentication Flow (MVP)
94
+
95
+ **Test Scenario**: New user signup → signin → task management
96
+
97
+ **Steps**:
98
+
99
+ 1. **Navigate to signup**:
100
+ ```
101
+ Open: http://localhost:3000/auth/signup
102
+ ```
103
+
104
+ 2. **Test validation errors**:
105
+ - Try empty email → Should show "Email is required"
106
+ - Try invalid email (e.g., "notanemail") → Should show "Invalid email format"
107
+ - Try weak password (e.g., "pass") → Should show password requirements
108
+ - Try short name → Should show "Name is required"
109
+
110
+ 3. **Create account**:
111
+ - Email: `test@example.com`
112
+ - Password: `TestPass123`
113
+ - Name: `Test User`
114
+ - Click "Sign Up"
115
+ - **Expected**: Redirect to signin page with success message
116
+
117
+ 4. **Sign in**:
118
+ - Email: `test@example.com`
119
+ - Password: `TestPass123`
120
+ - Click "Sign In"
121
+ - **Expected**: Redirect to home page (http://localhost:3000)
122
+
123
+ 5. **Verify authenticated state**:
124
+ - Header should show "Welcome, Test User"
125
+ - "Sign Out" button should be visible
126
+ - Task form and list should be visible
127
+
128
+ 6. **Sign out**:
129
+ - Click "Sign Out" button
130
+ - **Expected**: Redirect to signin page
131
+ - **Expected**: Cannot access home page without signin
132
+
133
+ **Pass Criteria**:
134
+ - ✅ Validation errors display inline
135
+ - ✅ Signup creates account successfully
136
+ - ✅ Signin issues JWT token
137
+ - ✅ Home page shows user profile
138
+ - ✅ Sign out clears session
139
+
140
+ ---
141
+
142
+ ### P2: Responsive UI States
143
+
144
+ **Test Scenario**: Loading, empty, and error states
145
+
146
+ **Steps**:
147
+
148
+ 1. **Test loading state**:
149
+ - Sign in as test user
150
+ - Observe task list loading
151
+ - **Expected**: Loading spinner with "Loading tasks..." message
152
+ - **Expected**: Spinner disappears when tasks load
153
+
154
+ 2. **Test empty state**:
155
+ - If no tasks exist:
156
+ - **Expected**: "No tasks yet" message
157
+ - **Expected**: Call-to-action to create first task
158
+ - **Expected**: Empty state is centered and clear
159
+
160
+ 3. **Test error state**:
161
+ - Stop backend server (Ctrl+C in backend terminal)
162
+ - Try to create a task
163
+ - **Expected**: Error message "Unable to connect to server"
164
+ - **Expected**: Retry button appears
165
+ - Restart backend server
166
+ - Click retry button
167
+ - **Expected**: Operation succeeds
168
+
169
+ 4. **Test form loading state**:
170
+ - Create a task
171
+ - Observe submit button during API call
172
+ - **Expected**: Button shows "Creating..." and is disabled
173
+ - **Expected**: Button returns to normal after success
174
+
175
+ 5. **Test token expiration** (optional - requires waiting 7 days or manual token manipulation):
176
+ - With expired token, try to access home page
177
+ - **Expected**: Redirect to signin with "Session expired" message
178
+
179
+ **Pass Criteria**:
180
+ - ✅ Loading states appear within 100ms
181
+ - ✅ Empty states provide clear guidance
182
+ - ✅ Error messages are actionable
183
+ - ✅ Form buttons show loading state
184
+ - ✅ Token expiration handled gracefully
185
+
186
+ ---
187
+
188
+ ### P3: Responsive Design
189
+
190
+ **Test Scenario**: Mobile, tablet, desktop layouts
191
+
192
+ **Steps**:
193
+
194
+ 1. **Test desktop layout (≥1024px)**:
195
+ - Open browser DevTools (F12)
196
+ - Set viewport to 1920x1080
197
+ - **Expected**: Three-column layout
198
+ - **Expected**: Task form (left), filters (middle), task list (right)
199
+
200
+ 2. **Test tablet layout (768px-1023px)**:
201
+ - Set viewport to 768x1024
202
+ - **Expected**: Two-column layout
203
+ - **Expected**: Task form and filters stacked (left), task list (right)
204
+
205
+ 3. **Test mobile layout (<768px)**:
206
+ - Set viewport to 375x667 (iPhone SE)
207
+ - **Expected**: Single-column layout
208
+ - **Expected**: All elements stacked vertically
209
+ - **Expected**: No horizontal scrolling
210
+
211
+ 4. **Test touch targets**:
212
+ - On mobile viewport, inspect buttons
213
+ - **Expected**: All buttons are at least 44x44px
214
+ - **Expected**: Adequate spacing between interactive elements
215
+
216
+ 5. **Test signin/signup forms**:
217
+ - Navigate to signin page on mobile
218
+ - **Expected**: Form is centered and readable
219
+ - **Expected**: Input fields use appropriate types (email, password)
220
+ - **Expected**: Keyboard doesn't obscure form fields
221
+
222
+ **Pass Criteria**:
223
+ - ✅ Layouts adapt to viewport width
224
+ - ✅ No horizontal scrolling on any device
225
+ - ✅ Touch targets are 44x44px minimum
226
+ - ✅ Forms are usable on mobile
227
+ - ✅ Text is readable without zooming
228
+
229
+ ---
230
+
231
+ ### P4: Centralized API Communication
232
+
233
+ **Test Scenario**: Verify API client consistency
234
+
235
+ **Steps**:
236
+
237
+ 1. **Verify JWT token inclusion**:
238
+ - Sign in as test user
239
+ - Open browser DevTools → Network tab
240
+ - Create a task
241
+ - Inspect POST /api/tasks request
242
+ - **Expected**: Authorization header present: `Bearer <token>`
243
+
244
+ 2. **Verify 401 handling**:
245
+ - Clear localStorage (DevTools → Application → Local Storage → Clear)
246
+ - Try to access home page
247
+ - **Expected**: Automatic redirect to signin
248
+ - **Expected**: No console errors
249
+
250
+ 3. **Verify error formatting**:
251
+ - Sign in
252
+ - Stop backend server
253
+ - Try to create a task
254
+ - Open browser console
255
+ - **Expected**: APIError with status, detail, error_code
256
+ - **Expected**: Error displayed in UI (not just console)
257
+
258
+ 4. **Verify all endpoints use fetchAPI**:
259
+ - Review code: `frontend/src/lib/api.ts`
260
+ - **Expected**: All API functions use fetchAPI helper
261
+ - **Expected**: No direct fetch() calls in components
262
+
263
+ **Pass Criteria**:
264
+ - ✅ JWT tokens included automatically
265
+ - ✅ 401 errors trigger signin redirect
266
+ - ✅ Errors formatted consistently
267
+ - ✅ All API calls use centralized client
268
+ - ✅ No unhandled promise rejections
269
+
270
+ ---
271
+
272
+ ### P5: Environment Coordination
273
+
274
+ **Test Scenario**: Setup and configuration
275
+
276
+ **Steps**:
277
+
278
+ 1. **Verify environment variables**:
279
+ ```bash
280
+ # Backend
281
+ grep BETTER_AUTH_SECRET backend/.env
282
+
283
+ # Frontend
284
+ grep BETTER_AUTH_SECRET frontend/.env.local
285
+
286
+ # Expected: Both values match exactly
287
+ ```
288
+
289
+ 2. **Test with missing environment variable**:
290
+ - Temporarily rename `backend/.env` to `backend/.env.backup`
291
+ - Try to start backend
292
+ - **Expected**: Clear error message about missing variables
293
+ - Restore `backend/.env`
294
+
295
+ 3. **Test with mismatched secrets**:
296
+ - Change BETTER_AUTH_SECRET in `frontend/.env.local`
297
+ - Sign in
298
+ - **Expected**: Token verification fails
299
+ - **Expected**: Clear error message
300
+ - Restore correct secret
301
+
302
+ 4. **Verify README documentation**:
303
+ - Read `backend/README.md`
304
+ - **Expected**: Authentication setup instructions present
305
+ - **Expected**: Environment variable documentation
306
+ - Read `frontend/README.md`
307
+ - **Expected**: Better Auth configuration notes
308
+ - **Expected**: Setup instructions
309
+
310
+ **Pass Criteria**:
311
+ - ✅ Environment variables documented
312
+ - ✅ Missing variables show clear errors
313
+ - ✅ Mismatched secrets are detected
314
+ - ✅ README files are up-to-date
315
+ - ✅ Setup takes under 10 minutes
316
+
317
+ ---
318
+
319
+ ## Common Issues & Solutions
320
+
321
+ ### Issue: "404 Not Found" on /api/auth/signup
322
+
323
+ **Cause**: Auth router not registered in backend/src/main.py
324
+
325
+ **Solution**:
326
+ ```python
327
+ # In backend/src/main.py, ensure:
328
+ from .api.routes import tasks, auth
329
+
330
+ app.include_router(auth.router) # Must be present
331
+ app.include_router(tasks.router)
332
+ ```
333
+
334
+ ### Issue: "Token signature verification failed"
335
+
336
+ **Cause**: BETTER_AUTH_SECRET differs between frontend and backend
337
+
338
+ **Solution**:
339
+ ```bash
340
+ # Verify secrets match:
341
+ grep BETTER_AUTH_SECRET backend/.env
342
+ grep BETTER_AUTH_SECRET frontend/.env.local
343
+
344
+ # If different, copy backend secret to frontend
345
+ ```
346
+
347
+ ### Issue: "Unable to connect to database"
348
+
349
+ **Cause**: DATABASE_URL is incorrect or database is not running
350
+
351
+ **Solution**:
352
+ ```bash
353
+ # For Neon PostgreSQL:
354
+ # Verify connection string in backend/.env includes ?sslmode=require
355
+
356
+ # For local PostgreSQL:
357
+ # Ensure PostgreSQL is running:
358
+ # Windows: Check Services
359
+ # Mac/Linux: sudo systemctl status postgresql
360
+ ```
361
+
362
+ ### Issue: Frontend shows blank page
363
+
364
+ **Cause**: JavaScript error or build issue
365
+
366
+ **Solution**:
367
+ ```bash
368
+ # Check browser console for errors
369
+ # Clear Next.js cache:
370
+ cd frontend
371
+ rm -rf .next
372
+ npm run dev
373
+ ```
374
+
375
+ ### Issue: Tasks not loading
376
+
377
+ **Cause**: JWT token missing or invalid
378
+
379
+ **Solution**:
380
+ ```bash
381
+ # Check localStorage in browser DevTools:
382
+ # Application → Local Storage → http://localhost:3000
383
+ # Look for 'auth_session' key
384
+
385
+ # If missing or invalid, sign out and sign in again
386
+ ```
387
+
388
+ ## Performance Benchmarks
389
+
390
+ **Expected Performance**:
391
+ - Loading states appear: <100ms
392
+ - Page transitions: <500ms
393
+ - API responses: <200ms
394
+ - Task list load (10 tasks): <300ms
395
+ - Signup/signin: <1s
396
+
397
+ **How to Measure**:
398
+ ```javascript
399
+ // In browser console:
400
+ performance.mark('start');
401
+ // Perform action (e.g., create task)
402
+ performance.mark('end');
403
+ performance.measure('action', 'start', 'end');
404
+ console.log(performance.getEntriesByType('measure'));
405
+ ```
406
+
407
+ ## Validation Checklist
408
+
409
+ Before marking this feature complete, verify:
410
+
411
+ **Authentication Flow**:
412
+ - [ ] Signup form validates inputs
413
+ - [ ] Signup creates user in database
414
+ - [ ] Signin issues JWT token
415
+ - [ ] Home page shows user profile
416
+ - [ ] Sign out clears session
417
+
418
+ **UI States**:
419
+ - [ ] Loading spinners appear during async operations
420
+ - [ ] Empty states show helpful messages
421
+ - [ ] Error messages are clear and actionable
422
+ - [ ] Form buttons show loading state
423
+
424
+ **Responsive Design**:
425
+ - [ ] Desktop layout (3 columns) works at 1920px
426
+ - [ ] Tablet layout (2 columns) works at 768px
427
+ - [ ] Mobile layout (1 column) works at 375px
428
+ - [ ] No horizontal scrolling on any device
429
+ - [ ] Touch targets are 44x44px minimum
430
+
431
+ **API Communication**:
432
+ - [ ] JWT tokens included in all requests
433
+ - [ ] 401 errors trigger signin redirect
434
+ - [ ] Errors formatted consistently
435
+ - [ ] No unhandled promise rejections
436
+
437
+ **Environment Setup**:
438
+ - [ ] Backend starts without errors
439
+ - [ ] Frontend starts without errors
440
+ - [ ] Environment variables documented
441
+ - [ ] README files are accurate
442
+
443
+ ## Next Steps
444
+
445
+ After validating all user stories:
446
+
447
+ 1. **Mark tasks complete** in `tasks.md`
448
+ 2. **Document any issues** found during testing
449
+ 3. **Create git commit** with implementation
450
+ 4. **Prepare for demo** (if hackathon submission)
451
+
452
+ ## Support
453
+
454
+ For issues or questions:
455
+ - Review specification: `specs/002-fullstack-ui-integration/spec.md`
456
+ - Review implementation plan: `specs/002-fullstack-ui-integration/plan.md`
457
+ - Check API reference: `specs/002-fullstack-ui-integration/contracts/existing-api-reference.yaml`
458
+ - Review existing specs: `specs/001-auth-security/`
specs/002-fullstack-ui-integration/research.md ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research: Full-Stack Integration & UI Experience
2
+
3
+ **Feature**: 002-fullstack-ui-integration
4
+ **Date**: 2026-01-09
5
+ **Status**: Complete
6
+
7
+ ## Overview
8
+
9
+ This research document captures technical decisions, patterns, and best practices for integrating existing functionality (Specs 1 & 2) into a cohesive user experience. Since this is a polish/integration feature rather than new functionality, most decisions reference existing implementations.
10
+
11
+ ## Research Areas
12
+
13
+ ### 1. UI State Management Patterns
14
+
15
+ **Decision**: Use React hooks (useState, useEffect) with loading/error/data states
16
+
17
+ **Rationale**:
18
+ - Already established pattern in existing components (TaskList, TaskForm)
19
+ - Simple and effective for component-level state
20
+ - No need for global state management (Redux, Zustand) for this scope
21
+ - Aligns with Next.js App Router best practices
22
+
23
+ **Pattern**:
24
+ ```typescript
25
+ const [isLoading, setIsLoading] = useState(false);
26
+ const [error, setError] = useState<string | null>(null);
27
+ const [data, setData] = useState<T | null>(null);
28
+ ```
29
+
30
+ **Alternatives Considered**:
31
+ - React Query / TanStack Query: Overkill for current scope, adds dependency
32
+ - Redux: Too complex for simple loading/error states
33
+ - Context API: Not needed - state is component-local
34
+
35
+ **References**:
36
+ - Existing: `frontend/src/components/tasks/TaskList.tsx` (lines 10-15)
37
+ - Next.js Data Fetching: https://nextjs.org/docs/app/building-your-application/data-fetching
38
+
39
+ ---
40
+
41
+ ### 2. Loading State Indicators
42
+
43
+ **Decision**: Use Tailwind CSS spinner with descriptive text
44
+
45
+ **Rationale**:
46
+ - Consistent with existing Tailwind-only styling constraint
47
+ - Accessible (includes text for screen readers)
48
+ - Lightweight (no external animation libraries)
49
+ - Fast to implement and customize
50
+
51
+ **Pattern**:
52
+ ```tsx
53
+ {isLoading && (
54
+ <div className="flex items-center justify-center p-8">
55
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
56
+ <span className="ml-3 text-gray-600">Loading tasks...</span>
57
+ </div>
58
+ )}
59
+ ```
60
+
61
+ **Alternatives Considered**:
62
+ - Skeleton screens: More complex, better for content-heavy pages
63
+ - Progress bars: Not suitable for indeterminate loading
64
+ - Third-party libraries (react-spinners): Adds dependency, unnecessary
65
+
66
+ **References**:
67
+ - Tailwind Animation: https://tailwindcss.com/docs/animation
68
+ - Accessibility: Include aria-live="polite" for screen readers
69
+
70
+ ---
71
+
72
+ ### 3. Empty State Design
73
+
74
+ **Decision**: Centered message with icon and call-to-action
75
+
76
+ **Rationale**:
77
+ - Guides users toward next action (create first task)
78
+ - Reduces confusion when no data exists
79
+ - Industry standard pattern (GitHub, Notion, Linear)
80
+ - Improves onboarding experience
81
+
82
+ **Pattern**:
83
+ ```tsx
84
+ {tasks.length === 0 && !isLoading && (
85
+ <div className="text-center py-12">
86
+ <p className="text-gray-500 text-lg mb-4">No tasks yet</p>
87
+ <p className="text-gray-400 mb-6">Create your first task to get started</p>
88
+ <button className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
89
+ Create Task
90
+ </button>
91
+ </div>
92
+ )}
93
+ ```
94
+
95
+ **Alternatives Considered**:
96
+ - Blank screen: Poor UX, users don't know what to do
97
+ - Tutorial overlay: Too intrusive for simple app
98
+ - Animated illustrations: Adds complexity, not needed
99
+
100
+ **References**:
101
+ - Empty States Best Practices: https://www.nngroup.com/articles/empty-state-design/
102
+ - Material Design Empty States: https://m2.material.io/design/communication/empty-states.html
103
+
104
+ ---
105
+
106
+ ### 4. Error Handling & Display
107
+
108
+ **Decision**: Inline error messages with retry button
109
+
110
+ **Rationale**:
111
+ - Keeps user in context (no modal dialogs)
112
+ - Provides actionable recovery (retry button)
113
+ - Consistent with existing API error handling
114
+ - Follows progressive disclosure principle
115
+
116
+ **Pattern**:
117
+ ```tsx
118
+ {error && (
119
+ <div className="bg-red-50 border border-red-200 rounded-md p-4 mb-4">
120
+ <div className="flex items-start">
121
+ <div className="flex-1">
122
+ <h3 className="text-sm font-medium text-red-800">Error</h3>
123
+ <p className="text-sm text-red-700 mt-1">{error}</p>
124
+ </div>
125
+ <button
126
+ onClick={handleRetry}
127
+ className="ml-3 text-sm font-medium text-red-600 hover:text-red-500"
128
+ >
129
+ Retry
130
+ </button>
131
+ </div>
132
+ </div>
133
+ )}
134
+ ```
135
+
136
+ **Alternatives Considered**:
137
+ - Toast notifications: Disappear too quickly, users miss them
138
+ - Modal dialogs: Disruptive, blocks entire UI
139
+ - Console.error only: Not user-facing, poor UX
140
+
141
+ **References**:
142
+ - Existing: `frontend/src/lib/api.ts` APIError class
143
+ - Error Message Guidelines: https://www.nngroup.com/articles/error-message-guidelines/
144
+
145
+ ---
146
+
147
+ ### 5. Responsive Design Breakpoints
148
+
149
+ **Decision**: Use Tailwind's default breakpoints (sm: 640px, md: 768px, lg: 1024px)
150
+
151
+ **Rationale**:
152
+ - Already configured in existing tailwind.config.ts
153
+ - Industry-standard breakpoints
154
+ - Covers mobile (320px-767px), tablet (768px-1023px), desktop (1024px+)
155
+ - No custom breakpoints needed for this scope
156
+
157
+ **Pattern**:
158
+ ```tsx
159
+ <div className="grid gap-6 lg:grid-cols-3 md:grid-cols-2 grid-cols-1">
160
+ {/* Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns */}
161
+ </div>
162
+ ```
163
+
164
+ **Breakpoint Strategy**:
165
+ - **Mobile (<768px)**: Single column, stacked layout
166
+ - **Tablet (768px-1023px)**: Two columns where appropriate
167
+ - **Desktop (≥1024px)**: Three columns, full layout
168
+
169
+ **Alternatives Considered**:
170
+ - Custom breakpoints: Unnecessary complexity
171
+ - Container queries: Not widely supported yet
172
+ - Fixed pixel widths: Not responsive
173
+
174
+ **References**:
175
+ - Existing: `frontend/tailwind.config.ts`
176
+ - Tailwind Responsive Design: https://tailwindcss.com/docs/responsive-design
177
+
178
+ ---
179
+
180
+ ### 6. Touch Target Sizing
181
+
182
+ **Decision**: Minimum 44x44px for all interactive elements
183
+
184
+ **Rationale**:
185
+ - WCAG 2.1 Level AAA guideline (44x44px)
186
+ - Apple Human Interface Guidelines (44x44pt)
187
+ - Material Design (48x48dp)
188
+ - Prevents accidental taps on mobile devices
189
+
190
+ **Pattern**:
191
+ ```tsx
192
+ <button className="min-h-[44px] min-w-[44px] px-4 py-2">
193
+ Click Me
194
+ </button>
195
+ ```
196
+
197
+ **Implementation**:
198
+ - Buttons: `min-h-[44px]` class
199
+ - Links: Adequate padding (py-2 px-3 minimum)
200
+ - Form inputs: `h-11` or `h-12` classes
201
+ - Checkboxes: `w-5 h-5` (20px) with larger clickable area via padding
202
+
203
+ **Alternatives Considered**:
204
+ - 48x48px: More generous but takes more space
205
+ - 40x40px: Below accessibility guidelines
206
+ - Variable sizing: Inconsistent, harder to maintain
207
+
208
+ **References**:
209
+ - WCAG 2.1 Success Criterion 2.5.5: https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
210
+ - Apple HIG: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/
211
+
212
+ ---
213
+
214
+ ### 7. API Client Error Handling
215
+
216
+ **Decision**: Centralized error handling in fetchAPI with typed errors
217
+
218
+ **Rationale**:
219
+ - Already implemented in `frontend/src/lib/api.ts`
220
+ - Consistent error structure across all API calls
221
+ - TypeScript types for error responses
222
+ - Automatic 401 handling with signin redirect
223
+
224
+ **Existing Implementation**:
225
+ ```typescript
226
+ class APIError extends Error {
227
+ constructor(
228
+ message: string,
229
+ public status: number,
230
+ public errorCode?: string,
231
+ public fieldErrors?: Record<string, string[]>
232
+ ) {
233
+ super(message);
234
+ this.name = 'APIError';
235
+ }
236
+ }
237
+ ```
238
+
239
+ **Enhancement Needed**: None - existing implementation is sufficient
240
+
241
+ **Alternatives Considered**:
242
+ - Per-component error handling: Inconsistent, duplicated code
243
+ - Global error boundary: Too coarse-grained, loses context
244
+ - Axios interceptors: Adds dependency, fetch is sufficient
245
+
246
+ **References**:
247
+ - Existing: `frontend/src/lib/api.ts` (lines 6-16, 18-59)
248
+
249
+ ---
250
+
251
+ ### 8. Form Validation Patterns
252
+
253
+ **Decision**: Client-side validation with inline error messages
254
+
255
+ **Rationale**:
256
+ - Already implemented in SignUpForm and SignInForm
257
+ - Immediate feedback improves UX
258
+ - Reduces unnecessary API calls
259
+ - Backend validation still enforced (defense in depth)
260
+
261
+ **Existing Pattern**:
262
+ ```typescript
263
+ const [errors, setErrors] = useState<Record<string, string>>({});
264
+
265
+ const validateEmail = (email: string): boolean => {
266
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
267
+ return emailRegex.test(email);
268
+ };
269
+
270
+ // Display errors inline
271
+ {errors.email && (
272
+ <p className="text-red-600 text-sm mt-1">{errors.email}</p>
273
+ )}
274
+ ```
275
+
276
+ **Enhancement Needed**: None - existing validation is sufficient
277
+
278
+ **Alternatives Considered**:
279
+ - Form libraries (React Hook Form, Formik): Overkill for simple forms
280
+ - Schema validation (Zod, Yup): Adds complexity, not needed
281
+ - Server-side only: Poor UX, slow feedback
282
+
283
+ **References**:
284
+ - Existing: `frontend/src/components/auth/SignUpForm.tsx` (lines 20-40)
285
+ - Existing: `frontend/src/components/auth/SignInForm.tsx`
286
+
287
+ ---
288
+
289
+ ### 9. Optimistic UI Updates
290
+
291
+ **Decision**: Update UI immediately, rollback on error
292
+
293
+ **Rationale**:
294
+ - Improves perceived performance
295
+ - Makes app feel responsive
296
+ - Standard pattern for modern web apps
297
+ - Easy to implement with React state
298
+
299
+ **Pattern**:
300
+ ```typescript
301
+ const handleToggleComplete = async (taskId: number) => {
302
+ // Optimistic update
303
+ setTasks(tasks.map(t =>
304
+ t.id === taskId ? { ...t, completed: !t.completed } : t
305
+ ));
306
+
307
+ try {
308
+ await patchTask(taskId, { completed: !task.completed });
309
+ } catch (error) {
310
+ // Rollback on error
311
+ setTasks(tasks.map(t =>
312
+ t.id === taskId ? { ...t, completed: task.completed } : t
313
+ ));
314
+ setError('Failed to update task');
315
+ }
316
+ };
317
+ ```
318
+
319
+ **Alternatives Considered**:
320
+ - Wait for server response: Slower, less responsive
321
+ - No rollback: Inconsistent state on errors
322
+ - Pessimistic updates: Poor UX
323
+
324
+ **References**:
325
+ - React Optimistic Updates: https://react.dev/reference/react/useOptimistic
326
+ - Existing: Partially implemented in TaskItem component
327
+
328
+ ---
329
+
330
+ ### 10. Environment Configuration
331
+
332
+ **Decision**: Use .env files with clear documentation
333
+
334
+ **Rationale**:
335
+ - Already established in Specs 1 & 2
336
+ - Standard practice for web applications
337
+ - Keeps secrets out of source code
338
+ - Easy to configure for different environments
339
+
340
+ **Existing Configuration**:
341
+ - Backend: `backend/.env` (DATABASE_URL, BETTER_AUTH_SECRET, JWT_ALGORITHM, JWT_EXPIRATION_DAYS)
342
+ - Frontend: `frontend/.env.local` (NEXT_PUBLIC_API_URL, BETTER_AUTH_SECRET)
343
+
344
+ **Enhancement Needed**: Document in README files and quickstart.md
345
+
346
+ **Alternatives Considered**:
347
+ - Hardcoded values: Security risk, not flexible
348
+ - Config files: Less standard than .env
349
+ - Cloud secret managers: Overkill for local development
350
+
351
+ **References**:
352
+ - Existing: `backend/.env`, `frontend/.env.local`
353
+ - Next.js Environment Variables: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables
354
+
355
+ ---
356
+
357
+ ## Summary of Decisions
358
+
359
+ | Area | Decision | Status |
360
+ |------|----------|--------|
361
+ | UI State Management | React hooks (useState, useEffect) | ✅ Existing |
362
+ | Loading Indicators | Tailwind CSS spinner with text | 🔄 To implement |
363
+ | Empty States | Centered message with CTA | 🔄 To implement |
364
+ | Error Display | Inline errors with retry button | 🔄 To implement |
365
+ | Responsive Design | Tailwind default breakpoints | ✅ Existing |
366
+ | Touch Targets | Minimum 44x44px | 🔄 To verify |
367
+ | API Error Handling | Centralized fetchAPI with typed errors | ✅ Existing |
368
+ | Form Validation | Client-side with inline errors | ✅ Existing |
369
+ | Optimistic Updates | Immediate UI update with rollback | 🔄 To implement |
370
+ | Environment Config | .env files with documentation | ✅ Existing |
371
+
372
+ **Legend**:
373
+ - ✅ Existing: Already implemented in Specs 1 & 2
374
+ - 🔄 To implement: Needs to be added in this feature
375
+ - 🔄 To verify: Needs to be checked/refined
376
+
377
+ ## Implementation Priorities
378
+
379
+ Based on user story priorities (P1-P5):
380
+
381
+ 1. **P1 (Authentication Flow)**: Verify existing implementation works end-to-end
382
+ 2. **P2 (UI States)**: Implement loading, empty, and error states
383
+ 3. **P3 (Responsive Design)**: Verify and refine responsive layouts
384
+ 4. **P4 (API Communication)**: Verify centralized API client works correctly
385
+ 5. **P5 (Environment Setup)**: Document configuration in README files
386
+
387
+ ## Next Steps
388
+
389
+ 1. Generate `data-model.md` (reference existing User and Task entities)
390
+ 2. Generate `contracts/` (document existing API endpoints)
391
+ 3. Generate `quickstart.md` (testing and setup guide)
392
+ 4. Proceed to task generation (`/sp.tasks`)
specs/002-fullstack-ui-integration/spec.md ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Feature Specification: Full-Stack Integration & UI Experience
2
+
3
+ **Feature Branch**: `002-fullstack-ui-integration`
4
+ **Created**: 2026-01-09
5
+ **Status**: Draft
6
+ **Input**: User description: "Full-Stack Integration & UI Experience – Phase II Todo Web App"
7
+
8
+ ## User Scenarios & Testing *(mandatory)*
9
+
10
+ ### User Story 1 - Complete Authentication Flow (Priority: P1) 🎯 MVP
11
+
12
+ A new user visits the application, creates an account, signs in, and immediately sees a clean, responsive interface ready for task management.
13
+
14
+ **Why this priority**: This is the entry point for all users. Without a seamless authentication experience, users cannot access any functionality. This story validates the entire authentication integration from Spec 2 works end-to-end with proper UI feedback.
15
+
16
+ **Independent Test**: Navigate to the application URL, complete signup form, verify redirect to signin, sign in with credentials, and land on the task management page with user profile displayed in header.
17
+
18
+ **Acceptance Scenarios**:
19
+
20
+ 1. **Given** a new user visits the application root URL, **When** they are not authenticated, **Then** they are automatically redirected to the signin page with a link to signup
21
+ 2. **Given** a user on the signup page, **When** they submit valid credentials (email, password, name), **Then** they see a success message and are redirected to signin page
22
+ 3. **Given** a user on the signup page, **When** they submit invalid data (weak password, invalid email), **Then** they see clear inline validation errors without page reload
23
+ 4. **Given** a registered user on the signin page, **When** they submit correct credentials, **Then** they are redirected to the home page with their name displayed in the header
24
+ 5. **Given** a user on the signin page, **When** they submit incorrect credentials, **Then** they see a generic error message "Invalid email or password" without revealing which field is wrong
25
+ 6. **Given** an authenticated user on the home page, **When** they click the "Sign Out" button, **Then** their session is cleared and they are redirected to the signin page
26
+
27
+ ---
28
+
29
+ ### User Story 2 - Responsive UI States (Priority: P2)
30
+
31
+ Users experience appropriate visual feedback during all application states: loading data, empty states, error conditions, and successful operations.
32
+
33
+ **Why this priority**: Professional applications provide clear feedback. Users should never wonder if the app is working or broken. This story ensures the UI communicates system state effectively.
34
+
35
+ **Independent Test**: Sign in, observe loading spinner while tasks load, create first task and see empty state disappear, disconnect network and see error state, reconnect and see recovery.
36
+
37
+ **Acceptance Scenarios**:
38
+
39
+ 1. **Given** a user signs in successfully, **When** the task list is loading, **Then** they see a loading spinner with "Loading tasks..." message
40
+ 2. **Given** a new user with no tasks, **When** the task list finishes loading, **Then** they see an empty state with "No tasks yet" message and a call-to-action to create their first task
41
+ 3. **Given** a user viewing their task list, **When** a network error occurs, **Then** they see a clear error message "Unable to load tasks. Please check your connection." with a retry button
42
+ 4. **Given** a user creating a new task, **When** the API request is in progress, **Then** the submit button shows "Creating..." and is disabled to prevent duplicate submissions
43
+ 5. **Given** a user on any page, **When** their JWT token expires, **Then** they are automatically redirected to signin with a message "Your session has expired. Please sign in again."
44
+ 6. **Given** a user completing a task, **When** the update succeeds, **Then** the task UI updates immediately (optimistic update) without requiring a full page reload
45
+
46
+ ---
47
+
48
+ ### User Story 3 - Responsive Design (Priority: P3)
49
+
50
+ Users can access and use the application seamlessly across desktop, tablet, and mobile devices with appropriate layout adjustments.
51
+
52
+ **Why this priority**: Modern web applications must work on all screen sizes. This story ensures the UI adapts gracefully to different viewports, making the app accessible to users on any device.
53
+
54
+ **Independent Test**: Open the application on desktop (1920px), tablet (768px), and mobile (375px) viewports. Verify all functionality is accessible and layouts adjust appropriately.
55
+
56
+ **Acceptance Scenarios**:
57
+
58
+ 1. **Given** a user on a desktop browser (≥1024px), **When** they view the home page, **Then** they see a three-column layout: task form (left), filters (middle), task list (right)
59
+ 2. **Given** a user on a tablet (768px-1023px), **When** they view the home page, **Then** they see a two-column layout: task form and filters stacked (left), task list (right)
60
+ 3. **Given** a user on a mobile device (<768px), **When** they view the home page, **Then** they see a single-column layout with task form, filters, and task list stacked vertically
61
+ 4. **Given** a user on any device, **When** they interact with buttons and form inputs, **Then** touch targets are at least 44x44px for comfortable interaction
62
+ 5. **Given** a user on mobile, **When** they view the signin/signup forms, **Then** the forms are centered, readable, and keyboard-friendly with appropriate input types (email, password)
63
+ 6. **Given** a user on any device, **When** they navigate the application, **Then** all text is readable without horizontal scrolling and maintains proper contrast ratios
64
+
65
+ ---
66
+
67
+ ### User Story 4 - Centralized API Communication (Priority: P4)
68
+
69
+ All frontend-backend communication flows through a unified API client that handles authentication, error handling, and request/response formatting consistently.
70
+
71
+ **Why this priority**: Consistent API communication prevents bugs and makes the codebase maintainable. This story ensures all API calls follow the same patterns for auth, errors, and data handling.
72
+
73
+ **Independent Test**: Review the codebase to verify all API calls use the centralized `fetchAPI` function. Test that JWT tokens are automatically included, 401 errors trigger signin redirect, and error responses are consistently formatted.
74
+
75
+ **Acceptance Scenarios**:
76
+
77
+ 1. **Given** any component making an API request, **When** the request is initiated, **Then** the JWT token is automatically included in the Authorization header without manual intervention
78
+ 2. **Given** an API request in progress, **When** the backend returns a 401 Unauthorized, **Then** the user is automatically redirected to signin and their session is cleared
79
+ 3. **Given** an API request fails, **When** the backend returns an error response, **Then** the error is caught and formatted consistently with `{ detail, error_code, field_errors }` structure
80
+ 4. **Given** a component making multiple API calls, **When** any call fails, **Then** the error is handled locally without crashing the entire application
81
+ 5. **Given** the backend is unreachable, **When** an API request times out, **Then** the user sees a clear error message "Unable to connect to server. Please try again later."
82
+ 6. **Given** a successful API response, **When** the data is returned, **Then** it is automatically parsed as JSON and typed correctly for TypeScript consumers
83
+
84
+ ---
85
+
86
+ ### User Story 5 - Environment Coordination (Priority: P5)
87
+
88
+ The application runs successfully in local development with proper environment variable configuration and clear setup instructions.
89
+
90
+ **Why this priority**: Developers and reviewers need to run the application easily. This story ensures environment setup is straightforward and well-documented.
91
+
92
+ **Independent Test**: Clone the repository, follow README instructions to set up environment variables, start backend and frontend, and verify the application works end-to-end.
93
+
94
+ **Acceptance Scenarios**:
95
+
96
+ 1. **Given** a developer cloning the repository, **When** they follow the backend README, **Then** they can set up the database, configure environment variables, and start the backend server successfully
97
+ 2. **Given** a developer with the backend running, **When** they follow the frontend README, **Then** they can configure environment variables and start the frontend development server successfully
98
+ 3. **Given** both servers running, **When** a user accesses `http://localhost:3000`, **Then** the frontend successfully communicates with the backend at `http://localhost:8000`
99
+ 4. **Given** environment variables are missing, **When** the application starts, **Then** clear error messages indicate which variables are required (e.g., "BETTER_AUTH_SECRET is required")
100
+ 5. **Given** the BETTER_AUTH_SECRET differs between frontend and backend, **When** a user tries to sign in, **Then** token verification fails with a clear error message
101
+ 6. **Given** the database is not running, **When** the backend starts, **Then** it shows a clear error message "Unable to connect to database at [URL]"
102
+
103
+ ---
104
+
105
+ ### Edge Cases
106
+
107
+ - What happens when a user's JWT token expires while they're actively using the application (e.g., editing a task)?
108
+ - How does the system handle rapid successive API calls (e.g., user clicking "Create Task" multiple times)?
109
+ - What happens when the backend returns a 500 Internal Server Error?
110
+ - How does the UI behave when task titles or descriptions contain special characters, emojis, or very long text?
111
+ - What happens when a user tries to access a protected route by manually typing the URL while unauthenticated?
112
+ - How does the application handle browser back/forward navigation after signin/signout?
113
+ - What happens when localStorage is disabled or unavailable in the browser?
114
+ - How does the system handle concurrent edits (user edits same task in two browser tabs)?
115
+
116
+ ## Requirements *(mandatory)*
117
+
118
+ ### Functional Requirements
119
+
120
+ - **FR-001**: System MUST redirect unauthenticated users from protected routes to the signin page automatically
121
+ - **FR-002**: System MUST display user profile information (name or email) in the application header when authenticated
122
+ - **FR-003**: System MUST show loading indicators during all asynchronous operations (API calls, page transitions)
123
+ - **FR-004**: System MUST display empty states with helpful messages when no data exists (e.g., "No tasks yet. Create your first task!")
124
+ - **FR-005**: System MUST show clear error messages when operations fail, with actionable guidance (e.g., "Retry" button)
125
+ - **FR-006**: System MUST handle JWT token expiration gracefully by redirecting to signin with an appropriate message
126
+ - **FR-007**: System MUST prevent duplicate form submissions by disabling submit buttons during API requests
127
+ - **FR-008**: System MUST validate all form inputs on the client side before submission with inline error messages
128
+ - **FR-009**: System MUST adapt layout and component sizing based on viewport width (responsive design)
129
+ - **FR-010**: System MUST ensure all interactive elements have minimum touch target size of 44x44px for mobile usability
130
+ - **FR-011**: System MUST route all API requests through a centralized client that handles authentication automatically
131
+ - **FR-012**: System MUST include JWT tokens in Authorization headers for all protected API endpoints
132
+ - **FR-013**: System MUST catch and format all API errors consistently across the application
133
+ - **FR-014**: System MUST clear user session and redirect to signin on 401 Unauthorized responses
134
+ - **FR-015**: System MUST persist authentication state across page refreshes using localStorage
135
+ - **FR-016**: System MUST provide clear setup instructions in README files for both frontend and backend
136
+ - **FR-017**: System MUST validate that required environment variables are present on application startup
137
+ - **FR-018**: System MUST use the same BETTER_AUTH_SECRET in both frontend and backend for JWT verification
138
+ - **FR-019**: System MUST display appropriate CORS configuration to allow frontend-backend communication
139
+ - **FR-020**: System MUST use Tailwind CSS utility classes exclusively for styling (no inline styles)
140
+
141
+ ### Key Entities
142
+
143
+ This feature focuses on integration and UI experience rather than introducing new data entities. It leverages existing entities from Specs 1 and 2:
144
+
145
+ - **User**: Authenticated user with profile information (from Spec 2)
146
+ - **Task**: User's todo items with CRUD operations (from Spec 1)
147
+ - **AuthSession**: Frontend session state containing JWT token and user profile (from Spec 2)
148
+
149
+ ## Success Criteria *(mandatory)*
150
+
151
+ ### Measurable Outcomes
152
+
153
+ - **SC-001**: Users can complete the full flow from signup to creating their first task in under 3 minutes
154
+ - **SC-002**: All loading states appear within 100ms of initiating an action to provide immediate feedback
155
+ - **SC-003**: Empty states provide clear guidance, resulting in 80% of new users creating their first task within 2 minutes
156
+ - **SC-004**: Error messages are clear enough that users can resolve issues without external help 90% of the time
157
+ - **SC-005**: The application layout adapts correctly to viewport widths from 320px (mobile) to 1920px (desktop) without horizontal scrolling
158
+ - **SC-006**: All interactive elements are accessible and usable on touch devices with no accidental clicks
159
+ - **SC-007**: JWT token expiration is handled gracefully with zero application crashes or undefined states
160
+ - **SC-008**: API errors are caught and displayed consistently across all features with zero unhandled promise rejections
161
+ - **SC-009**: Developers can set up and run the application locally in under 10 minutes following README instructions
162
+ - **SC-010**: The application works end-to-end in local development with proper environment configuration
163
+
164
+ ## Assumptions *(mandatory)*
165
+
166
+ 1. **Existing Functionality**: Specs 1 (Task CRUD) and 2 (Authentication) are fully implemented and functional
167
+ 2. **Browser Support**: Modern browsers with ES6+ support (Chrome, Firefox, Safari, Edge - latest 2 versions)
168
+ 3. **JavaScript Enabled**: Users have JavaScript enabled in their browsers
169
+ 4. **Network Connectivity**: Users have stable internet connection for API communication
170
+ 5. **LocalStorage Available**: Browser supports and allows localStorage for session persistence
171
+ 6. **Development Environment**: Developers have Node.js 18+, Python 3.11+, and PostgreSQL installed
172
+ 7. **Screen Sizes**: Target devices range from 320px (small mobile) to 1920px (desktop)
173
+ 8. **Single User Session**: Users are expected to use one browser session at a time (concurrent sessions not optimized)
174
+ 9. **English Language**: All UI text and error messages are in English
175
+ 10. **No Offline Support**: Application requires active internet connection (no offline mode)
176
+
177
+ ## Dependencies *(mandatory)*
178
+
179
+ ### Internal Dependencies
180
+
181
+ - **Spec 1 - Task CRUD**: All task management endpoints must be functional
182
+ - **Spec 2 - Authentication & API Security**: JWT authentication and user management must be working
183
+ - **Backend API**: FastAPI server must be running and accessible
184
+ - **Database**: PostgreSQL database with all migrations applied
185
+ - **Environment Variables**: BETTER_AUTH_SECRET, DATABASE_URL, API URLs configured correctly
186
+
187
+ ### External Dependencies
188
+
189
+ - **Next.js 16+**: Frontend framework with App Router
190
+ - **React 18+**: UI library
191
+ - **TypeScript 5.x**: Type safety
192
+ - **Tailwind CSS 3.x**: Styling framework
193
+ - **FastAPI**: Backend framework
194
+ - **SQLModel**: ORM for database operations
195
+ - **Better Auth**: Authentication library
196
+ - **JWT**: Token-based authentication
197
+
198
+ ## Out of Scope *(mandatory)*
199
+
200
+ The following are explicitly NOT included in this specification:
201
+
202
+ 1. **New Backend Logic**: No new API endpoints or business logic (handled in Spec 1)
203
+ 2. **New Authentication Mechanisms**: No OAuth, SSO, or MFA (handled in Spec 2)
204
+ 3. **Advanced Animations**: No complex transitions, animations, or motion design
205
+ 4. **Design System**: No comprehensive component library or design tokens
206
+ 5. **Mobile Native Apps**: No iOS or Android native applications
207
+ 6. **Progressive Web App (PWA)**: No offline support, service workers, or installability
208
+ 7. **Internationalization (i18n)**: No multi-language support
209
+ 8. **Accessibility Audit**: No WCAG compliance testing (basic accessibility assumed)
210
+ 9. **Performance Optimization**: No advanced caching, code splitting beyond Next.js defaults, or CDN setup
211
+ 10. **CI/CD Pipelines**: No automated testing, deployment, or infrastructure scripts
212
+ 11. **Docker Deployment**: No production Docker configuration (local development only)
213
+ 12. **Monitoring & Analytics**: No error tracking, user analytics, or performance monitoring
214
+ 13. **SEO Optimization**: No meta tags, sitemaps, or search engine optimization
215
+ 14. **Email Notifications**: No email verification, password reset emails, or notifications
216
+ 15. **Real-time Features**: No WebSockets, live updates, or collaborative editing
217
+
218
+ ## References
219
+
220
+ - **@specs/ui/components.md**: Component design specifications (if exists)
221
+ - **@specs/ui/pages.md**: Page layout specifications (if exists)
222
+ - **@specs/overview.md**: Project overview and architecture (if exists)
223
+ - **@specs/architecture.md**: Technical architecture decisions (if exists)
224
+ - **Spec 1**: Task CRUD API implementation
225
+ - **Spec 2**: Authentication & API Security implementation
226
+ - **Next.js App Router Documentation**: https://nextjs.org/docs/app
227
+ - **Tailwind CSS Documentation**: https://tailwindcss.com/docs
228
+ - **Better Auth Documentation**: https://better-auth.com/docs
229
+
230
+ ## Notes
231
+
232
+ This specification focuses on polishing and integrating existing functionality rather than building new features. The goal is to create a cohesive, professional user experience that demonstrates the full capabilities of the Phase II Todo Web App for hackathon evaluation.
233
+
234
+ Key integration points:
235
+ - Frontend ↔ Backend: Unified API client with automatic JWT handling
236
+ - Authentication ↔ UI: Seamless auth state management across all pages
237
+ - Components ↔ Styling: Consistent Tailwind CSS usage throughout
238
+ - Development ↔ Production: Clear environment setup and configuration
239
+
240
+ Success depends on attention to detail in error handling, loading states, and responsive design rather than adding new functionality.
specs/002-fullstack-ui-integration/tasks.md ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tasks: Full-Stack Integration & UI Experience
2
+
3
+ **Input**: Design documents from `/specs/002-fullstack-ui-integration/`
4
+ **Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md
5
+
6
+ **Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
7
+
8
+ **Note**: Tests are not included as they were not explicitly requested in the feature specification. This feature focuses on integration and polish of existing functionality.
9
+
10
+ ## Format: `[ID] [P?] [Story] Description`
11
+
12
+ - **[P]**: Can run in parallel (different files, no dependencies)
13
+ - **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
14
+ - Include exact file paths in descriptions
15
+
16
+ ## Path Conventions
17
+
18
+ - **Web app**: `backend/src/`, `frontend/src/`
19
+ - All paths are relative to repository root
20
+
21
+ ---
22
+
23
+ ## Phase 1: Setup (6 tasks)
24
+
25
+ **Purpose**: Verify project structure and dependencies
26
+
27
+ - [x] T001 Verify backend project structure matches plan.md (backend/src/ with api/, core/, models/, schemas/, services/)
28
+ - [x] T002 Verify frontend project structure matches plan.md (frontend/src/ with app/, components/, lib/, providers/)
29
+ - [x] T003 [P] Verify backend dependencies installed (FastAPI, SQLModel, PyJWT, passlib, alembic)
30
+ - [x] T004 [P] Verify frontend dependencies installed (Next.js 16+, React 18+, TypeScript 5.x, Tailwind CSS 3.x)
31
+ - [x] T005 [P] Verify database connection works (backend can connect to PostgreSQL)
32
+ - [x] T006 [P] Verify environment variables exist (backend/.env and frontend/.env.local)
33
+
34
+ **Checkpoint**: Project structure and dependencies verified
35
+
36
+ ---
37
+
38
+ ## Phase 2: Foundational (7 tasks)
39
+
40
+ **Purpose**: Verify core infrastructure from Specs 1 & 2 works correctly
41
+
42
+ **⚠️ CRITICAL**: These tasks verify existing implementations are functional before adding UI polish
43
+
44
+ - [x] T007 Verify auth router is registered in backend/src/main.py (POST /api/auth/signup, POST /api/auth/signin, GET /api/auth/me)
45
+ - [x] T008 Verify task router is registered in backend/src/main.py (GET/POST /api/tasks, GET/PUT/PATCH/DELETE /api/tasks/{id})
46
+ - [x] T009 [P] Verify JWT token generation works in backend/src/core/security.py (create_access_token function)
47
+ - [x] T010 [P] Verify JWT token verification works in backend/src/api/deps.py (get_current_user dependency)
48
+ - [x] T011 [P] Verify API client exists in frontend/src/lib/api.ts with fetchAPI function
49
+ - [x] T012 [P] Verify AuthProvider exists in frontend/src/providers/AuthProvider.tsx with session management
50
+ - [x] T013 Test end-to-end flow: signup → signin → create task → signout (manual verification)
51
+
52
+ **Checkpoint**: Foundation verified - all existing implementations functional
53
+
54
+ ---
55
+
56
+ ## Phase 3: User Story 1 - Complete Authentication Flow (Priority: P1) 🎯 MVP (8 tasks)
57
+
58
+ **Goal**: Ensure seamless authentication experience from signup to task management
59
+
60
+ **Independent Test**: Navigate to application URL, complete signup, signin, and land on task management page with user profile displayed
61
+
62
+ ### Implementation for User Story 1
63
+
64
+ - [x] T014 [P] [US1] Verify signup page exists at frontend/src/app/auth/signup/page.tsx with validation
65
+ - [x] T015 [P] [US1] Verify signin page exists at frontend/src/app/auth/signin/page.tsx with validation
66
+ - [x] T016 [US1] Verify protected route redirect in frontend/src/app/page.tsx (redirects unauthenticated users to signin)
67
+ - [x] T017 [US1] Add user profile display to header in frontend/src/app/layout.tsx (show "Welcome, {name}" when authenticated)
68
+ - [x] T018 [US1] Add signout button to header in frontend/src/app/layout.tsx (clears session and redirects to signin)
69
+ - [x] T019 [US1] Verify inline validation errors display in frontend/src/components/auth/SignUpForm.tsx (email, password, name)
70
+ - [x] T020 [US1] Verify inline validation errors display in frontend/src/components/auth/SignInForm.tsx (email, password)
71
+ - [x] T021 [US1] Test complete authentication flow: signup → signin → home page → signout (manual validation per quickstart.md)
72
+
73
+ **Checkpoint**: User Story 1 complete - authentication flow works end-to-end with proper UI feedback
74
+
75
+ ---
76
+
77
+ ## Phase 4: User Story 2 - Responsive UI States (Priority: P2) (8 tasks)
78
+
79
+ **Goal**: Provide clear visual feedback during all application states
80
+
81
+ **Independent Test**: Sign in, observe loading spinner, create first task and see empty state disappear, disconnect network and see error state
82
+
83
+ ### Implementation for User Story 2
84
+
85
+ - [x] T022 [P] [US2] Add loading state to TaskList in frontend/src/components/tasks/TaskList.tsx (spinner with "Loading tasks..." message)
86
+ - [x] T023 [P] [US2] Add empty state to TaskList in frontend/src/components/tasks/TaskList.tsx (centered "No tasks yet" with CTA)
87
+ - [x] T024 [P] [US2] Add error state to TaskList in frontend/src/components/tasks/TaskList.tsx (error message with retry button)
88
+ - [x] T025 [P] [US2] Add loading state to TaskForm in frontend/src/components/tasks/TaskForm.tsx (disable submit button, show "Creating...")
89
+ - [x] T026 [US2] Add token expiration handling in frontend/src/lib/api.ts (redirect to signin with "Session expired" message on 401)
90
+ - [x] T027 [US2] Implement optimistic update for task completion in frontend/src/components/tasks/TaskItem.tsx (immediate UI update with rollback on error)
91
+ - [x] T028 [US2] Add loading state to task update operations in frontend/src/components/tasks/TaskItem.tsx (disable buttons during update)
92
+ - [x] T029 [US2] Test all UI states: loading, empty, error, token expiration (manual validation per quickstart.md)
93
+
94
+ **Checkpoint**: User Story 2 complete - all UI states provide clear feedback
95
+
96
+ ---
97
+
98
+ ## Phase 5: User Story 3 - Responsive Design (Priority: P3) (8 tasks)
99
+
100
+ **Goal**: Ensure application works seamlessly across desktop, tablet, and mobile devices
101
+
102
+ **Independent Test**: Open application at 1920px, 768px, and 375px viewports - verify layouts adjust appropriately
103
+
104
+ ### Implementation for User Story 3
105
+
106
+ - [x] T030 [P] [US3] Verify/refine desktop layout in frontend/src/app/page.tsx (3-column: form, filters, list at ≥1024px)
107
+ - [x] T031 [P] [US3] Verify/refine tablet layout in frontend/src/app/page.tsx (2-column: form+filters, list at 768px-1023px)
108
+ - [x] T032 [P] [US3] Verify/refine mobile layout in frontend/src/app/page.tsx (1-column: stacked at <768px)
109
+ - [x] T033 [P] [US3] Verify touch target sizes in all buttons (min-h-[44px] min-w-[44px] classes)
110
+ - [x] T034 [P] [US3] Verify form responsiveness in frontend/src/components/auth/SignInForm.tsx (centered, readable on mobile)
111
+ - [x] T035 [P] [US3] Verify form responsiveness in frontend/src/components/auth/SignUpForm.tsx (centered, readable on mobile)
112
+ - [x] T036 [US3] Test responsive layouts at breakpoints: 375px (mobile), 768px (tablet), 1920px (desktop) using browser DevTools
113
+ - [x] T037 [US3] Verify no horizontal scrolling at any viewport width (manual validation per quickstart.md)
114
+
115
+ **Checkpoint**: User Story 3 complete - responsive design works across all devices
116
+
117
+ ---
118
+
119
+ ## Phase 6: User Story 4 - Centralized API Communication (Priority: P4) (7 tasks)
120
+
121
+ **Goal**: Ensure all API communication flows through unified client with consistent error handling
122
+
123
+ **Independent Test**: Review codebase to verify all API calls use fetchAPI, test JWT inclusion and 401 handling
124
+
125
+ ### Implementation for User Story 4
126
+
127
+ - [x] T038 [P] [US4] Verify fetchAPI includes JWT token automatically in frontend/src/lib/api.ts (Authorization: Bearer header)
128
+ - [x] T039 [P] [US4] Verify 401 handling redirects to signin in frontend/src/lib/api.ts (clear session and redirect)
129
+ - [x] T040 [P] [US4] Verify error formatting consistency in frontend/src/lib/api.ts (APIError with detail, error_code, field_errors)
130
+ - [x] T041 [US4] Audit all components to ensure they use fetchAPI (TaskList, TaskForm, TaskItem, SignUpForm, SignInForm)
131
+ - [x] T042 [US4] Add timeout handling to fetchAPI in frontend/src/lib/api.ts (show "Unable to connect to server" on timeout)
132
+ - [x] T043 [US4] Test error scenarios: 401 Unauthorized, 500 Internal Server Error, network timeout (manual validation)
133
+ - [x] T044 [US4] Verify no unhandled promise rejections in browser console during error scenarios
134
+
135
+ **Checkpoint**: User Story 4 complete - API communication is centralized and consistent
136
+
137
+ ---
138
+
139
+ ## Phase 7: User Story 5 - Environment Coordination (Priority: P5) (6 tasks)
140
+
141
+ **Goal**: Ensure developers can set up and run the application easily
142
+
143
+ **Independent Test**: Follow README instructions to set up environment variables, start servers, and verify end-to-end functionality
144
+
145
+ ### Implementation for User Story 5
146
+
147
+ - [x] T045 [P] [US5] Update backend/README.md with setup instructions (database setup, environment variables, migrations, server start)
148
+ - [x] T046 [P] [US5] Update frontend/README.md with setup instructions (environment variables, dependencies, server start)
149
+ - [x] T047 [P] [US5] Document all environment variables in backend/README.md (DATABASE_URL, BETTER_AUTH_SECRET, JWT_ALGORITHM, JWT_EXPIRATION_DAYS)
150
+ - [x] T048 [P] [US5] Document all environment variables in frontend/README.md (NEXT_PUBLIC_API_URL, BETTER_AUTH_SECRET)
151
+ - [x] T049 [US5] Add environment variable validation on backend startup in backend/src/main.py (check required vars, show clear errors)
152
+ - [x] T050 [US5] Test setup from scratch: clone repo, follow README, verify application works (manual validation per quickstart.md)
153
+
154
+ **Checkpoint**: User Story 5 complete - environment setup is documented and validated
155
+
156
+ ---
157
+
158
+ ## Phase 8: Polish & Cross-Cutting Concerns (4 tasks)
159
+
160
+ **Purpose**: Final refinements and validation
161
+
162
+ - [x] T051 [P] Code cleanup: Remove console.logs, unused imports, commented code across frontend/src/
163
+ - [x] T052 [P] Verify all Tailwind CSS classes are used correctly (no inline styles) across frontend/src/
164
+ - [ ] T053 Manual testing: Complete all test scenarios in specs/002-fullstack-ui-integration/quickstart.md
165
+ - [ ] T054 Final validation: Run through all 5 user stories end-to-end and verify acceptance criteria
166
+
167
+ **Checkpoint**: Feature complete and ready for demo/review
168
+
169
+ ---
170
+
171
+ ## Dependencies & Execution Order
172
+
173
+ ### Phase Dependencies
174
+
175
+ - **Setup (Phase 1)**: No dependencies - can start immediately
176
+ - **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
177
+ - **User Stories (Phase 3-7)**: All depend on Foundational phase completion
178
+ - User stories can proceed in parallel (if staffed)
179
+ - Or sequentially in priority order (P1 → P2 → P3 → P4 → P5)
180
+ - **Polish (Phase 8)**: Depends on all user stories being complete
181
+
182
+ ### User Story Dependencies
183
+
184
+ - **User Story 1 (P1 - MVP)**: Can start after Foundational (Phase 2) - No dependencies on other stories
185
+ - **User Story 2 (P2)**: Can start after Foundational (Phase 2) - Independent of US1 but builds on existing components
186
+ - **User Story 3 (P3)**: Can start after Foundational (Phase 2) - Independent of US1/US2
187
+ - **User Story 4 (P4)**: Can start after Foundational (Phase 2) - Independent of US1/US2/US3
188
+ - **User Story 5 (P5)**: Can start after Foundational (Phase 2) - Independent of all other stories
189
+
190
+ ### Within Each User Story
191
+
192
+ - Tasks marked [P] can run in parallel (different files)
193
+ - Tasks without [P] may have dependencies on previous tasks in the same story
194
+ - Complete all tasks in a story before moving to next priority
195
+
196
+ ### Parallel Opportunities
197
+
198
+ - **Phase 1**: T003, T004, T005, T006 can run in parallel
199
+ - **Phase 2**: T009, T010, T011, T012 can run in parallel
200
+ - **Phase 3 (US1)**: T014, T015 can run in parallel
201
+ - **Phase 4 (US2)**: T022, T023, T024, T025 can run in parallel
202
+ - **Phase 5 (US3)**: T030, T031, T032, T033, T034, T035 can run in parallel
203
+ - **Phase 6 (US4)**: T038, T039, T040 can run in parallel
204
+ - **Phase 7 (US5)**: T045, T046, T047, T048 can run in parallel
205
+ - **Phase 8**: T051, T052 can run in parallel
206
+
207
+ ---
208
+
209
+ ## Parallel Example: User Story 2 (Responsive UI States)
210
+
211
+ ```bash
212
+ # Launch all UI state additions in parallel:
213
+ Task: "Add loading state to TaskList in frontend/src/components/tasks/TaskList.tsx"
214
+ Task: "Add empty state to TaskList in frontend/src/components/tasks/TaskList.tsx"
215
+ Task: "Add error state to TaskList in frontend/src/components/tasks/TaskList.tsx"
216
+ Task: "Add loading state to TaskForm in frontend/src/components/tasks/TaskForm.tsx"
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Implementation Strategy
222
+
223
+ ### MVP First (User Story 1 Only)
224
+
225
+ 1. Complete Phase 1: Setup (6 tasks)
226
+ 2. Complete Phase 2: Foundational (7 tasks) - CRITICAL
227
+ 3. Complete Phase 3: User Story 1 (8 tasks)
228
+ 4. **STOP and VALIDATE**: Test authentication flow end-to-end
229
+ 5. Demo/review if ready
230
+
231
+ **Total MVP tasks**: 21 tasks
232
+
233
+ ### Incremental Delivery
234
+
235
+ 1. Complete Setup + Foundational → Foundation verified (13 tasks)
236
+ 2. Add User Story 1 → Test independently → Demo (MVP!) (8 tasks)
237
+ 3. Add User Story 2 → Test independently → Demo (8 tasks)
238
+ 4. Add User Story 3 → Test independently → Demo (8 tasks)
239
+ 5. Add User Story 4 → Test independently → Demo (7 tasks)
240
+ 6. Add User Story 5 → Test independently → Demo (6 tasks)
241
+ 7. Polish → Final validation → Demo (4 tasks)
242
+
243
+ **Total tasks**: 54 tasks
244
+
245
+ ### Parallel Team Strategy
246
+
247
+ With multiple developers:
248
+
249
+ 1. Team completes Setup + Foundational together (13 tasks)
250
+ 2. Once Foundational is done:
251
+ - Developer A: User Story 1 (8 tasks)
252
+ - Developer B: User Story 2 (8 tasks)
253
+ - Developer C: User Story 3 (8 tasks)
254
+ 3. Then:
255
+ - Developer A: User Story 4 (7 tasks)
256
+ - Developer B: User Story 5 (6 tasks)
257
+ - Developer C: Polish (4 tasks)
258
+
259
+ ---
260
+
261
+ ## Task Summary
262
+
263
+ | Phase | User Story | Task Count | Parallel Tasks |
264
+ |-------|------------|------------|----------------|
265
+ | Phase 1: Setup | - | 6 | 4 |
266
+ | Phase 2: Foundational | - | 7 | 4 |
267
+ | Phase 3: US1 (MVP) | Complete Authentication Flow | 8 | 2 |
268
+ | Phase 4: US2 | Responsive UI States | 8 | 4 |
269
+ | Phase 5: US3 | Responsive Design | 8 | 6 |
270
+ | Phase 6: US4 | Centralized API Communication | 7 | 3 |
271
+ | Phase 7: US5 | Environment Coordination | 6 | 4 |
272
+ | Phase 8: Polish | Cross-Cutting Concerns | 4 | 2 |
273
+ | **TOTAL** | **5 User Stories** | **54** | **29** |
274
+
275
+ ---
276
+
277
+ ## Notes
278
+
279
+ - [P] tasks = different files, no dependencies - can run in parallel
280
+ - [Story] label maps task to specific user story for traceability
281
+ - Each user story should be independently completable and testable
282
+ - Most tasks are verification/refinement since Specs 1 & 2 already implemented core functionality
283
+ - Focus is on UI polish (loading states, empty states, error handling) and integration
284
+ - Manual testing per quickstart.md is critical for validation
285
+ - Commit after each task or logical group
286
+ - Stop at any checkpoint to validate story independently