Commit graph

23 commits

Author SHA1 Message Date
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