Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:25:20 +08:00
commit 34b2a798b6
17 changed files with 7796 additions and 0 deletions

View 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.

View 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.

View 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`.

View 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.