8.9 KiB
ADDED Requirements
Requirement: Theme toggle in sidebar
The UI shell SHALL include a theme toggle button in the sidebar. The button SHALL be positioned at the bottom of the sidebar, visually separated from the tool buttons.
Scenario: Toggle button renders
- WHEN the application loads
- THEN a theme toggle button is visible at the bottom of the sidebar
Scenario: Toggle button displays correct icon
- WHEN the current theme mode is "system"
- THEN the button shows a monitor icon (lucide-react
Monitor) - WHEN the current theme mode is "light"
- THEN the button shows a sun icon (lucide-react
Sun) - WHEN the current theme mode is "dark"
- THEN the button shows a moon icon (lucide-react
Moon)
Scenario: Toggle button has tooltip
- WHEN user hovers over the theme toggle button
- THEN a tooltip displays the current mode name (e.g., "Theme: System", "Theme: Light", "Theme: Dark")
Requirement: Accessibility on interactive elements
All interactive elements (buttons, dropdowns, modals) SHALL have aria-label attributes describing their function. Toggle buttons SHALL use aria-pressed. The keyboard shortcuts modal SHALL have role="dialog" and aria-modal="true".
Scenario: Button has aria-label
- WHEN a toolbar button renders
- THEN it has an
aria-labelattribute describing its action (e.g., "Draw span annotation")
Scenario: Modal has dialog role
- WHEN the keyboard shortcuts modal opens
- THEN it has
role="dialog"andaria-modal="true"
Requirement: Focus trapping in modals
Modal dialogs (keyboard shortcuts, confirmation dialogs) SHALL trap focus within the modal while open. Tab and Shift+Tab SHALL cycle through focusable elements within the modal.
Scenario: Focus trapped in modal
- WHEN a modal is open and the user presses Tab
- THEN focus cycles through focusable elements within the modal only
Requirement: Dark theme on settings pages
The annotation-types and span-label-types settings pages SHALL use theme-aware CSS variables instead of hardcoded light colors. They SHALL render correctly in both light and dark themes.
Scenario: Settings page in dark mode
- WHEN the theme is set to dark and user navigates to annotation-types page
- THEN the page renders with dark background and light text (no hardcoded white backgrounds)
Requirement: next/font for Google Fonts
The application SHALL use next/font/google to load Google Fonts instead of CSS @import in globals.css. This prevents render-blocking font loading.
Scenario: Font loaded via next/font
- WHEN the application loads
- THEN Google Fonts are loaded via
next/font/google(not via CSS@import url()in globals.css)
Requirement: Confidence slider debounce
The confidence threshold slider in PredictionPanel SHALL debounce chart re-renders. The slider SHALL update the displayed value immediately but only trigger chart updates after 150ms of inactivity (or on onPointerUp).
Scenario: Dragging slider does not re-render chart per pixel
- WHEN the user drags the confidence slider
- THEN the chart re-renders at most once every 150ms (not on every pixel movement)
Requirement: ChartSelector closes on outside click
The custom chart selector dropdown SHALL close when the user clicks outside of it.
Scenario: Click outside closes dropdown
- WHEN the chart selector dropdown is open and the user clicks elsewhere on the page
- THEN the dropdown closes
Requirement: Dead code removal
The following dead code SHALL be removed:
src/lib/db/migrate.ts(SQLite migration code)get_db_session()inservices/ml/app/db.py(unused session leak)- Dead filter code (TODO comment, no-op) in
page.tsx - Dead
inference*package reference inpyproject.toml
Scenario: No dead migration code
- WHEN
src/lib/db/migrate.tsis searched for - THEN the file does not exist
Scenario: No unused db session function
- WHEN
services/ml/app/db.pyis inspected - THEN
get_db_session()function is absent
Requirement: Deprecated Python API replacements
The ML service SHALL replace deprecated Python APIs:
@app.on_event("startup")replaced with lifespan patterndeclarative_base()replaced withclass Base(DeclarativeBase)datetime.utcnow()replaced withdatetime.now(datetime.UTC)
Scenario: No deprecated startup event
- WHEN
services/ml/app/main.pyis inspected - THEN startup logic uses the FastAPI lifespan pattern (not
@app.on_event)
Scenario: No deprecated utcnow
- WHEN
datetime.utcnow()is searched for in the ML service - THEN zero matches are found (all replaced with
datetime.now(datetime.UTC))
Requirement: Unused import cleanup
Components SHALL not have unused imports. Specifically, Toolbox.tsx SHALL remove unused TrendingUp and ChevronUp imports.
Scenario: No unused imports in Toolbox
- WHEN
Toolbox.tsxis inspected - THEN only imported symbols that are used in the component are present
Requirement: Tooltip component functional or removed
The ui/tooltip.tsx component SHALL either be implemented using Radix Tooltip or removed if unused.
Scenario: Tooltip is functional
- WHEN the Tooltip component is used
- THEN it renders an actual tooltip on hover (not a no-op passthrough)
Requirement: SpanAnnotationList confidence check for zero
The confidence display in SpanAnnotationList SHALL use != null instead of a falsy check, so that a confidence value of 0 is correctly displayed.
Scenario: Confidence zero displayed
- WHEN a span annotation has confidence value
0 - THEN the list displays "0%" (not hidden as if confidence is absent)
MODIFIED Requirements (user-accounts)
Requirement: Theme toggle in sidebar
The UI shell SHALL include a theme toggle button in the sidebar. The button SHALL be positioned at the bottom of the sidebar, visually separated from the tool buttons.
Scenario: Toggle button renders
- WHEN the application loads at
/app - THEN a theme toggle button is visible at the bottom of the sidebar
Scenario: Toggle button displays correct icon
- WHEN the current theme mode is "system"
- THEN the button shows a monitor icon (lucide-react
Monitor) - WHEN the current theme mode is "light"
- THEN the button shows a sun icon (lucide-react
Sun) - WHEN the current theme mode is "dark"
- THEN the button shows a moon icon (lucide-react
Moon)
Scenario: Toggle button has tooltip
- WHEN user hovers over the theme toggle button
- THEN a tooltip displays the current mode name (e.g., "Theme: System", "Theme: Light", "Theme: Dark")
ADDED Requirements (user-accounts)
Requirement: App workspace route at /app
The main workspace page SHALL be served at /app (route src/app/app/page.tsx). The existing src/app/page.tsx content (chart, annotations, toolbox, panels) SHALL move to this new route. The /app route SHALL be protected by the auth proxy.
Scenario: Workspace at /app
- WHEN an authenticated user navigates to
/app - THEN the full workspace renders (chart, toolbox, panels — same as current
/)
Scenario: Unauthenticated redirect
- WHEN an unauthenticated user navigates to
/app - THEN they are redirected to
/login
Requirement: App layout with user menu
The /app layout SHALL include a top navigation bar with the CandleAnnotator logo (linking to /app), and a user menu on the right side. The user menu SHALL show the user's name/email and provide links to Settings and Sign Out.
Scenario: User menu displays identity
- WHEN an authenticated user views the app
- THEN the top nav shows the user's name or email with an avatar/initial
Scenario: User menu dropdown
- WHEN a user clicks the user menu
- THEN a dropdown shows: "Settings" (links to
/app/settings) and "Sign Out" (callssignOut())
Scenario: Sign out
- WHEN a user clicks "Sign Out" in the user menu
- THEN the session is destroyed and the user is redirected to
/login
Requirement: Settings link in sidebar
The sidebar SHALL include a settings gear icon button that navigates to /app/settings.
Scenario: Settings button renders
- WHEN the app workspace loads
- THEN a settings icon button is visible in the sidebar (near the theme toggle)
Scenario: Navigate to settings
- WHEN a user clicks the settings icon
- THEN they are navigated to
/app/settings
Requirement: Public page layout
Public pages (/, /login, /register) SHALL use a separate layout (src/app/(public)/layout.tsx) without the workspace sidebar, toolbox, or user menu. They SHALL share the same root layout (fonts, ThemeProvider).
Scenario: Public layout structure
- WHEN a user views a public page
- THEN the page renders without sidebar, toolbox, or user menu
- AND the root layout fonts and theme provider are still active