Initial commit
This commit is contained in:
468
references/example-enhanced-phase.md
Normal file
468
references/example-enhanced-phase.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# Example: Enhanced Phase with File-Level Detail
|
||||
|
||||
This document shows before/after examples of phases with and without file-level detail enhancements.
|
||||
|
||||
---
|
||||
|
||||
## Example Project: Task Management API
|
||||
|
||||
A simple task management system with user authentication, CRUD operations, and tagging.
|
||||
|
||||
---
|
||||
|
||||
## BEFORE: Basic Phase (Without File-Level Detail)
|
||||
|
||||
```markdown
|
||||
## Phase 3: Tasks API
|
||||
|
||||
**Type**: API
|
||||
**Estimated**: 4 hours (~4 minutes human time)
|
||||
**Files**: `src/routes/tasks.ts`, `src/lib/schemas.ts`, `src/middleware/auth.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Create task validation schemas
|
||||
- [ ] Implement GET /api/tasks endpoint
|
||||
- [ ] Implement POST /api/tasks endpoint
|
||||
- [ ] Implement PATCH /api/tasks/:id endpoint
|
||||
- [ ] Implement DELETE /api/tasks/:id endpoint
|
||||
- [ ] Add error handling
|
||||
- [ ] Test all endpoints
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] All endpoints return correct status codes
|
||||
- [ ] Validation works properly
|
||||
- [ ] Authentication is enforced
|
||||
- [ ] CRUD operations work
|
||||
|
||||
### Exit Criteria
|
||||
Task API is complete and functional.
|
||||
```
|
||||
|
||||
**Problems with basic phase**:
|
||||
- ❌ Claude doesn't know file relationships (what imports what)
|
||||
- ❌ No indication of which file to start with
|
||||
- ❌ Missing security considerations (ownership checks)
|
||||
- ❌ No performance considerations (pagination)
|
||||
- ❌ Vague verification criteria
|
||||
- ❌ Token waste: Claude will grep/glob to understand structure
|
||||
|
||||
---
|
||||
|
||||
## AFTER: Enhanced Phase (With File-Level Detail)
|
||||
|
||||
```markdown
|
||||
## Phase 3: Tasks API
|
||||
|
||||
**Type**: API
|
||||
**Estimated**: 4 hours (~4 minutes human time)
|
||||
**Files**: `src/routes/tasks.ts` (new), `src/lib/schemas.ts` (modify), `src/middleware/auth.ts` (existing)
|
||||
|
||||
### File Map
|
||||
|
||||
- `src/routes/tasks.ts` (estimated ~150 lines)
|
||||
- **Purpose**: CRUD endpoints for task management
|
||||
- **Key exports**: GET, POST, PATCH, DELETE handlers
|
||||
- **Dependencies**:
|
||||
- `../lib/schemas` (taskSchema, createTaskSchema, updateTaskSchema)
|
||||
- `../middleware/auth` (authenticateUser middleware)
|
||||
- `env.DB` (D1 binding)
|
||||
- **Used by**: Main Hono app (src/index.ts)
|
||||
- **Route**: `/api/tasks` and `/api/tasks/:id`
|
||||
|
||||
- `src/lib/schemas.ts` (add ~40 lines to existing)
|
||||
- **Purpose**: Zod validation schemas for request/response validation
|
||||
- **Key exports**:
|
||||
- `taskSchema` - Complete task object
|
||||
- `createTaskSchema` - New task input validation
|
||||
- `updateTaskSchema` - Partial task updates
|
||||
- **Dependencies**: `zod` package
|
||||
- **Used by**: routes/tasks.ts (validation), frontend forms (type inference)
|
||||
- **Modifications**: Add three new schema definitions to existing file
|
||||
|
||||
- `src/middleware/auth.ts` (existing, no changes needed)
|
||||
- **Purpose**: JWT verification and user extraction
|
||||
- **Key exports**: `authenticateUser` middleware
|
||||
- **Note**: Already implemented in Phase 2, just import and use
|
||||
|
||||
### Data Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as Client (Browser)
|
||||
participant W as Worker (Hono)
|
||||
participant A as Auth Middleware
|
||||
participant V as Validator (Zod)
|
||||
participant D as D1 Database
|
||||
|
||||
C->>W: POST /api/tasks<br/>{title, description}
|
||||
Note over W: Route: routes/tasks.ts
|
||||
W->>A: authenticateUser()
|
||||
Note over A: Check JWT token
|
||||
A-->>W: {user_id, email}
|
||||
W->>V: validateSchema(createTaskSchema)
|
||||
Note over V: Validate request body
|
||||
V-->>W: {validated data}
|
||||
W->>D: INSERT INTO tasks<br/>(user_id, title, description)
|
||||
D-->>W: {id, title, description, created_at}
|
||||
W->>C: 201 Created<br/>{task object}
|
||||
```
|
||||
|
||||
### Critical Dependencies
|
||||
|
||||
**Internal** (codebase files):
|
||||
- `src/middleware/auth.ts` - JWT authentication (must run before routes)
|
||||
- `src/lib/schemas.ts` - Validation schemas (import and extend)
|
||||
- `src/index.ts` - Main Hono app (register routes here)
|
||||
|
||||
**External** (npm packages):
|
||||
- `zod` (^3.23.8) - Schema validation
|
||||
- `hono` (^4.6.14) - Web framework
|
||||
- `@clerk/backend` (^1.18.5) - JWT verification
|
||||
|
||||
**Configuration** (environment):
|
||||
- `CLERK_SECRET_KEY` - Set in wrangler.jsonc secrets
|
||||
- No additional env vars needed
|
||||
|
||||
**Cloudflare Bindings**:
|
||||
- `DB` (D1 database) - Must be configured in wrangler.jsonc:
|
||||
```jsonc
|
||||
{
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "task-manager-db",
|
||||
"database_id": "your-database-id"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Gotchas & Known Issues
|
||||
|
||||
**🔒 Security: Ownership Verification Required**:
|
||||
- PATCH and DELETE **must** verify `task.user_id === user.id` before mutations
|
||||
- Failing to check allows users to modify/delete others' tasks (critical security vulnerability)
|
||||
- Pattern:
|
||||
```typescript
|
||||
// Fetch task first
|
||||
const task = await env.DB.prepare('SELECT * FROM tasks WHERE id = ?').bind(id).first();
|
||||
if (!task || task.user_id !== user.id) {
|
||||
return c.json({ error: 'Not found or unauthorized' }, 404);
|
||||
}
|
||||
// Now safe to update/delete
|
||||
```
|
||||
|
||||
**⚡ Performance: Pagination Required for GET**:
|
||||
- Without pagination, endpoint returns ALL tasks (performance issue for users with 1000+ tasks)
|
||||
- Max: 50 tasks per page (reasonable default)
|
||||
- Use query params: `?page=1&limit=50`
|
||||
- Pattern:
|
||||
```typescript
|
||||
const page = parseInt(c.req.query('page') || '1');
|
||||
const limit = Math.min(parseInt(c.req.query('limit') || '50'), 100); // Cap at 100
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const tasks = await env.DB.prepare(
|
||||
'SELECT * FROM tasks WHERE user_id = ? AND deleted_at IS NULL ORDER BY created_at DESC LIMIT ? OFFSET ?'
|
||||
).bind(user.id, limit, offset).all();
|
||||
```
|
||||
|
||||
**🗑️ Data Integrity: Soft Delete Pattern**:
|
||||
- Don't use `DELETE FROM tasks` (hard delete loses data permanently)
|
||||
- Use `UPDATE tasks SET deleted_at = ? WHERE id = ?` (soft delete)
|
||||
- Reasons:
|
||||
- Audit trail (know when/why data was deleted)
|
||||
- Undo capability (restore deleted tasks)
|
||||
- Data recovery (prevent accidental data loss)
|
||||
- Filter in queries: `WHERE deleted_at IS NULL`
|
||||
|
||||
**🕐 Timezone Handling**:
|
||||
- Store all timestamps as UTC unix timestamps (INTEGER)
|
||||
- Convert to user's timezone in frontend only
|
||||
- Patterns:
|
||||
- Storage: `Math.floor(Date.now() / 1000)` (unix timestamp in seconds)
|
||||
- Display: `new Date(timestamp * 1000).toLocaleString()`
|
||||
- SQLite date functions won't work with unix timestamps - use JavaScript
|
||||
|
||||
**🔍 Case-Sensitive Search**:
|
||||
- SQLite's LIKE is case-insensitive by default
|
||||
- For case-sensitive search, use: `WHERE title LIKE ? COLLATE NOCASE`
|
||||
- For full-text search, consider adding FTS5 table (separate phase)
|
||||
|
||||
### Tasks
|
||||
|
||||
- [ ] Add task schemas to `src/lib/schemas.ts`
|
||||
- [ ] `taskSchema` (base schema)
|
||||
- [ ] `createTaskSchema` (omit id, user_id, timestamps)
|
||||
- [ ] `updateTaskSchema` (partial with only title, description, completed)
|
||||
|
||||
- [ ] Create `src/routes/tasks.ts` file
|
||||
- [ ] Set up Hono router with auth middleware
|
||||
- [ ] Implement GET /api/tasks (with pagination)
|
||||
- [ ] Implement POST /api/tasks (with validation)
|
||||
- [ ] Implement PATCH /api/tasks/:id (with ownership check)
|
||||
- [ ] Implement DELETE /api/tasks/:id (soft delete with ownership check)
|
||||
|
||||
- [ ] Register task routes in `src/index.ts`
|
||||
- [ ] Import task routes
|
||||
- [ ] Mount at `/api/tasks`
|
||||
|
||||
- [ ] Error handling
|
||||
- [ ] 400 for validation errors (Zod messages)
|
||||
- [ ] 401 for missing/invalid JWT
|
||||
- [ ] 404 for non-existent task IDs
|
||||
- [ ] 403 for ownership violations
|
||||
|
||||
- [ ] Testing (all endpoints with curl or Postman)
|
||||
- [ ] Test with valid JWT
|
||||
- [ ] Test with invalid/missing JWT
|
||||
- [ ] Test with invalid data
|
||||
- [ ] Test pagination parameters
|
||||
- [ ] Test ownership checks
|
||||
|
||||
### Verification Criteria
|
||||
|
||||
**Authentication**:
|
||||
- [ ] Requests without JWT return 401 Unauthorized
|
||||
- [ ] Requests with invalid JWT return 401 Unauthorized
|
||||
- [ ] Requests with valid JWT proceed to handler
|
||||
|
||||
**GET /api/tasks** (List):
|
||||
- [ ] Returns 200 with array of user's tasks (only their tasks)
|
||||
- [ ] Returns empty array `[]` for users with no tasks
|
||||
- [ ] Pagination works: `?page=2` returns correct offset
|
||||
- [ ] Limit works: `?limit=10` returns max 10 tasks
|
||||
- [ ] Deleted tasks are excluded (WHERE deleted_at IS NULL)
|
||||
- [ ] Tasks are sorted by created_at DESC (newest first)
|
||||
|
||||
**POST /api/tasks** (Create):
|
||||
- [ ] Valid data returns 201 Created with task object
|
||||
- [ ] Task has auto-generated `id` (integer)
|
||||
- [ ] Task has `user_id` matching authenticated user
|
||||
- [ ] Task has `created_at` timestamp
|
||||
- [ ] Invalid data returns 400 with Zod error messages
|
||||
- [ ] Missing required fields (title) returns 400
|
||||
|
||||
**PATCH /api/tasks/:id** (Update):
|
||||
- [ ] Valid update returns 200 with updated task
|
||||
- [ ] Can update `title`, `description`, `completed` fields
|
||||
- [ ] Cannot update `id`, `user_id`, `created_at` (immutable)
|
||||
- [ ] Invalid task ID returns 404
|
||||
- [ ] Another user's task returns 404 (not 403 to avoid leaking existence)
|
||||
- [ ] Deleted task returns 404
|
||||
|
||||
**DELETE /api/tasks/:id** (Soft Delete):
|
||||
- [ ] Valid delete returns 204 No Content
|
||||
- [ ] Task still exists in database (SELECT * FROM tasks WHERE id = ?)
|
||||
- [ ] Task has `deleted_at` timestamp set
|
||||
- [ ] Task no longer appears in GET /api/tasks
|
||||
- [ ] Deleting same task twice returns 404 (already deleted)
|
||||
- [ ] Another user's task returns 404
|
||||
|
||||
**Performance**:
|
||||
- [ ] GET /api/tasks with 100+ tasks completes in <200ms
|
||||
- [ ] Pagination limits result set (never returns unbounded data)
|
||||
|
||||
### Exit Criteria
|
||||
|
||||
All CRUD operations work correctly with:
|
||||
- ✅ Proper HTTP status codes (200, 201, 204, 400, 401, 404)
|
||||
- ✅ Request validation via Zod schemas
|
||||
- ✅ Authentication enforcement (JWT required)
|
||||
- ✅ Ownership checks (users can only access their tasks)
|
||||
- ✅ Pagination (prevents performance issues)
|
||||
- ✅ Soft delete (preserves data and audit trail)
|
||||
- ✅ Error messages are helpful and consistent
|
||||
```
|
||||
|
||||
**Benefits of enhanced phase**:
|
||||
- ✅ Claude knows exactly where to start (routes/tasks.ts)
|
||||
- ✅ Clear dependency graph (what imports what)
|
||||
- ✅ Visual data flow (Mermaid diagram shows request/response)
|
||||
- ✅ Security considerations upfront (ownership checks)
|
||||
- ✅ Performance patterns documented (pagination)
|
||||
- ✅ Specific verification criteria (testable, measurable)
|
||||
- ✅ Token savings: ~60-70% reduction (fewer grep/glob operations)
|
||||
|
||||
---
|
||||
|
||||
## More Mermaid Diagram Examples
|
||||
|
||||
### Example 1: UI Component Interaction (Flowchart)
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Start([User clicks 'Add Task' button]) --> OpenDialog[TaskDialog opens]
|
||||
OpenDialog --> FillForm[User fills form]
|
||||
FillForm --> ValidateClient{Client-side<br/>validation}
|
||||
ValidateClient -->|Invalid| ShowError[Show validation errors]
|
||||
ShowError --> FillForm
|
||||
ValidateClient -->|Valid| SubmitAPI[POST /api/tasks]
|
||||
SubmitAPI --> ValidateServer{Server-side<br/>validation}
|
||||
ValidateServer -->|400 Error| ShowServerError[Show server errors]
|
||||
ShowServerError --> FillForm
|
||||
ValidateServer -->|201 Success| RefetchTasks[TanStack Query refetch]
|
||||
RefetchTasks --> UpdateUI[UI updates with new task]
|
||||
UpdateUI --> CloseDialog[Dialog closes]
|
||||
CloseDialog --> End([Done])
|
||||
```
|
||||
|
||||
### Example 2: Authentication Flow (Sequence Diagram)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as User (Browser)
|
||||
participant F as Frontend (React)
|
||||
participant C as Clerk
|
||||
participant W as Worker
|
||||
participant D as D1 Database
|
||||
|
||||
U->>F: Enter email/password
|
||||
F->>C: signIn(email, password)
|
||||
C-->>F: JWT token + user data
|
||||
F->>F: Store token in localStorage
|
||||
|
||||
Note over F: User navigates to tasks page
|
||||
|
||||
F->>W: GET /api/tasks<br/>Authorization: Bearer {token}
|
||||
W->>W: Extract token from header
|
||||
W->>C: Verify JWT signature
|
||||
C-->>W: Valid: {user_id, email}
|
||||
W->>D: SELECT * FROM tasks<br/>WHERE user_id = ?
|
||||
D-->>W: Array of tasks
|
||||
W-->>F: 200 OK + tasks array
|
||||
F->>U: Render task list
|
||||
```
|
||||
|
||||
### Example 3: Error Handling Paths (Flowchart)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Request[Incoming Request] --> Auth{Auth<br/>Middleware}
|
||||
Auth -->|No token| E401[401 Unauthorized]
|
||||
Auth -->|Invalid token| E401
|
||||
Auth -->|Valid token| Validate{Zod<br/>Validation}
|
||||
Validate -->|Invalid data| E400[400 Bad Request]
|
||||
Validate -->|Valid data| CheckOwnership{Ownership<br/>Check}
|
||||
CheckOwnership -->|Not owner| E404[404 Not Found]
|
||||
CheckOwnership -->|Owner| Database[(Database<br/>Operation)]
|
||||
Database -->|Success| S200[200 OK]
|
||||
Database -->|Error| E500[500 Internal Error]
|
||||
```
|
||||
|
||||
### Example 4: Multi-Service Architecture (Graph)
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Browser[Browser Client]
|
||||
Worker[Cloudflare Worker]
|
||||
D1[(D1 Database)]
|
||||
R2[(R2 Storage)]
|
||||
KV[(KV Cache)]
|
||||
Clerk[Clerk Auth]
|
||||
AI[Workers AI]
|
||||
|
||||
Browser -->|HTTPS| Worker
|
||||
Worker -->|SQL| D1
|
||||
Worker -->|Files| R2
|
||||
Worker -->|Config| KV
|
||||
Worker -->|Verify JWT| Clerk
|
||||
Worker -->|Inference| AI
|
||||
|
||||
style Browser fill:#e1f5ff
|
||||
style Worker fill:#ffd6a5
|
||||
style D1 fill:#caffbf
|
||||
style R2 fill:#caffbf
|
||||
style KV fill:#caffbf
|
||||
style Clerk fill:#ffc6ff
|
||||
style AI fill:#ffadad
|
||||
```
|
||||
|
||||
### Example 5: Database Relationships (ER Diagram)
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USERS ||--o{ TASKS : creates
|
||||
TASKS ||--o{ TASK_TAGS : has
|
||||
TAGS ||--o{ TASK_TAGS : applied_to
|
||||
|
||||
USERS {
|
||||
int id PK
|
||||
text email UK
|
||||
int created_at
|
||||
}
|
||||
|
||||
TASKS {
|
||||
int id PK
|
||||
int user_id FK
|
||||
text title
|
||||
text description
|
||||
bool completed
|
||||
int deleted_at
|
||||
int created_at
|
||||
}
|
||||
|
||||
TAGS {
|
||||
int id PK
|
||||
text name UK
|
||||
text color
|
||||
}
|
||||
|
||||
TASK_TAGS {
|
||||
int task_id FK
|
||||
int tag_id FK
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## When to Use Each Diagram Type
|
||||
|
||||
| Diagram Type | Best For | Example Use Cases |
|
||||
|--------------|----------|-------------------|
|
||||
| **Sequence** | Request/response flows, API calls | Authentication, webhooks, multi-step processes |
|
||||
| **Flowchart** | Decision logic, user flows | Form validation, error handling, component state |
|
||||
| **Graph/Architecture** | System components, service boundaries | Multi-service apps, microservices, infrastructure |
|
||||
| **ER Diagram** | Database relationships | Schema design, data modeling |
|
||||
|
||||
---
|
||||
|
||||
## Token Efficiency Comparison
|
||||
|
||||
### Scenario: "Implement task CRUD endpoints"
|
||||
|
||||
**Without file-level detail**:
|
||||
```
|
||||
1. Claude greps for existing routes: ~2k tokens
|
||||
2. Claude globs for schema patterns: ~1k tokens
|
||||
3. Claude reads 3-4 files to understand structure: ~6k tokens
|
||||
4. Claude writes code in wrong location: ~2k tokens
|
||||
5. User corrects: "Use routes/tasks.ts": ~500 tokens
|
||||
6. Claude re-reads and rewrites: ~4k tokens
|
||||
Total: ~15.5k tokens, 2 corrections needed
|
||||
```
|
||||
|
||||
**With file-level detail**:
|
||||
```
|
||||
1. Claude reads IMPLEMENTATION_PHASES.md file map: ~1k tokens
|
||||
2. Claude writes code in correct location first try: ~2k tokens
|
||||
3. Claude references gotchas to implement security checks: ~500 tokens
|
||||
Total: ~3.5k tokens, 0 corrections needed
|
||||
```
|
||||
|
||||
**Savings**: 12k tokens (~77% reduction) + 2 fewer correction cycles
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Enhanced phases with file-level detail provide:
|
||||
|
||||
1. **Navigation efficiency** - Claude knows exactly where to look
|
||||
2. **Security by default** - Gotchas prevent common vulnerabilities
|
||||
3. **Performance patterns** - Best practices documented upfront
|
||||
4. **Visual clarity** - Mermaid diagrams show complex flows
|
||||
5. **Token savings** - 60-70% reduction vs grep/glob exploration
|
||||
6. **First-try accuracy** - Correct file placement, fewer rewrites
|
||||
|
||||
The small upfront investment in detailed planning (~5 extra minutes) saves significant implementation time and prevents errors.
|
||||
596
references/example-outputs/ai-web-app.md
Normal file
596
references/example-outputs/ai-web-app.md
Normal file
@@ -0,0 +1,596 @@
|
||||
# Example: AI-Powered Research Assistant
|
||||
|
||||
This example shows planning docs for an AI-powered research assistant with agents and tools.
|
||||
|
||||
**User Request**: "I want to build an AI research assistant that can search the web, summarize articles, and help me organize research notes. Users should be able to chat with the AI and have it perform actions on their behalf."
|
||||
|
||||
---
|
||||
|
||||
## IMPLEMENTATION_PHASES.md (Excerpt)
|
||||
|
||||
# Implementation Phases: AI Research Assistant
|
||||
|
||||
**Project Type**: AI-Powered Web App with Agents
|
||||
**Stack**: Cloudflare Workers + Vite + React + D1 + Clerk + OpenAI
|
||||
**Estimated Total**: 30 hours (~30 minutes human time)
|
||||
**Created**: 2025-10-25
|
||||
|
||||
---
|
||||
|
||||
## Phase 1-3: [Standard setup phases - Infrastructure, Database, Auth]
|
||||
|
||||
[Similar to auth-web-app.md example]
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: OpenAI Integration
|
||||
**Type**: Integration
|
||||
**Estimated**: 3 hours
|
||||
**Files**: `src/lib/openai-client.ts`, `src/routes/ai.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Create OpenAI account and get API key
|
||||
- [ ] Install `openai` package
|
||||
- [ ] Create AI client wrapper
|
||||
- [ ] Test basic chat completion
|
||||
- [ ] Implement streaming responses
|
||||
- [ ] Add error handling and retries
|
||||
- [ ] Test token usage tracking
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Can send message to OpenAI
|
||||
- [ ] Receives streaming response
|
||||
- [ ] Streams correctly to frontend
|
||||
- [ ] Errors handled gracefully (rate limits, API down)
|
||||
- [ ] Token usage logged
|
||||
|
||||
### Exit Criteria
|
||||
OpenAI integration working with streaming responses.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: AI Tools (Functions)
|
||||
**Type**: Integration
|
||||
**Estimated**: 5 hours
|
||||
**Files**: `src/lib/ai-tools.ts`, `src/lib/web-search.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Define tool: `search_web` (using Brave Search API or similar)
|
||||
- [ ] Define tool: `save_note` (save to user's notes in D1)
|
||||
- [ ] Define tool: `search_notes` (search user's existing notes)
|
||||
- [ ] Define tool: `summarize_url` (fetch and summarize webpage)
|
||||
- [ ] Implement tool execution logic
|
||||
- [ ] Add tool result formatting
|
||||
- [ ] Test each tool independently
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] `search_web` returns relevant results
|
||||
- [ ] `save_note` creates note in database
|
||||
- [ ] `search_notes` finds user's notes
|
||||
- [ ] `summarize_url` fetches and summarizes content
|
||||
- [ ] Tools work when called by AI
|
||||
- [ ] Tool errors handled (404, timeout, etc)
|
||||
|
||||
### Exit Criteria
|
||||
All AI tools implemented and tested.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Research Agent
|
||||
**Type**: Integration
|
||||
**Estimated**: 4 hours
|
||||
**Files**: `src/agents/research-agent.ts`, `src/routes/agents.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Design research agent system prompt
|
||||
- [ ] Implement agent with tool calling
|
||||
- [ ] Add conversation state (Durable Object or in-memory)
|
||||
- [ ] Implement streaming tool calls to frontend
|
||||
- [ ] Add agent endpoint: POST /api/agents/research
|
||||
- [ ] Test multi-step research workflow
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Agent responds to questions
|
||||
- [ ] Agent calls tools when needed
|
||||
- [ ] Tool results incorporated into response
|
||||
- [ ] Multi-turn conversation works
|
||||
- [ ] Streaming updates show tool usage to user
|
||||
|
||||
### Exit Criteria
|
||||
Research agent working with tool integration.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Notes Management
|
||||
**Type**: API + UI
|
||||
**Estimated**: 6 hours
|
||||
**Files**: `src/routes/notes.ts`, `src/components/NotesList.tsx`, etc.
|
||||
|
||||
### Tasks
|
||||
- [ ] Create notes CRUD API
|
||||
- [ ] Build notes list UI
|
||||
- [ ] Build note viewer/editor
|
||||
- [ ] Add markdown rendering
|
||||
- [ ] Add note search functionality
|
||||
- [ ] Integrate AI-saved notes with manual notes
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Can view all notes
|
||||
- [ ] Can create/edit/delete notes manually
|
||||
- [ ] AI-saved notes appear in list
|
||||
- [ ] Markdown renders correctly
|
||||
- [ ] Search finds notes
|
||||
|
||||
### Exit Criteria
|
||||
Complete notes management system.
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: Chat Interface
|
||||
**Type**: UI
|
||||
**Estimated**: 8 hours
|
||||
**Files**: `src/components/ChatInterface.tsx`, `src/components/Message.tsx`, etc.
|
||||
|
||||
### Tasks
|
||||
- [ ] Install Vercel AI SDK (`@ai-sdk/react`)
|
||||
- [ ] Build chat UI with message list
|
||||
- [ ] Implement message input with auto-resize
|
||||
- [ ] Add streaming message display
|
||||
- [ ] Show tool call indicators (loading states)
|
||||
- [ ] Display tool results inline
|
||||
- [ ] Add conversation history persistence
|
||||
- [ ] Style with shadcn/ui components
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Messages stream correctly
|
||||
- [ ] Tool calls show loading indicators
|
||||
- [ ] Tool results displayed clearly
|
||||
- [ ] Can continue conversation
|
||||
- [ ] Conversation history persists
|
||||
- [ ] UI handles errors gracefully
|
||||
|
||||
### Exit Criteria
|
||||
Polished chat interface with full AI interaction.
|
||||
|
||||
---
|
||||
|
||||
## AGENTS_CONFIG.md (Excerpt)
|
||||
|
||||
# AI Agents Configuration: AI Research Assistant
|
||||
|
||||
**AI Provider**: OpenAI
|
||||
**Model**: gpt-5
|
||||
**Framework**: Vercel AI SDK
|
||||
|
||||
---
|
||||
|
||||
## Agents
|
||||
|
||||
### Research Agent
|
||||
|
||||
**Purpose**: Help users research topics by searching the web, summarizing content, and organizing notes.
|
||||
|
||||
**Model**: gpt-5 (for complex reasoning, tool use)
|
||||
|
||||
**System Prompt**:
|
||||
```
|
||||
You are a research assistant helping users gather and organize information.
|
||||
|
||||
Your capabilities:
|
||||
- Search the web for information on any topic
|
||||
- Summarize articles and web pages
|
||||
- Save important findings as notes
|
||||
- Search through saved notes
|
||||
- Provide citations and sources
|
||||
|
||||
Your workflow:
|
||||
1. When asked about a topic, search the web for recent information
|
||||
2. Summarize key findings concisely
|
||||
3. Offer to save important information as notes
|
||||
4. Always cite sources with URLs
|
||||
|
||||
Guidelines:
|
||||
- Be thorough but concise
|
||||
- Verify information from multiple sources when possible
|
||||
- Organize information logically
|
||||
- Ask clarifying questions if user request is vague
|
||||
- Always provide sources for claims
|
||||
|
||||
Response format:
|
||||
- Use markdown for structure
|
||||
- Use bullet points for lists
|
||||
- Bold important findings
|
||||
- Include clickable links to sources
|
||||
```
|
||||
|
||||
**Available Tools**:
|
||||
- `search_web` - Search the web using Brave Search API
|
||||
- `summarize_url` - Fetch and summarize a specific webpage
|
||||
- `save_note` - Save information as a note in user's database
|
||||
- `search_notes` - Search user's existing notes
|
||||
|
||||
**Example Conversation**:
|
||||
```
|
||||
User: "What are the latest developments in quantum computing?"
|
||||
|
||||
Agent: I'll search for recent information on quantum computing.
|
||||
|
||||
[Calls: search_web({ query: "latest quantum computing developments 2025" })]
|
||||
|
||||
Based on recent sources, here are the latest developments:
|
||||
|
||||
1. **IBM's 1000-qubit processor** - Announced in Q3 2025
|
||||
- Source: [IBM Research](https://...)
|
||||
|
||||
2. **Google's error correction breakthrough** - Published in Nature
|
||||
- Reduced error rates by 50%
|
||||
- Source: [Nature article](https://...)
|
||||
|
||||
3. **Commercial applications emerging**
|
||||
- Drug discovery (Pfizer partnership)
|
||||
- Financial modeling (Goldman Sachs)
|
||||
|
||||
Would you like me to save any of these findings as notes?
|
||||
|
||||
User: "Yes, save the IBM development"
|
||||
|
||||
Agent: [Calls: save_note({ title: "IBM 1000-qubit processor", content: "...", source: "..." })]
|
||||
|
||||
✓ Saved note: "IBM 1000-qubit processor"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
|
||||
### Tool: `search_web`
|
||||
|
||||
**Purpose**: Search the web for information
|
||||
|
||||
**Parameters**:
|
||||
```typescript
|
||||
{
|
||||
query: string, // Search query
|
||||
limit?: number // Max results (default 5)
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
export async function search_web(
|
||||
{ query, limit = 5 }: SearchWebParams,
|
||||
context: Context
|
||||
) {
|
||||
const response = await fetch('https://api.search.brave.com/res/v1/web/search', {
|
||||
headers: {
|
||||
'X-Subscription-Token': context.env.BRAVE_API_KEY
|
||||
},
|
||||
params: { q: query, count: limit }
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
results: data.web.results.map(r => ({
|
||||
title: r.title,
|
||||
url: r.url,
|
||||
description: r.description
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```typescript
|
||||
// Agent calls
|
||||
const results = await search_web({
|
||||
query: "quantum computing 2025",
|
||||
limit: 5
|
||||
})
|
||||
|
||||
// Returns
|
||||
{
|
||||
success: true,
|
||||
results: [
|
||||
{
|
||||
title: "IBM announces 1000-qubit processor",
|
||||
url: "https://...",
|
||||
description: "IBM has unveiled..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tool: `summarize_url`
|
||||
|
||||
**Purpose**: Fetch and summarize a webpage
|
||||
|
||||
**Parameters**:
|
||||
```typescript
|
||||
{
|
||||
url: string // URL to fetch and summarize
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
export async function summarize_url(
|
||||
{ url }: SummarizeUrlParams,
|
||||
context: Context
|
||||
) {
|
||||
// Fetch webpage
|
||||
const response = await fetch(url)
|
||||
const html = await response.text()
|
||||
|
||||
// Extract main content (simplified - use Readability or similar in production)
|
||||
const text = extractMainContent(html)
|
||||
|
||||
// Summarize with OpenAI
|
||||
const summary = await context.env.AI.run('@cf/meta/llama-3-8b-instruct', {
|
||||
prompt: `Summarize this article in 3-5 bullet points:\n\n${text}`
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
summary: summary.response,
|
||||
url
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tool: `save_note`
|
||||
|
||||
**Purpose**: Save information as a note
|
||||
|
||||
**Parameters**:
|
||||
```typescript
|
||||
{
|
||||
title: string, // Note title
|
||||
content: string, // Note content (markdown)
|
||||
source?: string, // Optional source URL
|
||||
tags?: string[] // Optional tags
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
export async function save_note(
|
||||
{ title, content, source, tags }: SaveNoteParams,
|
||||
context: Context
|
||||
) {
|
||||
const userId = context.get('userId')
|
||||
|
||||
const result = await context.env.DB.prepare(`
|
||||
INSERT INTO notes (user_id, title, content, source, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`).bind(userId, title, content, source, Date.now(), Date.now()).run()
|
||||
|
||||
// Add tags if provided
|
||||
if (tags?.length) {
|
||||
// ... insert tag associations
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
noteId: result.meta.last_row_id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tool: `search_notes`
|
||||
|
||||
**Purpose**: Search user's existing notes
|
||||
|
||||
**Parameters**:
|
||||
```typescript
|
||||
{
|
||||
query: string, // Search query
|
||||
limit?: number // Max results (default 5)
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
export async function search_notes(
|
||||
{ query, limit = 5 }: SearchNotesParams,
|
||||
context: Context
|
||||
) {
|
||||
const userId = context.get('userId')
|
||||
|
||||
// Simple full-text search (use Vectorize for semantic search in production)
|
||||
const results = await context.env.DB.prepare(`
|
||||
SELECT id, title, content, source, created_at
|
||||
FROM notes
|
||||
WHERE user_id = ? AND (title LIKE ? OR content LIKE ?)
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?
|
||||
`).bind(userId, `%${query}%`, `%${query}%`, limit).all()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
notes: results.results
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Streaming Responses
|
||||
|
||||
**Server** (POST /api/agents/research):
|
||||
```typescript
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
import { streamText } from 'ai'
|
||||
|
||||
app.post('/api/agents/research', async (c) => {
|
||||
const { message, conversationId } = await c.req.json()
|
||||
const userId = c.get('userId')
|
||||
|
||||
// Get conversation history (from Durable Object or DB)
|
||||
const history = await getConversationHistory(conversationId)
|
||||
|
||||
const result = await streamText({
|
||||
model: openai('gpt-5'),
|
||||
messages: [
|
||||
{ role: 'system', content: RESEARCH_AGENT_PROMPT },
|
||||
...history,
|
||||
{ role: 'user', content: message }
|
||||
],
|
||||
tools: {
|
||||
search_web,
|
||||
summarize_url,
|
||||
save_note,
|
||||
search_notes
|
||||
},
|
||||
onFinish: async ({ text }) => {
|
||||
// Save conversation
|
||||
await saveMessage(conversationId, { role: 'assistant', content: text })
|
||||
}
|
||||
})
|
||||
|
||||
return result.toAIStreamResponse()
|
||||
})
|
||||
```
|
||||
|
||||
**Client** (React):
|
||||
```typescript
|
||||
import { useChat } from '@ai-sdk/react'
|
||||
|
||||
export function ChatInterface() {
|
||||
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
|
||||
api: '/api/agents/research'
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen">
|
||||
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
||||
{messages.map(m => (
|
||||
<Message key={m.id} message={m} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="border-t p-4">
|
||||
<textarea
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Ask me anything..."
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
<button type="submit" disabled={isLoading}>
|
||||
Send
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Tool Call Display**:
|
||||
```typescript
|
||||
function Message({ message }) {
|
||||
return (
|
||||
<div className={cn('flex', message.role === 'user' ? 'justify-end' : 'justify-start')}>
|
||||
<div className="max-w-[80%] rounded-lg p-4 bg-muted">
|
||||
<ReactMarkdown>{message.content}</ReactMarkdown>
|
||||
|
||||
{message.toolInvocations?.map((tool, i) => (
|
||||
<div key={i} className="mt-2 text-sm border-l-2 pl-2">
|
||||
<span className="font-semibold">🔧 {tool.toolName}</span>
|
||||
{tool.state === 'result' && (
|
||||
<div className="text-muted-foreground">
|
||||
✓ {tool.result.success ? 'Success' : 'Failed'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DATABASE_SCHEMA.md (Additions)
|
||||
|
||||
### `notes`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | |
|
||||
| `user_id` | INTEGER | FOREIGN KEY | References users(id) |
|
||||
| `title` | TEXT | NOT NULL | Note title |
|
||||
| `content` | TEXT | NOT NULL | Note content (markdown) |
|
||||
| `source` | TEXT | NULL | Source URL if from web |
|
||||
| `created_at` | INTEGER | NOT NULL | |
|
||||
| `updated_at` | INTEGER | NOT NULL | |
|
||||
|
||||
### `conversations`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | |
|
||||
| `user_id` | INTEGER | FOREIGN KEY | References users(id) |
|
||||
| `title` | TEXT | NULL | Auto-generated from first message |
|
||||
| `created_at` | INTEGER | NOT NULL | |
|
||||
| `updated_at` | INTEGER | NOT NULL | |
|
||||
|
||||
### `messages`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | |
|
||||
| `conversation_id` | INTEGER | FOREIGN KEY | References conversations(id) |
|
||||
| `role` | TEXT | NOT NULL | 'user' or 'assistant' |
|
||||
| `content` | TEXT | NOT NULL | Message content |
|
||||
| `tool_calls` | TEXT | NULL | JSON array of tool calls |
|
||||
| `created_at` | INTEGER | NOT NULL | |
|
||||
|
||||
---
|
||||
|
||||
## INTEGRATION.md (Additions)
|
||||
|
||||
### OpenAI
|
||||
|
||||
**Purpose**: AI-powered chat and tool use
|
||||
|
||||
**Environment Variables**:
|
||||
```env
|
||||
OPENAI_API_KEY=sk-...
|
||||
```
|
||||
|
||||
**API Client**:
|
||||
```typescript
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
|
||||
const model = openai('gpt-5')
|
||||
```
|
||||
|
||||
**Rate Limits**: 10,000 requests/minute (Tier 5)
|
||||
|
||||
**Token Management**:
|
||||
- Use `gpt-5-mini` for simple tasks (cheaper)
|
||||
- Use `gpt-5` for complex research (better reasoning)
|
||||
- Limit conversation history to last 20 messages
|
||||
- Track token usage per user (optional billing)
|
||||
|
||||
---
|
||||
|
||||
### Brave Search API
|
||||
|
||||
**Purpose**: Web search for research agent
|
||||
|
||||
**Environment Variables**:
|
||||
```env
|
||||
BRAVE_API_KEY=...
|
||||
```
|
||||
|
||||
**Rate Limits**: 15,000 queries/month (free tier)
|
||||
|
||||
---
|
||||
|
||||
**Note**: This example demonstrates a complete AI-powered application with agents, tools, and streaming responses. Adjust complexity based on actual requirements.
|
||||
515
references/example-outputs/auth-web-app.md
Normal file
515
references/example-outputs/auth-web-app.md
Normal file
@@ -0,0 +1,515 @@
|
||||
# Example: Personal Task Manager with Authentication
|
||||
|
||||
This example shows planning docs for a task manager with user authentication using Clerk.
|
||||
|
||||
**User Request**: "I want to build a task manager where users can sign up, log in, and manage their own tasks privately. Users should be able to organize tasks with tags and due dates."
|
||||
|
||||
---
|
||||
|
||||
## IMPLEMENTATION_PHASES.md (Excerpt)
|
||||
|
||||
# Implementation Phases: Personal Task Manager
|
||||
|
||||
**Project Type**: Authenticated Web App (Multi-user CRUD)
|
||||
**Stack**: Cloudflare Workers + Vite + React + Tailwind v4 + shadcn/ui + D1 + Clerk
|
||||
**Estimated Total**: 20 hours (~20 minutes human time)
|
||||
**Created**: 2025-10-25
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Project Setup
|
||||
**Type**: Infrastructure
|
||||
**Estimated**: 2-3 hours
|
||||
**Files**: `package.json`, `wrangler.jsonc`, `vite.config.ts`, `src/index.ts`
|
||||
|
||||
[Same structure as simple example]
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Database Schema
|
||||
**Type**: Database
|
||||
**Estimated**: 3-4 hours
|
||||
**Files**: `migrations/0001_initial.sql`, `src/lib/db-types.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Create D1 database
|
||||
- [ ] Design schema for users, tasks, tags, task_tags tables
|
||||
- [ ] Write migration SQL
|
||||
- [ ] Create TypeScript types
|
||||
- [ ] Apply migration locally
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] All tables created successfully
|
||||
- [ ] Foreign keys work (task references user)
|
||||
- [ ] Unique constraints work (user email, tag name per user)
|
||||
- [ ] Can query with joins (tasks with their tags)
|
||||
|
||||
### Exit Criteria
|
||||
Complete database schema with relationships working.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Clerk Authentication Setup
|
||||
**Type**: Integration
|
||||
**Estimated**: 3 hours
|
||||
**Files**: `src/main.tsx`, `src/middleware/auth.ts`, `src/lib/clerk-types.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Create Clerk account and application
|
||||
- [ ] Install `@clerk/clerk-react` and `@clerk/backend`
|
||||
- [ ] Configure Clerk in frontend (ClerkProvider)
|
||||
- [ ] Create custom JWT template in Clerk dashboard
|
||||
- [ ] Implement auth middleware for Worker
|
||||
- [ ] Test JWT verification
|
||||
- [ ] Create protected route wrapper component
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Can sign up new user (Clerk modal)
|
||||
- [ ] Can sign in existing user
|
||||
- [ ] JWT is included in API requests
|
||||
- [ ] Worker middleware verifies JWT correctly
|
||||
- [ ] Invalid JWT returns 401
|
||||
- [ ] Protected routes redirect if not authenticated
|
||||
|
||||
### Exit Criteria
|
||||
Authentication flow working end-to-end. Users can sign up, log in, and access protected routes.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Sync (Webhook)
|
||||
**Type**: Integration
|
||||
**Estimated**: 2 hours
|
||||
**Files**: `src/routes/webhooks.ts`, `src/lib/webhook-verify.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Install `svix` package
|
||||
- [ ] Create webhook endpoint `/api/webhooks/clerk`
|
||||
- [ ] Implement signature verification
|
||||
- [ ] Handle `user.created` event (insert into database)
|
||||
- [ ] Handle `user.updated` event
|
||||
- [ ] Handle `user.deleted` event
|
||||
- [ ] Configure webhook in Clerk dashboard
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] New user signup triggers webhook
|
||||
- [ ] User record created in D1 database
|
||||
- [ ] Invalid webhook signature rejected
|
||||
- [ ] User updates sync to database
|
||||
- [ ] User deletions remove tasks (cascade)
|
||||
|
||||
### Exit Criteria
|
||||
User data synced between Clerk and D1 database.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Tasks API
|
||||
**Type**: API
|
||||
**Estimated**: 5 hours
|
||||
**Files**: `src/routes/tasks.ts`, `src/lib/schemas.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Define Zod schemas for task validation
|
||||
- [ ] GET /api/tasks (user's tasks only)
|
||||
- [ ] POST /api/tasks (create for current user)
|
||||
- [ ] PATCH /api/tasks/:id (update if user owns)
|
||||
- [ ] DELETE /api/tasks/:id (delete if user owns)
|
||||
- [ ] Add authorization checks (verify ownership)
|
||||
- [ ] Filter by completion, tag, due date
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] GET /api/tasks returns only current user's tasks
|
||||
- [ ] Cannot access other users' tasks
|
||||
- [ ] Cannot update/delete other users' tasks (403)
|
||||
- [ ] Filters work (completed, tag, due date)
|
||||
- [ ] All CRUD operations tested
|
||||
|
||||
### Exit Criteria
|
||||
Tasks API complete with proper authorization.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Tags API
|
||||
**Type**: API
|
||||
**Estimated**: 2 hours
|
||||
**Files**: `src/routes/tags.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] GET /api/tags (user's tags)
|
||||
- [ ] POST /api/tags (create tag)
|
||||
- [ ] DELETE /api/tags/:id (delete tag)
|
||||
- [ ] POST /api/tasks/:id/tags (add tag to task)
|
||||
- [ ] DELETE /api/tasks/:id/tags/:tagId (remove tag from task)
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Can create tags
|
||||
- [ ] Can attach tags to tasks
|
||||
- [ ] Can filter tasks by tag
|
||||
- [ ] Deleting tag doesn't delete tasks
|
||||
|
||||
### Exit Criteria
|
||||
Tag management working with task associations.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Dashboard UI
|
||||
**Type**: UI
|
||||
**Estimated**: 6 hours
|
||||
**Files**: `src/pages/Dashboard.tsx`, `src/components/layout/Sidebar.tsx`, etc.
|
||||
|
||||
### Tasks
|
||||
- [ ] Build dashboard layout with sidebar
|
||||
- [ ] Add user menu with sign out
|
||||
- [ ] Create task list view
|
||||
- [ ] Add task filtering (completed, tags, due date)
|
||||
- [ ] Build task creation dialog
|
||||
- [ ] Build task editing dialog
|
||||
- [ ] Add task deletion with confirmation
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Dashboard shows user's tasks
|
||||
- [ ] Filters work correctly
|
||||
- [ ] Can create tasks via dialog
|
||||
- [ ] Can edit existing tasks
|
||||
- [ ] Can delete tasks
|
||||
- [ ] UI updates optimistically
|
||||
|
||||
### Exit Criteria
|
||||
Complete dashboard with full task management.
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: Tags UI
|
||||
**Type**: UI
|
||||
**Estimated**: 3 hours
|
||||
**Files**: `src/components/TagManager.tsx`, `src/components/TagBadge.tsx`
|
||||
|
||||
### Tasks
|
||||
- [ ] Build tag creation form
|
||||
- [ ] Build tag list component
|
||||
- [ ] Add tag selection to task form (multi-select)
|
||||
- [ ] Display tags as badges on tasks
|
||||
- [ ] Allow removing tags from tasks
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Can create new tags
|
||||
- [ ] Can select tags when creating/editing task
|
||||
- [ ] Tags display on task cards
|
||||
- [ ] Can filter by tag
|
||||
- [ ] Can remove tags from tasks
|
||||
|
||||
### Exit Criteria
|
||||
Full tag management integrated with tasks.
|
||||
|
||||
---
|
||||
|
||||
## DATABASE_SCHEMA.md (Excerpt)
|
||||
|
||||
# Database Schema: Personal Task Manager
|
||||
|
||||
---
|
||||
|
||||
## Tables
|
||||
|
||||
### `users`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | Auto-increment |
|
||||
| `clerk_id` | TEXT | UNIQUE, NOT NULL | Clerk user ID |
|
||||
| `email` | TEXT | UNIQUE, NOT NULL | User email |
|
||||
| `display_name` | TEXT | NULL | Display name |
|
||||
| `created_at` | INTEGER | NOT NULL | Unix timestamp |
|
||||
| `updated_at` | INTEGER | NOT NULL | Unix timestamp |
|
||||
|
||||
**Indexes**: `idx_users_clerk_id`, `idx_users_email`
|
||||
|
||||
---
|
||||
|
||||
### `tasks`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | Auto-increment |
|
||||
| `user_id` | INTEGER | FOREIGN KEY, NOT NULL | References users(id) |
|
||||
| `title` | TEXT | NOT NULL | Task title |
|
||||
| `description` | TEXT | NULL | Task description |
|
||||
| `completed` | INTEGER | NOT NULL | 0 or 1 |
|
||||
| `due_date` | INTEGER | NULL | Unix timestamp |
|
||||
| `created_at` | INTEGER | NOT NULL | Unix timestamp |
|
||||
| `updated_at` | INTEGER | NOT NULL | Unix timestamp |
|
||||
|
||||
**Indexes**: `idx_tasks_user_id`, `idx_tasks_due_date`, `idx_tasks_completed`
|
||||
|
||||
**Relationships**: Many-to-one with users
|
||||
|
||||
**Cascade**: ON DELETE CASCADE (deleting user deletes their tasks)
|
||||
|
||||
---
|
||||
|
||||
### `tags`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | Auto-increment |
|
||||
| `user_id` | INTEGER | FOREIGN KEY, NOT NULL | References users(id) |
|
||||
| `name` | TEXT | NOT NULL | Tag name |
|
||||
| `color` | TEXT | NOT NULL | Hex color code |
|
||||
| `created_at` | INTEGER | NOT NULL | Unix timestamp |
|
||||
|
||||
**Indexes**: `idx_tags_user_id`, `idx_tags_name_user_id UNIQUE`
|
||||
|
||||
**Unique Constraint**: (user_id, name) - users can't have duplicate tag names
|
||||
|
||||
---
|
||||
|
||||
### `task_tags`
|
||||
| Column | Type | Constraints | Notes |
|
||||
|--------|------|-------------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | Auto-increment |
|
||||
| `task_id` | INTEGER | FOREIGN KEY, NOT NULL | References tasks(id) |
|
||||
| `tag_id` | INTEGER | FOREIGN KEY, NOT NULL | References tags(id) |
|
||||
| `created_at` | INTEGER | NOT NULL | Unix timestamp |
|
||||
|
||||
**Indexes**: `idx_task_tags_task_id`, `idx_task_tags_tag_id`, `idx_task_tags_composite UNIQUE`
|
||||
|
||||
**Unique Constraint**: (task_id, tag_id) - can't add same tag to task twice
|
||||
|
||||
**Cascade**: ON DELETE CASCADE (deleting task or tag removes association)
|
||||
|
||||
---
|
||||
|
||||
## Relationships Diagram
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ users │
|
||||
└──────┬──────┘
|
||||
│ 1
|
||||
│
|
||||
├─────────────────────┬
|
||||
│ N │ N
|
||||
┌──────┴──────────┐ ┌──────┴──────────┐
|
||||
│ tasks │ │ tags │
|
||||
└──────┬──────────┘ └──────┬──────────┘
|
||||
│ N │ N
|
||||
│ │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌──────┴──────────┐
|
||||
│ task_tags │
|
||||
│ (junction) │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API_ENDPOINTS.md (Excerpt)
|
||||
|
||||
# API Endpoints: Personal Task Manager
|
||||
|
||||
**Auth**: Required on all `/api/*` routes (except webhooks)
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
### GET `/api/auth/me`
|
||||
**Purpose**: Get current user profile
|
||||
|
||||
**Response 200**:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"id": 1,
|
||||
"email": "user@example.com",
|
||||
"displayName": "John Doe",
|
||||
"createdAt": 1234567890
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### GET `/api/tasks`
|
||||
**Purpose**: Get current user's tasks
|
||||
|
||||
**Query Parameters**:
|
||||
- `completed` (optional): `true` or `false`
|
||||
- `tag` (optional): Tag ID to filter by
|
||||
- `dueBefore` (optional): Unix timestamp
|
||||
- `dueAfter` (optional): Unix timestamp
|
||||
|
||||
**Response 200**:
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Review PR",
|
||||
"description": "Check the new feature",
|
||||
"completed": false,
|
||||
"dueDate": 1234567890,
|
||||
"tags": [
|
||||
{ "id": 1, "name": "work", "color": "#3b82f6" }
|
||||
],
|
||||
"createdAt": 1234567890,
|
||||
"updatedAt": 1234567890
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST `/api/tasks`
|
||||
**Purpose**: Create task for current user
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"title": "New Task",
|
||||
"description": "Optional",
|
||||
"dueDate": 1234567890,
|
||||
"tagIds": [1, 2]
|
||||
}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
```typescript
|
||||
z.object({
|
||||
title: z.string().min(1).max(100),
|
||||
description: z.string().optional(),
|
||||
dueDate: z.number().optional(),
|
||||
tagIds: z.array(z.number()).optional()
|
||||
})
|
||||
```
|
||||
|
||||
**Response 201**: Created task with tags
|
||||
|
||||
---
|
||||
|
||||
## Tags
|
||||
|
||||
### GET `/api/tags`
|
||||
**Purpose**: Get current user's tags
|
||||
|
||||
**Response 200**:
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{ "id": 1, "name": "work", "color": "#3b82f6" },
|
||||
{ "id": 2, "name": "personal", "color": "#10b981" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST `/api/tags`
|
||||
**Purpose**: Create tag for current user
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"name": "urgent",
|
||||
"color": "#ef4444"
|
||||
}
|
||||
```
|
||||
|
||||
**Response 201**: Created tag
|
||||
|
||||
**Response 400**: Duplicate tag name (user already has tag with this name)
|
||||
|
||||
---
|
||||
|
||||
## INTEGRATION.md (Excerpt)
|
||||
|
||||
# Third-Party Integrations: Personal Task Manager
|
||||
|
||||
---
|
||||
|
||||
## Clerk (Authentication)
|
||||
|
||||
**Purpose**: User authentication and management
|
||||
|
||||
**Environment Variables**:
|
||||
```env
|
||||
VITE_CLERK_PUBLISHABLE_KEY=pk_test_...
|
||||
CLERK_SECRET_KEY=sk_test_...
|
||||
CLERK_WEBHOOK_SECRET=whsec_...
|
||||
```
|
||||
|
||||
**Custom JWT Template** (Clerk dashboard):
|
||||
```json
|
||||
{
|
||||
"email": "{{user.primary_email_address}}",
|
||||
"userId": "{{user.id}}",
|
||||
"firstName": "{{user.first_name}}",
|
||||
"lastName": "{{user.last_name}}"
|
||||
}
|
||||
```
|
||||
|
||||
**Frontend**:
|
||||
```tsx
|
||||
import { ClerkProvider, SignedIn, SignedOut, UserButton } from '@clerk/clerk-react'
|
||||
|
||||
<ClerkProvider publishableKey={...}>
|
||||
<SignedIn>
|
||||
<Dashboard />
|
||||
<UserButton />
|
||||
</SignedIn>
|
||||
<SignedOut>
|
||||
<LandingPage />
|
||||
</SignedOut>
|
||||
</ClerkProvider>
|
||||
```
|
||||
|
||||
**Backend Middleware**:
|
||||
```typescript
|
||||
import { verifyToken } from '@clerk/backend'
|
||||
|
||||
export async function authMiddleware(c: Context, next: Next) {
|
||||
const token = c.req.header('Authorization')?.replace('Bearer ', '')
|
||||
const verified = await verifyToken(token, {
|
||||
secretKey: c.env.CLERK_SECRET_KEY
|
||||
})
|
||||
c.set('clerkUserId', verified.userId)
|
||||
c.set('email', verified.email)
|
||||
|
||||
// Get local user ID from database
|
||||
const user = await c.env.DB.prepare(
|
||||
'SELECT id FROM users WHERE clerk_id = ?'
|
||||
).bind(verified.userId).first()
|
||||
|
||||
c.set('userId', user.id)
|
||||
await next()
|
||||
}
|
||||
```
|
||||
|
||||
**Webhook** (User Sync):
|
||||
```typescript
|
||||
app.post('/api/webhooks/clerk', async (c) => {
|
||||
const payload = await c.req.text()
|
||||
const verified = await verifyClerkWebhook(payload, c.req.raw.headers, c.env.CLERK_WEBHOOK_SECRET)
|
||||
|
||||
const event = JSON.parse(payload)
|
||||
|
||||
if (event.type === 'user.created') {
|
||||
await c.env.DB.prepare(`
|
||||
INSERT INTO users (clerk_id, email, display_name, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
`).bind(
|
||||
event.data.id,
|
||||
event.data.email_addresses[0].email_address,
|
||||
`${event.data.first_name} ${event.data.last_name}`,
|
||||
Date.now(),
|
||||
Date.now()
|
||||
).run()
|
||||
}
|
||||
|
||||
return c.json({ received: true })
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Note**: This example shows the complete structure for an authenticated multi-user app. For AI-powered features, see `ai-web-app.md`.
|
||||
334
references/example-outputs/simple-web-app.md
Normal file
334
references/example-outputs/simple-web-app.md
Normal file
@@ -0,0 +1,334 @@
|
||||
# Example: Simple Task Manager (No Auth)
|
||||
|
||||
This is an example of planning docs generated for a simple public task manager web app (no user accounts).
|
||||
|
||||
**User Request**: "I want to build a simple task manager where anyone can create, edit, and complete tasks. Just a public tool, no user accounts needed."
|
||||
|
||||
---
|
||||
|
||||
## IMPLEMENTATION_PHASES.md
|
||||
|
||||
# Implementation Phases: Simple Task Manager
|
||||
|
||||
**Project Type**: Public Web App (CRUD)
|
||||
**Stack**: Cloudflare Workers + Vite + React + Tailwind v4 + shadcn/ui + D1
|
||||
**Estimated Total**: 12 hours (~12 minutes human time with AI assistance)
|
||||
**Created**: 2025-10-25
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Project Setup
|
||||
**Type**: Infrastructure
|
||||
**Estimated**: 2-3 hours
|
||||
**Files**: `package.json`, `wrangler.jsonc`, `vite.config.ts`, `src/index.ts`, `src/index.css`
|
||||
|
||||
### Tasks
|
||||
- [ ] Scaffold Cloudflare Worker with Vite using `npm create cloudflare@latest`
|
||||
- [ ] Install dependencies: React, Tailwind v4, shadcn/ui, Hono
|
||||
- [ ] Configure `wrangler.jsonc` with D1 database binding
|
||||
- [ ] Setup Tailwind v4 with `@tailwindcss/vite` plugin
|
||||
- [ ] Initialize shadcn/ui with dark mode support
|
||||
- [ ] Create basic "Hello World" component
|
||||
- [ ] Test local dev server
|
||||
- [ ] Test deployment to Cloudflare
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] `npm run dev` starts without errors
|
||||
- [ ] `localhost:5173` shows React app with Tailwind styling
|
||||
- [ ] Dark/light mode toggle works
|
||||
- [ ] `npm run build` succeeds
|
||||
- [ ] `npx wrangler deploy` deploys successfully
|
||||
- [ ] Deployed URL shows working app
|
||||
|
||||
### Exit Criteria
|
||||
Working development environment with successful test deployment. Can iterate on code locally and deploy to Cloudflare.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Database Schema
|
||||
**Type**: Database
|
||||
**Estimated**: 2 hours
|
||||
**Files**: `migrations/0001_initial.sql`, `src/lib/db-types.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Create D1 database using `npx wrangler d1 create task-manager-db`
|
||||
- [ ] Design `tasks` table schema
|
||||
- [ ] Write migration SQL file
|
||||
- [ ] Apply migration to local database
|
||||
- [ ] Create TypeScript types for database schema
|
||||
- [ ] Write test query in Worker to verify database connection
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Migration runs without errors
|
||||
- [ ] Can insert test task
|
||||
- [ ] Can query tasks from Worker
|
||||
- [ ] TypeScript types match database schema
|
||||
|
||||
### Exit Criteria
|
||||
Database schema deployed locally, can perform CRUD operations from Worker.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Tasks API
|
||||
**Type**: API
|
||||
**Estimated**: 4 hours
|
||||
**Files**: `src/routes/tasks.ts`, `src/lib/schemas.ts`, `src/middleware/cors.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Define Zod schema for task validation
|
||||
- [ ] Create CORS middleware
|
||||
- [ ] Implement GET /api/tasks (list all tasks)
|
||||
- [ ] Implement POST /api/tasks (create task)
|
||||
- [ ] Implement PATCH /api/tasks/:id (update task)
|
||||
- [ ] Implement DELETE /api/tasks/:id (delete task)
|
||||
- [ ] Add error handling middleware
|
||||
- [ ] Test all endpoints manually with curl
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] GET /api/tasks returns empty array initially
|
||||
- [ ] POST /api/tasks with valid data returns 201
|
||||
- [ ] POST /api/tasks with invalid data returns 400
|
||||
- [ ] PATCH /api/tasks/:id updates task and returns 200
|
||||
- [ ] DELETE /api/tasks/:id removes task and returns 204
|
||||
- [ ] Invalid task ID returns 404
|
||||
- [ ] CORS headers present in responses
|
||||
|
||||
### Exit Criteria
|
||||
All CRUD endpoints working, tested with curl, proper error handling.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Task List UI
|
||||
**Type**: UI
|
||||
**Estimated**: 3-4 hours
|
||||
**Files**: `src/components/TaskList.tsx`, `src/components/TaskCard.tsx`, `src/lib/api.ts`
|
||||
|
||||
### Tasks
|
||||
- [ ] Setup TanStack Query for data fetching
|
||||
- [ ] Create API client functions (fetch tasks, create, update, delete)
|
||||
- [ ] Build `TaskList` component with loading/error states
|
||||
- [ ] Build `TaskCard` component to display individual tasks
|
||||
- [ ] Add "Mark complete" toggle functionality
|
||||
- [ ] Add delete button with confirmation
|
||||
- [ ] Style with Tailwind and shadcn/ui components
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Task list displays fetched tasks
|
||||
- [ ] Loading skeleton shows while fetching
|
||||
- [ ] Error message shows if API fails
|
||||
- [ ] Can toggle task completion (optimistic update)
|
||||
- [ ] Can delete task (shows confirmation dialog)
|
||||
- [ ] UI updates immediately after mutations
|
||||
|
||||
### Exit Criteria
|
||||
Task list displays correctly with all CRUD operations working from UI.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Task Creation Form
|
||||
**Type**: UI
|
||||
**Estimated**: 2-3 hours
|
||||
**Files**: `src/components/TaskForm.tsx`, `src/components/CreateTaskDialog.tsx`
|
||||
|
||||
### Tasks
|
||||
- [ ] Install React Hook Form and Zod resolver
|
||||
- [ ] Create `TaskForm` component with title and description fields
|
||||
- [ ] Add client-side validation (Zod schema)
|
||||
- [ ] Build `CreateTaskDialog` modal wrapper
|
||||
- [ ] Implement form submission with TanStack Query mutation
|
||||
- [ ] Add loading state during submission
|
||||
- [ ] Show success/error feedback
|
||||
- [ ] Clear form and close dialog on success
|
||||
|
||||
### Verification Criteria
|
||||
- [ ] Form validates empty title (shows error)
|
||||
- [ ] Form validates title length (max 100 chars)
|
||||
- [ ] Successful submission creates task in database
|
||||
- [ ] Task appears in list immediately (optimistic update)
|
||||
- [ ] Form resets after successful submission
|
||||
- [ ] Dialog closes after successful submission
|
||||
- [ ] Error message shows if submission fails
|
||||
|
||||
### Exit Criteria
|
||||
Can create tasks via form, validation works, UX is smooth.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
### Testing Strategy
|
||||
Testing built into each phase via verification criteria. No separate testing phase needed for this simple project.
|
||||
|
||||
### Deployment Strategy
|
||||
Deploy after each phase to test in production environment:
|
||||
```bash
|
||||
npm run build && npx wrangler deploy
|
||||
```
|
||||
|
||||
### Context Management
|
||||
Phases sized to complete in single session including implementation, verification, and expected debugging.
|
||||
|
||||
---
|
||||
|
||||
## DATABASE_SCHEMA.md
|
||||
|
||||
# Database Schema: Simple Task Manager
|
||||
|
||||
**Database**: Cloudflare D1 (SQLite)
|
||||
**Migrations**: `migrations/` directory
|
||||
**ORM**: None (raw SQL)
|
||||
|
||||
---
|
||||
|
||||
## Tables
|
||||
|
||||
### `tasks`
|
||||
**Purpose**: Store tasks (public, no user association)
|
||||
|
||||
| Column | Type | Constraints | Default | Notes |
|
||||
|--------|------|-------------|---------|-------|
|
||||
| `id` | INTEGER | PRIMARY KEY | AUTO | Auto-increment |
|
||||
| `title` | TEXT | NOT NULL | - | Task title (max 100 chars) |
|
||||
| `description` | TEXT | NULL | - | Task description (optional) |
|
||||
| `completed` | INTEGER | NOT NULL | 0 | 0 = incomplete, 1 = complete |
|
||||
| `created_at` | INTEGER | NOT NULL | - | Unix timestamp |
|
||||
| `updated_at` | INTEGER | NOT NULL | - | Unix timestamp |
|
||||
|
||||
**Indexes**:
|
||||
- `idx_tasks_created_at` on `created_at` (for sorting by date)
|
||||
- `idx_tasks_completed` on `completed` (for filtering complete/incomplete)
|
||||
|
||||
---
|
||||
|
||||
## Migrations
|
||||
|
||||
### Migration 0001: Initial Schema
|
||||
**File**: `migrations/0001_initial_schema.sql`
|
||||
**Purpose**: Create tasks table
|
||||
|
||||
```sql
|
||||
CREATE TABLE tasks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
completed INTEGER NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_tasks_created_at ON tasks(created_at);
|
||||
CREATE INDEX idx_tasks_completed ON tasks(completed);
|
||||
```
|
||||
|
||||
**Run**:
|
||||
```bash
|
||||
npx wrangler d1 execute task-manager-db --local --file=migrations/0001_initial_schema.sql
|
||||
npx wrangler d1 execute task-manager-db --remote --file=migrations/0001_initial_schema.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Seed Data
|
||||
|
||||
**File**: `migrations/seed.sql`
|
||||
|
||||
```sql
|
||||
INSERT INTO tasks (title, description, completed, created_at, updated_at)
|
||||
VALUES
|
||||
('Build database schema', 'Create tasks table with migrations', 1, strftime('%s', 'now'), strftime('%s', 'now')),
|
||||
('Create API endpoints', 'Implement CRUD operations for tasks', 1, strftime('%s', 'now'), strftime('%s', 'now')),
|
||||
('Build UI components', 'Task list and creation form', 0, strftime('%s', 'now'), strftime('%s', 'now'));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API_ENDPOINTS.md
|
||||
|
||||
# API Endpoints: Simple Task Manager
|
||||
|
||||
**Base URL**: `/api`
|
||||
**Framework**: Hono
|
||||
**Auth**: None (public API)
|
||||
**Validation**: Zod schemas
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### GET `/api/tasks`
|
||||
**Purpose**: List all tasks
|
||||
|
||||
**Query Parameters**:
|
||||
- `completed` (optional): Filter by completion status (`true` or `false`)
|
||||
|
||||
**Response 200**:
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Sample Task",
|
||||
"description": "Task description",
|
||||
"completed": false,
|
||||
"createdAt": 1234567890,
|
||||
"updatedAt": 1234567890
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST `/api/tasks`
|
||||
**Purpose**: Create a new task
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"title": "New Task",
|
||||
"description": "Optional description"
|
||||
}
|
||||
```
|
||||
|
||||
**Validation**:
|
||||
```typescript
|
||||
z.object({
|
||||
title: z.string().min(1).max(100),
|
||||
description: z.string().optional()
|
||||
})
|
||||
```
|
||||
|
||||
**Response 201**: Created task object
|
||||
|
||||
**Response 400**: Validation error
|
||||
|
||||
---
|
||||
|
||||
### PATCH `/api/tasks/:id`
|
||||
**Purpose**: Update a task
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"title": "Updated title",
|
||||
"description": "Updated description",
|
||||
"completed": true
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200**: Updated task object
|
||||
|
||||
**Response 404**: Task not found
|
||||
|
||||
---
|
||||
|
||||
### DELETE `/api/tasks/:id`
|
||||
**Purpose**: Delete a task
|
||||
|
||||
**Response 204**: No content (success)
|
||||
|
||||
**Response 404**: Task not found
|
||||
|
||||
---
|
||||
|
||||
**Note**: This is a simplified example for a public task manager. For a production app with user accounts, see the `auth-web-app.md` example.
|
||||
Reference in New Issue
Block a user