Commit graph

393 commits

Author SHA1 Message Date
Marko Djordjevic
c77d17e5e2 Fix MLflow psycopg2 missing by installing psycopg2-binary at startup
The official MLflow image lacks psycopg2. Install it via pip before
starting the server. Also fix artifact root to use absolute path
inside the mounted volume.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 09:54:51 +01:00
Marko Djordjevic
d7f583701c change mlflow to use database instead of mlflow folder 2026-02-21 09:35:15 +01:00
Marko Djordjevic
187243bfdb Fix MLflow localhost references to use Docker service name
Replace hardcoded localhost:5000 with mlflow:5000 in pipeline.yaml
and main.py health check fallback so containers can reach MLflow
over Docker's internal network.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 09:34:16 +01:00
Marko Djordjevic
f3425557ce add credentials to ml-service docker for migrations 2026-02-21 09:12:24 +01:00
Marko Djordjevic
60e3cb755d remove __pycache__ from git 2026-02-21 09:11:47 +01:00
Marko Djordjevic
33ed7b7cb7 Fix auth redirect to 0.0.0.0 and credentials sign-in error
- Add AUTH_URL env var to docker-compose.yml and .env/.env.example so
  NextAuth builds correct redirect URLs instead of falling back to the
  Docker bind address (0.0.0.0:3000)
- Normalize email to lowercase in authorize() to match how the register
  route stores emails, preventing case-sensitive lookup mismatches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 23:42:24 +01:00
Marko Djordjevic
53e6d363b7 Fix malformed favicon.svg - remove nested SVG tags
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 23:26:36 +01:00
Marko Djordjevic
852d19e3db Add favicon from RealFaviconGenerator
Downloads and integrates favicon assets (SVG, PNG, ICO, Apple touch icon,
web app manifest icons) and wires them up via Next.js metadata API in the
root layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 23:07:10 +01:00
Marko Djordjevic
ea8c86f425 fix annotation links 2026-02-20 22:30:55 +01:00
Marko Djordjevic
54a45146ed Redirect to home page on sign out instead of login page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 22:30:38 +01:00
Marko Djordjevic
173623a432 Move span-label-types and annotation-types links from sidebar settings menu to settings page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 22:26:39 +01:00
Marko Djordjevic
044a73c3f0 Add db:migrate npm script for local development convenience
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 22:19:36 +01:00
Marko Djordjevic
61ad63ce35 Remove root page.tsx redirect so landing page renders at /
The root src/app/page.tsx was redirecting all visitors to /login,
preventing the (public)/page.tsx landing page from rendering at /.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:13:54 +01:00
Marko Djordjevic
3e242c3359 Migrate middleware.ts to proxy.ts for Next.js 16 and fix build errors
Next.js 16 renamed middleware to proxy. Merged session-based auth and
API key auth into a single proxy.ts. Also fixed: auth route handler
exports, missing card component, Button asChild type errors, signIn
return type, Drizzle eq() type narrowing, and useSearchParams suspense
boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:52:38 +01:00
Marko Djordjevic
76cb49e908 Migrate MLflow backend to PostgreSQL and fix .env loading
- Add python-dotenv loading in main.py so DATABASE_URL is read from .env
  before db.py module initializes
- Add MLFLOW_TRACKING_URI to .env.example pointing to PostgreSQL
- Add python-dotenv>=1.0.0 to pyproject.toml dependencies
- Initialize MLflow schema in candle_annotator PostgreSQL database

MLflow server now starts without filesystem deprecation warnings and
with full job execution support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 21:34:31 +01:00
Marko Djordjevic
5fb9733bd6 Archive user-accounts change to openspec/changes/archive/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:50:36 +01:00
Marko Djordjevic
448b67199f Sync user-accounts delta specs to main specs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:50:14 +01:00
Marko Djordjevic
34d58948a3 Mark task 15.4 as complete: Update .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:41:32 +01:00
Marko Djordjevic
e1ddcfe1b1 Update .env.example with correct AUTH_SECRET generation command
Change AUTH_SECRET generation command from 'openssl rand -hex 32' to 'openssl rand -base64 32' for consistency with documentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:41:26 +01:00
Marko Djordjevic
fb1411cb13 Mark task 15.3 as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:40:59 +01:00
Marko Djordjevic
f5a67d9fa4 Update CLAUDE_DESCRIPTION.md with auth system, routing, and schema changes (v3.2.0)
- Document Auth.js v5 multi-user authentication with Credentials and Google OAuth
- Add new routing structure: (public) for /, /login, /register and /app/* protected routes
- Document middleware-based route protection in middleware.ts
- Add new API auth endpoints: /api/auth/register, /profile, /password, /account
- Document user_id foreign keys on all data tables with composite unique constraints
- Add settings page at /app/settings for user profile management
- Update API endpoints section to show auth endpoints and protected data endpoints
- Update file structure to reflect new auth files and route groups
- Update constraints to note authentication requirement and JWT session management
- Update version history to reflect v3.2.0 changes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:40:52 +01:00
Marko Djordjevic
66bcd8cca8 Mark task 15.2 as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:39:48 +01:00
Marko Djordjevic
e783c9cbe9 Update README.md with user accounts feature description (Task 15.2)
Add new 'User Accounts & Authentication' section describing:
- Multi-user support with per-user data isolation
- Auth.js v5 with credentials and Google OAuth sign-in
- Registration with email validation and password requirements
- Settings page for profile management and account deletion
- Default admin account seeding

Remove outdated single-user limitation from Known Limitations section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:39:43 +01:00
Marko Djordjevic
1001de659f Mark task 15.1 as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:39:18 +01:00
Marko Djordjevic
227a5b66e6 Update DEPLOYMENT.md with authentication and migration documentation
- Add new environment variables section: AUTH_SECRET, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET, AUTH_TRUST_HOST, DEFAULT_ADMIN_EMAIL, DEFAULT_ADMIN_PASSWORD
- Add detailed Google OAuth setup instructions with step-by-step guide to create OAuth app
- Add database migration steps: Drizzle migrations + user migration script with explanation
- Update Docker environment configuration with all auth-related variables
- Update Notes section to reflect new multi-user authentication system

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:39:14 +01:00
Marko Djordjevic
8623b61c73 Mark task 14.3 as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:38:24 +01:00
Marko Djordjevic
688e75e6be Scope training run queries in FastAPI to filter by user ID (Task 14.3)
- Add user_id column to TrainingRun model in db.py
- Store user_id on TrainingRun insert in /training/start
- Filter GET /training/runs by user_id (returns empty list if no user context)
- Enforce user ownership on GET /training/runs/{run_id} (404 on mismatch)
- Enforce user ownership on DELETE /training/runs/{run_id} (404 on mismatch)
- Add migration 002 to add user_id column and index to training_runs table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 18:38:18 +01:00
Marko Djordjevic
cbb921b4a7 Scope MLflow experiment names to include user ID (Task 14.2)
- Updated FastAPI /training/start endpoint to extract X-User-ID header via get_user_id() dependency
- Modified _run_training_background to accept and use user_id parameter
- Added MLflow experiment setup with user scoping: experiments are named user_{user_id}_training when user_id is provided, falling back to default experiment name otherwise
- Updated database record insertion to store scoped experiment name
- Updated training/train.py train() function to accept user_id parameter and use it for experiment naming
- Mark task 14.2 as complete in tasks.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:46:00 +01:00
Marko Djordjevic
9f76d7eb62 Mark task 14.1 as complete in tasks.md.
Task 14.1: Update FastAPI service to read X-User-ID header from incoming requests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:44:06 +01:00
Marko Djordjevic
399e760fa5 Add X-User-ID header extraction to FastAPI service.
Create a get_user_id() dependency that extracts the X-User-ID header
from incoming requests, making it available to route handlers.
The dependency is optional (not enforced) — callers decide whether
to use it or require it on specific routes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:44:02 +01:00
Marko Djordjevic
b9f6770f2a Mark task 13.3 complete: Wire signOut() in user menu
The signOut() function in src/components/user-menu.tsx is already correctly
configured with callbackUrl: '/login' to destroy the session and redirect
to the login page. Verified implementation is complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:42:57 +01:00
Marko Djordjevic
fe68eca773 Add settings gear icon to sidebar (task 13.2)
Added a Settings icon button next to the theme toggle in the sidebar header
that links to /app/settings. This provides quick access to user settings
from the main workspace.

- Import Link from next/link in app/page.tsx
- Add Settings icon with link to /app/settings in sidebar header
- Mark task 13.2 as complete in tasks.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:42:19 +01:00
Marko Djordjevic
9884f47d5a feat(13.1): add UserMenu component with avatar, Settings link, and Sign Out
- Install @radix-ui/react-dropdown-menu and add shadcn/ui dropdown-menu component
- Create src/components/user-menu.tsx: avatar button showing user initial,
  DropdownMenu with name/email label, Settings link (/app/settings), Sign Out
  (calls signOut with redirect to /login)
- Replace placeholder div in src/app/app/layout.tsx with <UserMenu />
- Remove now-redundant standalone Settings link from nav bar (Settings is in dropdown)
- Mark task 13.1 done in openspec/changes/user-accounts/tasks.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:41:21 +01:00
Marko Djordjevic
fba0b29d64 Add back navigation link to /app on settings page
- 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>
2026-02-20 13:37:48 +01:00
Marko Djordjevic
0d8d8627a2 Add Danger Zone section to settings page with delete account dialog
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>
2026-02-20 13:37:03 +01:00
Marko Djordjevic
64b3bfd0d4 feat(settings): add Security section with change password form (task 12.2)
- 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>
2026-02-20 13:35:19 +01:00
Marko Djordjevic
9514a987e3 Add settings page profile section (task 12.1)
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>
2026-02-20 13:32:39 +01:00
Marko Djordjevic
3f3cb6eebf Mark task 11.3 complete: Add Google button and sign-in link to register page 2026-02-20 13:31:10 +01:00
Marko Djordjevic
77327eeb61 Add Continue with Google button to register page
- 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
2026-02-20 13:31:03 +01:00
Marko Djordjevic
bf3b59ab2d Mark task 11.2 as complete: error state display verified on register page
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>
2026-02-20 13:30:24 +01:00
Marko Djordjevic
50d8c84367 Add register page (task 11.1): name/email/password form with POST to /api/auth/register and auto sign-in
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:29:36 +01:00
Marko Djordjevic
3b03a87c41 Task 10.3: Add "Forgot password?" link with toast and "Sign up" link to login page
- 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>
2026-02-20 13:28:17 +01:00
Marko Djordjevic
42a76ed41b Add error state display for invalid credentials on login page
- 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>
2026-02-20 13:22:51 +01:00
Marko Djordjevic
954dd27c88 Add login page with credentials and Google sign-in (task 10.1)
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>
2026-02-20 13:21:48 +01:00
Marko Djordjevic
2d29f63597 Mark task 9.2 as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:20:03 +01:00
Marko Djordjevic
d0ebf677f3 Add auth-aware navbar to landing page
- 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>
2026-02-20 13:19:58 +01:00
Marko Djordjevic
09facbce69 Add landing page at src/app/(public)/page.tsx (task 9.1)
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>
2026-02-20 13:18:31 +01:00
Marko Djordjevic
162dfb0882 Mark task 8.4 complete: Update hardcoded links to /app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:16:49 +01:00
Marko Djordjevic
7cd0acc82f Update hardcoded links in app page from / to /app
- 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>
2026-02-20 13:16:45 +01:00
Marko Djordjevic
07efa32cfb Task 8.3: Create src/app/app/layout.tsx with SessionProvider and nav bar
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>
2026-02-20 13:15:41 +01:00