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