Commit graph

187 commits

Author SHA1 Message Date
Marko Djordjevic
bd668589b6 Add X-User-ID header to all FastAPI ML service proxy routes
- Add X-User-ID header containing user.id to all fetch calls from proxy routes
- Updated routes: /api/predict, /api/predict/batch, /api/model/info, /api/model/load, /api/patterns/detect, /api/patterns/available, /api/training/start, /api/training/runs
- Enables user scoping on the FastAPI ML service side

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:12:25 +01:00
Marko Djordjevic
685639a0d3 Add getAuthUser() auth guard to all ML proxy API routes (task 7.3)
Adds authentication check at the top of each handler in:
- /api/predict
- /api/predict/batch
- /api/model/info
- /api/model/load
- /api/patterns/detect
- /api/patterns/available
- /api/training/start
- /api/training/runs

Returns 401 Unauthorized for unauthenticated requests. Proxy/fetch logic unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:10:23 +01:00
Marko Djordjevic
5f727d84c6 Scope all Drizzle queries by user_id from authenticated session
Every data API route now filters SELECT, INSERT, UPDATE, and DELETE
queries by the authenticated user's ID, ensuring full multi-tenant
data isolation. Candle queries are scoped via chart_id ownership.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:08:09 +01:00
Marko Djordjevic
9901d0f3f1 Add getAuthUser() auth guard to all data API routes (task 7.1)
Add 401 Unauthorized check at the top of every handler in:
- /api/upload (POST)
- /api/candles (GET)
- /api/charts (GET) and /api/charts/[id] (GET, DELETE)
- /api/annotations (GET, POST, DELETE) and /api/annotations/[id] (PATCH, DELETE)
- /api/annotation-types (GET, POST, DELETE) and /api/annotation-types/[id] (PATCH)
- /api/span-annotations (GET, POST, DELETE), /[id] (PATCH, DELETE), /export (GET)
- /api/span-label-types (GET, POST) and /[id] (PATCH, DELETE)
- /api/export (GET) and /api/export/spans (GET)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:26:09 +01:00
Marko Djordjevic
aa2c5fdb69 Add DELETE /api/auth/account endpoint for full account deletion
Implements task 6.3: deletes all user data in correct FK order
(span_annotations, annotations, candles, charts, span_label_types,
annotation_types) then deletes the user record. Returns 401 if not
authenticated, 200 on success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:22:43 +01:00
Marko Djordjevic
93f7d20382 Add PUT /api/auth/password endpoint for credential users
Implements task 6.2: verifies current password with bcryptjs, rejects
OAuth users (no password_hash), validates new password (8+ chars),
hashes and persists the new password.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:21:27 +01:00
Marko Djordjevic
c36ab7c146 Implement task 6.1: Create PUT /api/auth/profile endpoint for updating user display name
- Create src/app/api/auth/profile/route.ts with PUT handler
- Validates user is authenticated (returns 401 if not)
- Validates request body has a non-empty name field
- Updates user's name in the database
- Returns 200 with updated user data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:20:20 +01:00
Marko Djordjevic
d4e92cf88f Add src/lib/auth.ts helper for extracting user from Auth.js session
Implement task 5.2: Create getAuthUser() helper that calls auth() from
src/auth.ts and returns the authenticated user object or null if not
authenticated. Mark task 5.2 complete in tasks.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:19:12 +01:00
Marko Djordjevic
55fd91ff52 Add Next.js middleware for route protection (task 5.1)
- Create src/middleware.ts using Auth.js v5 auth() wrapper
- Protect /app/* routes: redirect unauthenticated users to /login
- Protect /api/* routes (except /api/auth/* and /api/health): return 401 JSON for unauthenticated requests
- Redirect authenticated users away from /login and /register to /app
- Mark task 5.1 as complete in tasks.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:18:15 +01:00
Marko Djordjevic
10e4ec8648 Task 4.2: Add default data seeding on new user creation
Create seedUserDefaults() helper in src/lib/db/seed-user-defaults.ts
that inserts default annotation_types (break_up, break_down, line) and
default span_label_types (bull_flag, bear_flag, etc.) scoped to a
given user_id. Call it from POST /api/auth/register after user insert
and from src/auth.ts Google signIn callback after new Google user creation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:16:55 +01:00
Marko Djordjevic
9a5e325632 feat(auth): add POST /api/auth/register endpoint (task 4.1)
Validates email presence and password length (8+ chars), checks email
uniqueness with 409 on conflict, hashes password with bcryptjs (cost 12),
inserts user into the users table and returns 201 with id/email/name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 10:14:55 +01:00
Marko Djordjevic
45b6366861 Create nextauth route handler exporting GET/POST from auth.ts (task 3.4) 2026-02-20 10:13:32 +01:00
Marko Djordjevic
a8c88f3ca2 Task 3.3: Handle Google OAuth sign-in callback in src/auth.ts
- Add signIn callback: on Google sign-in, check users table by email;
  create new user (provider='google', provider_account_id, name/image
  from profile) if not found, or allow sign-in for returning users
- Update jwt callback to look up DB uuid by email for Google sign-ins,
  so token.id is always the DB uuid rather than the Google sub ID
- Mark task 3.3 as complete in tasks.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:58:18 +01:00
Marko Djordjevic
40afd4111c Mark task 3.2 done: JWT and session callbacks already implemented in src/auth.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:56:48 +01:00
Marko Djordjevic
50e85e499a Add src/auth.ts with Auth.js v5 config (task 3.1)
JWT session strategy, Credentials provider with bcryptjs password
verification, and Google OAuth provider using AUTH_GOOGLE_ID/SECRET.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:55:04 +01:00
Marko Djordjevic
73f44bf447 Add data migration script for user-accounts (task 2.5)
Create scripts/migrate-users.ts that:
- Creates a default admin user from DEFAULT_ADMIN_EMAIL/DEFAULT_ADMIN_PASSWORD env vars
- Backfills user_id on all existing rows in charts, annotations, annotation_types,
  span_annotations, span_label_types
- Is idempotent (safe to run multiple times)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:51:23 +01:00
Marko Djordjevic
877ae032a1 Mark task 2.4 as complete: Generate Drizzle migration 2026-02-20 09:50:14 +01:00
Marko Djordjevic
b633a3f52a Task 2.3: Replace single-column unique constraints with composite (user_id, name) unique indexes
- charts.name → uniqueIndex('charts_user_id_name_unique').on(user_id, name)
- annotation_types.name → uniqueIndex('annotation_types_user_id_name_unique').on(user_id, name)
- span_label_types.name → uniqueIndex('span_label_types_user_id_name_unique').on(user_id, name)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:48:50 +01:00
Marko Djordjevic
0cd74ebedd Mark task 2.2 complete in user-accounts tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:47:41 +01:00
Marko Djordjevic
9101cfb7af Add users table to Drizzle schema (task 2.1)
Adds the `users` table to `src/lib/db/schema.ts` with:
- UUID primary key (defaultRandom)
- email (unique, not null)
- password_hash (nullable, for OAuth-only users)
- name, image (nullable)
- provider (default 'credentials'), provider_account_id (nullable)
- email_verified (timestamp, nullable)
- created_at, updated_at

Marks task 2.1 as complete in tasks.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:46:20 +01:00
Marko Djordjevic
d05ed21cd6 Task 1.3: Update docker-compose.yml to pass new auth environment variables
Add AUTH_SECRET, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, AUTH_TRUST_HOST,
DEFAULT_ADMIN_EMAIL, and DEFAULT_ADMIN_PASSWORD environment variables to
the candle-annotator service in docker-compose.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:45:12 +01:00
Marko Djordjevic
7ba1380cc7 Add authentication environment variables to .env.example
Added AUTH_SECRET, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, AUTH_TRUST_HOST, DEFAULT_ADMIN_EMAIL, and DEFAULT_ADMIN_PASSWORD environment variables with helpful comments and placeholder values for Auth.js v5 and Google OAuth setup.

Marked task 1.2 as complete in tasks.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:44:25 +01:00
Marko Djordjevic
973662739a Install authentication dependencies: next-auth@5, bcryptjs, @types/bcryptjs
Add required npm packages for user authentication implementation:
- next-auth@5.0.0-beta.30: Next.js authentication library
- bcryptjs@3.0.3: Password hashing library
- @types/bcryptjs@2.4.6: TypeScript types for bcryptjs

Mark task 1.1 as complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 09:43:45 +01:00
Marko Djordjevic
3c39690f4a Assign per-task model tags in user-accounts tasks.md
Replace section-level model tags with individual task-level tags.
Haiku for mechanical/config/boilerplate, sonnet for standard feature
work, opus for 2.5 (data migration backfill) and 7.2 (user_id query
permeation across all routes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 08:59:17 +01:00
Marko Djordjevic
925e7284e3 Archive code-review-fix change and sync specs to main
- Synced 14 capability delta specs to main specs
- Created 6 new main specs: api-authentication, error-boundary, input-validation, security-headers, shared-types
- Updated 8 existing specs with security, validation, and performance requirements
- Archived change to openspec/changes/archive/2026-02-20-code-review-fix/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 08:54:59 +01:00
Marko Djordjevic
16123d385a test deployment 2026-02-18 21:42:42 +01:00
Marko Djordjevic
25c959fd18 code-review-fix task 15.4: mark task 15.4 as done in tasks.md 2026-02-18 20:58:53 +01:00
Marko Djordjevic
09a361ca54 code-review-fix task 15.3: mark task 15.3 as done in tasks.md 2026-02-18 20:58:18 +01:00
Marko Djordjevic
9c08ffc44d code-review-fix task 15.2: mark task 15.2 as done in tasks.md 2026-02-18 20:57:44 +01:00
Marko Djordjevic
728c7e4d82 code-review-fix task 15.1: mark task 15.1 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 20:57:13 +01:00
Marko Djordjevic
21c855db89 code-review-fix task 14.5: mark task 14.5 as done in tasks.md 2026-02-18 20:55:21 +01:00
Marko Djordjevic
d4c14df284 code-review-fix task 14.4: mark task 14.4 as done in tasks.md 2026-02-18 20:48:44 +01:00
Marko Djordjevic
3e4d4bd7ae code-review-fix task 14.3: mark task 14.3 as done in tasks.md 2026-02-18 20:48:14 +01:00
Marko Djordjevic
4081a566b5 code-review-fix task 14.2: mark task 14.2 as done in tasks.md 2026-02-18 20:47:51 +01:00
Marko Djordjevic
c9c63aafa3 code-review-fix task 14.1: mark task 14.1 as done in tasks.md 2026-02-18 20:47:17 +01:00
Marko Djordjevic
bf9a475b89 code-review-fix task 13.3: mark task 13.3 as done in tasks.md 2026-02-18 20:46:37 +01:00
Marko Djordjevic
03b2500980 code-review-fix task 13.2: mark task 13.2 as done in tasks.md 2026-02-18 20:46:04 +01:00
Marko Djordjevic
36382508f7 code-review-fix task 13.1: mark task 13.1 as done in tasks.md 2026-02-18 20:45:30 +01:00
Marko Djordjevic
576375b135 code-review-fix task 12.12: mark task 12.12 as done in tasks.md 2026-02-18 20:44:54 +01:00
Marko Djordjevic
5ffab3ef44 code-review-fix task 12.11: mark task 12.11 as done in tasks.md 2026-02-18 20:44:04 +01:00
Marko Djordjevic
13f4860358 code-review-fix task 12.10: mark task 12.10 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 20:43:25 +01:00
Marko Djordjevic
030b0c5885 code-review-fix task 12.9: mark task 12.9 as done in tasks.md 2026-02-18 20:42:17 +01:00
Marko Djordjevic
3f6bcd5c7d code-review-fix task 12.8: mark task 12.8 as done in tasks.md 2026-02-18 20:40:47 +01:00
Marko Djordjevic
2d8222740c code-review-fix task 12.7: mark task 12.7 as done in tasks.md 2026-02-18 20:40:08 +01:00
Marko Djordjevic
e8b8bbb56f code-review-fix task 12.6: mark task 12.6 as done in tasks.md 2026-02-18 20:39:14 +01:00
Marko Djordjevic
6260f7caed code-review-fix task 12.5: mark task 12.5 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 20:38:30 +01:00
Marko Djordjevic
f9ff0d266e code-review-fix task 12.4: mark task 12.4 as done in tasks.md 2026-02-18 20:37:40 +01:00
Marko Djordjevic
a0a30beb8e code-review-fix task 12.3: mark task 12.3 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 20:36:41 +01:00
Marko Djordjevic
6a194e81ac code-review-fix task 12.2: mark task 12.2 as done in tasks.md 2026-02-18 20:34:55 +01:00
Marko Djordjevic
15be4c6ca1 code-review-fix task 12.1: mark task 12.1 as done in tasks.md 2026-02-18 20:34:20 +01:00