- Added ChevronLeft icon from lucide-react
- Added Link import from next/link
- Created back navigation component at top of settings page with hover state
- Links back to /app with "← Back" text
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a destructively-styled Danger Zone card to src/app/app/settings/page.tsx.
Clicking "Delete Account" opens a shadcn/ui Dialog that warns the user the
action is irreversible, requires typing "DELETE" to enable the confirm button,
calls DELETE /api/auth/account on confirmation, then signs the user out and
redirects to "/". Marks task 12.3 complete in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add GET /api/auth/profile endpoint to expose user provider info
- Settings page fetches provider on load to detect credentials vs OAuth
- Credentials users: change password form (current/new/confirm) calling PUT /api/auth/password
- OAuth (Google) users: "Signed in via Google — password cannot be changed" message
- Client-side validation: min 8 chars, passwords-must-match before API call
- Success and error feedback displayed inline in the Security card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create src/app/app/settings/page.tsx as a client component with a
Profile section: display name input pre-filled from session with a
Save button (PUT /api/auth/profile), read-only email field, and
success/error feedback. Mark task 12.1 done in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Google OAuth button matching login page style
- Add divider with 'or' text between form and OAuth button
- Button calls signIn('google') with redirect to /app
- Matches task 11.3 requirements
Verified that the register page at src/app/(public)/register/page.tsx already has proper error state handling:
- Duplicate email error (409): "An account with this email already exists"
- Short password error (400): "Password must be at least 8 characters"
- Errors displayed in a clear alert box with icon and destructive styling
- API endpoint returns correct error messages with proper HTTP status codes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Install sonner for toast notifications
- Add handleForgotPassword function that shows "Not yet available" toast
- Add "Forgot password?" link next to password label
- Verify "Sign up" link to /register exists
- Add Toaster component to public layout
- Mark task 10.3 as [x] in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Capture error from signIn() response (checks for ok: false)
- Check for ?error= in URL search params (Auth.js redirects with error on failure)
- Display red alert box with error message below the form when auth fails
- Clear error on new login attempt
Completes task 10.2 in user-accounts change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create src/app/(public)/login/page.tsx as a client component matching
the Lovable design: email/password form calling signIn("credentials"),
"Continue with Google" button calling signIn("google"), and a link to
the register page.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract navbar into separate client component (navbar.tsx) with useSession hook
- When authenticated: show "Go to App" button linking to /app
- When unauthenticated: show "Log in" and "Get Started" buttons
- Add SessionProvider to public layout to enable auth hooks
- Create session-provider wrapper component to separate concerns (metadata exports still work)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements the public landing page matching the Lovable design mockup:
- Sticky navbar with CandleAnnotator logo, Log in / Get Started links
- Hero section with gradient background, headline, and CTA buttons
- Features grid with 6 cards (Precision Annotation, ML Training Pipeline,
Real-Time Predictions, Multi-Chart Workspace, Keyboard-First Workflow,
Export & Persist) using lucide-react icons
- Stats bar showing 50ms render latency, 6 shortcut keys, JSON export
- Footer CTA section with Create Free Account button
- Minimal footer with logo and copyright
Uses Tailwind CSS and shadcn/ui Button component, consistent with project stack.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Changed href="/annotation-types" to href="/app/annotation-types"
- Changed href="/span-label-types" to href="/app/span-label-types"
These links are in the settings menu of the main app workspace
and should navigate within the protected /app route group.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Protected app layout wrapping all /app/* pages with SessionProvider from
next-auth/react. Includes a minimal fixed nav bar with an app title link,
a settings link to /app/settings, and a placeholder slot for the user menu
dropdown (to be implemented in task 13.1).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create src/app/app/ directory
- Move the main app component (dashboard) to src/app/app/page.tsx
- Replace src/app/page.tsx with a redirect to /login
- Update tasks.md to mark 8.2 as complete
This establishes the /app workspace route for the authenticated app while the root / will redirect to login.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create src/app/(public)/layout.tsx as route group for public pages
- Inherits font variables and theme from root layout via middleware
- No sidebar, nav bar, or protected components in public layout
- Marked task 8.1 complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
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>
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>
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>
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>
- 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>
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>
Adds nullable uuid user_id column referencing users.id to each of the 5
data tables. Column is nullable for now to allow the data migration
script (task 2.5) to backfill existing rows before enforcing NOT NULL.
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>