Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 29 additions & 26 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
GSD Task Manager is a privacy-first Eisenhower matrix task manager built with Next.js 16 App Router. All data is stored locally in IndexedDB via Dexie, with JSON export/import for backups. The app is a PWA that works completely offline.

**Key Features:**
- **Optional Cloud Sync** — End-to-end encrypted multi-device sync via Cloudflare Workers (OAuth with Google/Apple)
- **Optional Cloud Sync** — End-to-end encrypted multi-device sync via Supabase (Auth + Postgres + Realtime)
- **MCP Server Integration** — AI-powered task management through Claude Desktop with natural language queries
- **Zero-Knowledge Architecture** — Worker stores only encrypted blobs; decryption happens locally
- **Zero-Knowledge Architecture** — Server stores only encrypted blobs; decryption happens locally
- **Realtime Sync** — Instant cross-device updates via Supabase Realtime (WebSocket)
- **Smart Views** — Pin up to 5 smart views to header (keyboard shortcuts 1-9, 0 to clear)
- **Command Palette** — Global ⌘K/Ctrl+K shortcut for quick actions and navigation
- **iOS-style Settings** — Redesigned settings with grouped layout and modular sections
Expand Down Expand Up @@ -84,33 +85,41 @@ Logic in `lib/quadrants.ts` with `resolveQuadrantId()` and `quadrantOrder`.
- `components/pwa-register.tsx` - SW registration

### Cloud Sync Architecture
- **Backend**: Cloudflare Workers + D1 (SQLite) + KV + R2
- **Authentication**: OAuth 2.0 with Google and Apple (OIDC-compliant)
- **Backend**: Supabase (Postgres 17 + Auth + Realtime + PostgREST)
- **Authentication**: Supabase Auth with Google and Apple OAuth providers
- **Encryption**: AES-256-GCM with PBKDF2 key derivation (600k iterations)
- **Sync Protocol**: Vector clock-based conflict resolution
- **Zero-Knowledge**: Worker stores only encrypted blobs
- **Sync Protocol**: Last-write-wins (LWW) based on server `updated_at` timestamps
- **Realtime**: Supabase Realtime (WebSocket) for instant cross-device sync
- **Zero-Knowledge**: Server stores only encrypted blobs; RLS policies enforce user isolation

**Key Locations**:
- `worker/src/` - Cloudflare Worker (Hono router, handlers, D1 queries)
- `lib/supabase.ts` - Supabase client singleton
- `lib/sync/supabase-sync-client.ts` - Sync CRUD via Supabase SDK
- `lib/sync/realtime-listener.ts` - Realtime subscription manager
- `lib/sync/engine/` - Frontend sync engine (push, pull, conflict resolution)
- `lib/sync/crypto.ts` - Client-side encryption/decryption
- `components/sync/supabase-auth-dialog.tsx` - Auth UI with Supabase Auth

**API Endpoints**: `/api/auth/oauth/:provider/start`, `/api/auth/oauth/callback`, `/api/auth/oauth/result`, `/api/auth/refresh`, `/api/auth/logout`, `/api/auth/encryption-salt`, `/api/sync/push`, `/api/sync/pull`, `/api/sync/status`, `/api/devices`
**Database Tables**: `profiles`, `encrypted_tasks`, `devices`, `sync_metadata`, `conflict_log`

**Environment Variables**:
- `NEXT_PUBLIC_SUPABASE_URL` - Supabase project URL
- `NEXT_PUBLIC_SUPABASE_ANON_KEY` - Supabase anonymous key

### MCP Server Architecture
- **Purpose**: Enable Claude Desktop to access/analyze tasks via natural language
- **Location**: `packages/mcp-server/` - Standalone npm package
- **Runtime**: Node.js 18+ with TypeScript, stdio transport (JSON-RPC 2.0)

**20 MCP Tools**:
- *Read (7)*: list_tasks, get_task, search_tasks, get_sync_status, list_devices, get_task_stats, get_token_status
**19 MCP Tools**:
- *Read (6)*: list_tasks, get_task, search_tasks, get_sync_status, list_devices, get_task_stats
- *Write (5)*: create_task, update_task, complete_task, delete_task, bulk_update_tasks (all support dryRun)
- *Analytics (5)*: get_productivity_metrics, get_quadrant_analysis, get_tag_analytics, get_upcoming_deadlines, get_task_insights
- *System (3)*: validate_config, get_help, get_cache_stats

**Key Features**: Retry logic with exponential backoff, TTL cache, dry-run mode, circular dependency validation
**Key Features**: TTL cache, dry-run mode, circular dependency validation, direct Supabase queries via service role key

**Configuration**: Claude Desktop config at `~/Library/Application Support/Claude/claude_desktop_config.json` with `GSD_API_BASE_URL`, `GSD_AUTH_TOKEN`, `GSD_ENCRYPTION_PASSPHRASE`
**Configuration**: Claude Desktop config at `~/Library/Application Support/Claude/claude_desktop_config.json` with `GSD_SUPABASE_URL`, `GSD_SUPABASE_SERVICE_KEY`, `GSD_USER_EMAIL`, `GSD_ENCRYPTION_PASSPHRASE`

## Testing Guidelines
- UI tests in `tests/ui/`, data logic in `tests/data/`
Expand Down Expand Up @@ -141,23 +150,18 @@ Logic in `lib/quadrants.ts` with `resolveQuadrantId()` and `quadrantOrder`.
- Smart view shortcuts (1-9, 0) use `useSmartViewShortcuts` with typing detection

### Cloud Sync
- **Worker Deployment**: `npm run deploy:all` in `worker/`
- **Environment Setup**: `./worker/scripts/setup-{env}.sh`
- **Migrations**: `npm run migrations:{env}`
- JWT tokens expire after 7 days; handle refresh flow (401 → re-auth)
- **Auth**: Supabase Auth handles OAuth (Google/Apple) and session management automatically
- **Realtime**: `lib/sync/realtime-listener.ts` subscribes to `encrypted_tasks` changes via WebSocket
- **Conflict Resolution**: Last-write-wins (LWW) based on server `updated_at` timestamps
- Never log encryption salts or passphrases
- Supabase SDK auto-refreshes auth tokens; no manual token management needed

### MCP Server
- Build with `npm run build` in `packages/mcp-server/`
- Add tools: schemas in `tools/schemas/`, handlers in `tools/handlers/`
- Use `fetchWithRetry()` for resilient API calls
- Uses `@supabase/supabase-js` with service role key to query Postgres directly
- Use `CryptoManager` singleton for encryption/decryption

### OAuth Popup Handling
- `public/oauth-callback.html` uses multiple heuristics for popup detection
- OAuth results broadcast via BroadcastChannel, postMessage, and localStorage
- `SyncAuthDialog` adds delay to avoid duplicate encryption dialogs

### Pre-commit
- Run `bun run test`, `bun typecheck`, and `bun lint` before committing
- Static export mode means no API routes or SSR
Expand All @@ -168,12 +172,11 @@ The codebase follows coding standards (<350 lines per file, <30 lines per functi

- **lib/analytics/**: metrics, streaks, tags, trends
- **lib/notifications/**: display, permissions, settings, badge
- **lib/sync/engine/**: coordinator, push-handler, pull-handler, conflict-resolver, error-handler
- **lib/sync/oauth-handshake/**: broadcaster, subscriber, fetcher (cross-tab OAuth communication)
- **lib/sync/engine/**: sync engine, push-handler, pull-handler, conflict-resolver
- **lib/sync/**: supabase-sync-client, realtime-listener, crypto, queue
- **components/task-form/**: index, use-task-form hook, validation
- **components/settings/**: appearance, notification, sync, archive, data-management sections
- **worker/src/handlers/sync/**: push, pull, resolve, status, devices
- **worker/src/handlers/oidc/**: initiate, callback, result, token-exchange
- **components/sync/**: supabase-auth-dialog, supabase-oauth-buttons, sync-button, encryption-passphrase-dialog
- **packages/mcp-server/src/tools/**: handlers/, schemas/, individual tool files
- **packages/mcp-server/src/write-ops/**: task-operations, bulk-operations with dry-run support

Expand Down
58 changes: 26 additions & 32 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ When users enable cloud sync, the following security measures protect their data
- Derived keys never leave user's device

3. **Zero-Knowledge Architecture**
- Worker stores only encrypted blobs
- Supabase stores only encrypted blobs
- Server cannot decrypt task content (no access to passphrase)
- Encryption/decryption happens entirely in browser/MCP client
- Even Cloudflare employees cannot read your tasks
- Even database administrators cannot read your tasks

4. **Salt Architecture (Threat Model)**
- Salt is generated client-side (32 random bytes) and synced to server
Expand All @@ -69,29 +69,23 @@ When users enable cloud sync, the following security measures protect their data
- **Brute-force mitigation**: 600K PBKDF2 iterations makes attacks expensive
- **Design rationale**: Enables multi-device sync while maintaining zero-knowledge

### OAuth Authentication
### Authentication (Supabase Auth)

1. **Providers**
- Google (OIDC-compliant)
- Apple (OIDC-compliant)

2. **Security Features**
- PKCE (Proof Key for Code Exchange) prevents code interception
- PKCE (Proof Key for Code Exchange) handled by Supabase Auth
- State parameter prevents CSRF attacks
- ID token signature verification (JWT)
- Short-lived session tokens (24 hours)
- Supabase manages JWT issuance, refresh, and validation
- Row Level Security (RLS) enforces per-user data isolation

3. **Token Management**
- JWT tokens with 7-day expiration
- HS256 signature with 256-bit secret per environment
- Tokens stored in IndexedDB (browser-encrypted at rest)
- Refresh flow on token expiration

### Rate Limiting

- 100 requests/minute per IP via Cloudflare KV
- Prevents brute-force attacks on authentication
- Distributed rate limiting across edge locations
3. **Session Management**
- Supabase Auth handles token lifecycle automatically
- Auto-refresh on token expiration
- Sessions persisted in browser storage
- No manual JWT management required

### Network Security

Expand All @@ -106,14 +100,14 @@ The MCP server allows Claude Desktop to access tasks via natural language querie

### Security Model

1. **Read-Only Access**
- MCP tools can only read tasks, not modify/delete
- No write operations implemented
- Safe exploration without data modification risk
1. **Read & Write Access**
- 6 read tools, 5 write tools (with dry-run support), 5 analytics, 3 system tools
- Write operations support `dryRun` mode to preview changes safely
- Service role key provides server-side access (bypasses RLS)

2. **Local Decryption**
- Encryption passphrase stored only in Claude Desktop config
- Passphrase never transmitted to Worker
- Passphrase never transmitted to Supabase
- Decryption happens on user's local machine

3. **Opt-In Feature**
Expand All @@ -129,7 +123,9 @@ The MCP server allows Claude Desktop to access tasks via natural language querie
"mcpServers": {
"gsd-taskmanager": {
"env": {
"GSD_AUTH_TOKEN": "eyJ...", // JWT from OAuth
"GSD_SUPABASE_URL": "https://your-project.supabase.co",
"GSD_SUPABASE_SERVICE_KEY": "...", // Service role key
"GSD_USER_EMAIL": "your-email@example.com",
"GSD_ENCRYPTION_PASSPHRASE": "..." // User's passphrase
}
}
Expand All @@ -154,7 +150,7 @@ script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:;
font-src 'self' data:;
connect-src 'self' https://gsd-dev.vinny.dev https://accounts.google.com https://appleid.apple.com;
connect-src 'self' https://*.supabase.co wss://*.supabase.co https://accounts.google.com https://appleid.apple.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self' https://accounts.google.com https://appleid.apple.com;
Expand All @@ -167,7 +163,7 @@ script-src 'self';
style-src 'self';
img-src 'self' data: blob:;
font-src 'self';
connect-src 'self' https://gsd.vinny.dev https://accounts.google.com https://appleid.apple.com;
connect-src 'self' https://*.supabase.co wss://*.supabase.co https://accounts.google.com https://appleid.apple.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self' https://accounts.google.com https://appleid.apple.com;
Expand Down Expand Up @@ -342,18 +338,16 @@ If you discover a security vulnerability, please:
### Last Audit: 2026-01-23

- ✅ All critical vulnerabilities resolved
- ✅ Dependency vulnerabilities patched (wrangler, hono, MCP SDK)
- ✅ Token storage architecture reviewed and documented
- ✅ Dependency vulnerabilities patched (MCP SDK)
- ✅ Supabase Auth + RLS architecture reviewed and documented
- ✅ End-to-end encryption implemented for cloud sync
- ✅ OAuth PKCE flow implemented for authentication
- ✅ MCP server read-only access enforced

### Resolved Issues (2026-01-23)

1. **Hono JWT Algorithm Confusion (H1)** - Added override for hono ≥4.11.4 (fixes GHSA-3vhc-576x-3qv4, GHSA-f67f-6cw9-8mq4)
2. **Wrangler OS Command Injection (H2)** - Upgraded wrangler to ^4.59.1 (fixes GHSA-36p8-mvp6-cv38)
3. **Undici Decompression DoS (M3)** - Fixed transitively via wrangler update (fixes GHSA-g9mf-h72j-4rw9)
4. **MCP SDK update** - Upgraded @modelcontextprotocol/sdk to ^1.25.3
1. **MCP SDK update** - Upgraded @modelcontextprotocol/sdk to ^1.25.3
2. **Removed Cloudflare Worker dependencies** - Eliminated wrangler, hono, and associated transitive vulnerabilities by migrating to Supabase

### Previously Resolved Issues

Expand All @@ -366,7 +360,7 @@ If you discover a security vulnerability, please:

### Known Trade-offs (Documented)

1. **Token Storage in IndexedDB** - Required for offline-first PWA. Mitigated by React XSS protection, CSP headers, and E2E encryption of task data. See `worker/src/constants/security.ts:57-80` for full rationale.
1. **Session Storage in Browser** - Required for offline-first PWA. Mitigated by React XSS protection, CSP headers, Supabase Auth auto-refresh, and E2E encryption of task data.

## References

Expand Down
Loading