chore: archive both OpenSpec changes and sync specs to main

This commit is contained in:
Marko Djordjevic 2026-02-12 17:56:25 +01:00
parent a6e763c153
commit 50229e2ccf
25 changed files with 927 additions and 1 deletions

View file

@ -0,0 +1,203 @@
## ADDED Requirements
### Requirement: Multi-stage Dockerfile
The project SHALL include a Dockerfile with multi-stage build for optimized production images.
#### Scenario: Build stage setup
- **WHEN** Dockerfile build stage executes
- **THEN** uses Node.js 18-alpine base image, copies package files, installs ALL dependencies including devDependencies, copies source code, and runs `npm run build`
#### Scenario: Runtime stage setup
- **WHEN** Dockerfile runtime stage executes
- **THEN** uses Node.js 18-alpine base image, creates non-root user 'appuser', copies only production dependencies and built files from build stage, and sets USER to appuser
#### Scenario: Working directory structure
- **WHEN** container runs
- **THEN** application files are in /app directory, database volume mounts to /app/data, and permissions allow appuser to write to /app/data
#### Scenario: Environment variables in Dockerfile
- **WHEN** Dockerfile defines environment
- **THEN** sets NODE_ENV=production, PORT=3000, and HOSTNAME=0.0.0.0 for Next.js standalone server
#### Scenario: Exposed ports
- **WHEN** container is built
- **THEN** Dockerfile exposes port 3000 for HTTP traffic
#### Scenario: Container startup
- **WHEN** container starts
- **THEN** executes `node server.js` (Next.js standalone output) as the CMD
### Requirement: Docker Compose configuration
The project SHALL include docker-compose.yml for simplified deployment orchestration.
#### Scenario: Service definition
- **WHEN** docker-compose.yml is parsed
- **THEN** defines single service named 'candle-annotator' using Dockerfile from current directory
#### Scenario: Port mapping
- **WHEN** docker-compose up runs
- **THEN** maps host port 3000 to container port 3000 (configurable via PORT environment variable)
#### Scenario: Volume mounting for database
- **WHEN** docker-compose up runs
- **THEN** mounts named volume 'candle-data' to /app/data in container for SQLite database persistence
#### Scenario: Environment variable configuration
- **WHEN** docker-compose.yml is used
- **THEN** supports loading environment variables from .env file for NODE_ENV, PORT, and other configs
#### Scenario: Restart policy
- **WHEN** container crashes or stops
- **THEN** docker-compose automatically restarts container unless explicitly stopped (restart: unless-stopped)
#### Scenario: Volume declaration
- **WHEN** docker-compose.yml is parsed
- **THEN** declares 'candle-data' as named volume in volumes section
### Requirement: Environment variable configuration
The project SHALL use environment variables for runtime configuration.
#### Scenario: .env.example file
- **WHEN** repository is cloned
- **THEN** includes .env.example file documenting all configurable environment variables with example values
#### Scenario: PORT configuration
- **WHEN** PORT environment variable is set
- **THEN** Next.js server listens on specified port (default: 3000)
#### Scenario: NODE_ENV configuration
- **WHEN** NODE_ENV environment variable is set to 'production'
- **THEN** Next.js runs in production mode with optimizations enabled
#### Scenario: Database path configuration
- **WHEN** DATABASE_PATH environment variable is set (optional)
- **THEN** SQLite database file is created at specified path (default: ./data/candles.db)
#### Scenario: HOSTNAME configuration
- **WHEN** HOSTNAME environment variable is set
- **THEN** Next.js server binds to specified hostname (default: 0.0.0.0 for containers)
### Requirement: Health check endpoint
The API SHALL provide a health check endpoint for container orchestration.
#### Scenario: Health check endpoint responds
- **WHEN** GET request sent to `/api/health`
- **THEN** system returns 200 status with JSON `{ status: 'ok', timestamp: <unix_timestamp> }`
#### Scenario: Database connection check
- **WHEN** GET request sent to `/api/health?check=db`
- **THEN** system attempts simple database query and returns 200 if successful, 503 if database unavailable
#### Scenario: Health check in Dockerfile
- **WHEN** Dockerfile defines HEALTHCHECK
- **THEN** runs `curl -f http://localhost:3000/api/health || exit 1` every 30 seconds with 3 retries
### Requirement: .dockerignore file
The project SHALL include .dockerignore to exclude unnecessary files from Docker context.
#### Scenario: Excluded files
- **WHEN** Docker build context is created
- **THEN** .dockerignore excludes node_modules, .next, .git, data/, *.md, .env*, and test files
#### Scenario: Included files
- **WHEN** Docker build context is created
- **THEN** includes package.json, package-lock.json, source code in src/, and required config files
### Requirement: Next.js standalone output
The build SHALL use Next.js standalone output mode for minimal production bundle.
#### Scenario: next.config.js standalone setting
- **WHEN** next.config.js is read
- **THEN** output property is set to 'standalone'
#### Scenario: Standalone build output
- **WHEN** npm run build executes
- **THEN** Next.js creates .next/standalone directory with minimal runtime files and dependencies
#### Scenario: Copy standalone files to image
- **WHEN** Dockerfile runtime stage executes
- **THEN** copies .next/standalone/ contents to /app, copies .next/static to /app/.next/static, and copies public/ to /app/public
### Requirement: Production build optimization
The Docker image SHALL be optimized for production use with minimal size.
#### Scenario: Use alpine base images
- **WHEN** Dockerfile specifies base images
- **THEN** uses node:18-alpine for both build and runtime stages
#### Scenario: Multi-stage build cleanup
- **WHEN** Docker image is built
- **THEN** build artifacts, devDependencies, and source files are not included in final image
#### Scenario: Layer caching optimization
- **WHEN** Dockerfile is structured
- **THEN** package.json and package-lock.json are copied and dependencies installed before source code copy for better layer caching
#### Scenario: Final image size
- **WHEN** Docker image build completes
- **THEN** final image size is under 200MB (excluding data volume)
### Requirement: Database persistence
The deployment SHALL ensure SQLite database persists across container restarts.
#### Scenario: Volume mounting
- **WHEN** container runs with volume mount
- **THEN** /app/data directory is mounted from host or Docker volume
#### Scenario: Database file location
- **WHEN** application initializes database
- **THEN** SQLite file is created at /app/data/candles.db (inside mounted volume)
#### Scenario: Container restart preserves data
- **WHEN** container is stopped and restarted
- **THEN** existing database file is reused and all annotations and candles remain intact
#### Scenario: File permissions
- **WHEN** container creates database file
- **THEN** appuser has read/write permissions to /app/data directory
### Requirement: Deployment documentation
DEPLOYMENT.md SHALL include comprehensive Docker deployment instructions.
#### Scenario: Docker deployment section
- **WHEN** DEPLOYMENT.md is read
- **THEN** includes dedicated "Docker Deployment" section with prerequisites, build steps, and run commands
#### Scenario: Quick start commands
- **WHEN** following deployment docs
- **THEN** provides complete commands: `docker-compose up -d` for production and `docker-compose up --build` for rebuilding
#### Scenario: Environment setup instructions
- **WHEN** following deployment docs
- **THEN** explains how to copy .env.example to .env and configure required variables
#### Scenario: Volume backup instructions
- **WHEN** following deployment docs
- **THEN** provides commands to backup database: `docker cp candle-annotator:/app/data/candles.db ./backup.db`
#### Scenario: Troubleshooting section
- **WHEN** deployment issues occur
- **THEN** DEPLOYMENT.md includes troubleshooting for common Docker issues: port conflicts, permission errors, build failures
#### Scenario: Update and maintenance
- **WHEN** updating deployed application
- **THEN** documentation provides steps: pull new code, rebuild image, restart containers with data preservation
### Requirement: Container security
The Docker setup SHALL follow security best practices.
#### Scenario: Non-root user
- **WHEN** container runs
- **THEN** application process runs as non-root user 'appuser' (UID 1000)
#### Scenario: Read-only filesystem where possible
- **WHEN** container runs
- **THEN** only /app/data directory requires write permissions, all other files are read-only to appuser
#### Scenario: No sensitive data in image
- **WHEN** Docker image is built
- **THEN** .env files, secrets, and database files are not included in image layers
#### Scenario: Minimal attack surface
- **WHEN** container runs
- **THEN** only port 3000 is exposed, no SSH, no unnecessary services, alpine base reduces package vulnerabilities

View file

@ -0,0 +1,274 @@
## ADDED Requirements
### Requirement: Monospace typography
The application SHALL use monospace fonts throughout the entire interface.
#### Scenario: Primary font family
- **WHEN** CSS font-family is applied
- **THEN** system uses font stack: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace
#### Scenario: Font loading
- **WHEN** application loads
- **THEN** system loads JetBrains Mono font from Google Fonts or local files with weights: 400, 500, 700
#### Scenario: All text elements
- **WHEN** rendering any text (buttons, labels, inputs, tooltips, headings)
- **THEN** all text uses monospace font family without exception
#### Scenario: Number formatting
- **WHEN** displaying numbers (prices, timestamps, counts)
- **THEN** uses tabular-nums CSS property for aligned columns
### Requirement: Matrix-style color scheme
The application SHALL use a dark background with neon green (#00ff41) accent color scheme.
#### Scenario: Background colors
- **WHEN** rendering main layout
- **THEN** page background is #0a0e0a (near black), sidebar background is #0d110d, and chart background is #000000
#### Scenario: Primary accent color
- **WHEN** highlighting interactive elements, active states, or success messages
- **THEN** uses #00ff41 (matrix green) as the primary accent color
#### Scenario: Secondary accent colors
- **WHEN** rendering labels or status indicators
- **THEN** uses #ff0040 (neon red) for break_down/destructive, #00ff41 (neon green) for break_up/success, #00d4ff (neon cyan) for informational, #ffff00 (neon yellow) for warnings
#### Scenario: Text colors
- **WHEN** rendering text
- **THEN** primary text is #00ff41, secondary text is #00cc33 (dimmer green), and disabled text is #003311 (very dim green)
#### Scenario: Border colors
- **WHEN** rendering borders
- **THEN** uses #00ff41 with 1px solid for active elements, #003311 for inactive borders
### Requirement: Neon glow effects
The application SHALL apply glow effects to active and interactive elements.
#### Scenario: Button hover glow
- **WHEN** user hovers over any button
- **THEN** button shows box-shadow: 0 0 10px #00ff41, 0 0 20px #00ff4180
#### Scenario: Active tool glow
- **WHEN** a tool is active (selected)
- **THEN** button shows pulsing glow animation with box-shadow: 0 0 15px #00ff41, 0 0 30px #00ff4180
#### Scenario: Selected element glow
- **WHEN** a line or label is selected
- **THEN** element shows glow effect with filter: drop-shadow(0 0 8px #00ff41)
#### Scenario: Input focus glow
- **WHEN** user focuses on text input or search field
- **THEN** input shows border glow: box-shadow: 0 0 8px #00ff41
#### Scenario: Cursor circle glow
- **WHEN** drawing line with cursor circle visible
- **THEN** cursor circle has stroke glow with filter: drop-shadow(0 0 4px currentColor)
### Requirement: ASCII-style borders
The application SHALL use terminal-inspired border styling with corner characters.
#### Scenario: Container borders
- **WHEN** rendering bordered containers (Toolbox, label list sections)
- **THEN** uses 1px solid borders with #00ff41 color
#### Scenario: Border corners with pseudo-elements
- **WHEN** rendering section headers or important containers
- **THEN** uses CSS ::before and ::after pseudo-elements to display ASCII corner characters: ┌ ┐ └ ┘
#### Scenario: Separator lines
- **WHEN** rendering section separators
- **THEN** uses border-top: 1px solid #003311 with optional ASCII characters (─) via pseudo-elements
#### Scenario: Card-style containers
- **WHEN** rendering label list entries or modal dialogs
- **THEN** containers have 1px solid border with subtle inset shadow for depth
### Requirement: Terminal-like feedback messages
The application SHALL display command-style feedback for user actions.
#### Scenario: Success message format
- **WHEN** user completes an action successfully (delete, create, export)
- **THEN** displays message in format: `> SUCCESS: <action> completed [<count> items]` in green text
#### Scenario: Error message format
- **WHEN** an error occurs
- **THEN** displays message in format: `> ERROR: <description> [code: <error_code>]` in red text
#### Scenario: Info message format
- **WHEN** displaying informational message
- **THEN** displays message in format: `> INFO: <message>` in cyan text
#### Scenario: Message container styling
- **WHEN** displaying any feedback message
- **THEN** container has monospace font, left-aligned text, subtle border, and auto-dismiss after 4 seconds
#### Scenario: Message animation
- **WHEN** feedback message appears
- **THEN** slides in from top with fade-in animation (0.3s ease-out)
### Requirement: Minimalist icon treatment
The application SHALL use simplified, outline-style icons or ASCII alternatives.
#### Scenario: Lucide icon styling
- **WHEN** rendering Lucide React icons
- **THEN** icons use stroke-width: 1.5, size: 20px, and color matches text color (#00ff41)
#### Scenario: Icon hover effect
- **WHEN** user hovers over icon button
- **THEN** icon glows with filter: drop-shadow(0 0 4px currentColor)
#### Scenario: ASCII alternative icons (optional)
- **WHEN** rendering simple actions (delete, expand, collapse)
- **THEN** optionally uses ASCII characters: [×] for delete, [▼] for expand, [▲] for collapse, [>] for actions
#### Scenario: Icon color consistency
- **WHEN** icon is in active/selected state
- **THEN** icon color is #00ff41
- **WHEN** icon is in disabled state
- **THEN** icon color is #003311
### Requirement: High contrast for readability
The application SHALL maintain WCAG AA contrast ratios for all text.
#### Scenario: Primary text contrast
- **WHEN** displaying primary text (#00ff41) on dark background (#0a0e0a)
- **THEN** contrast ratio is at least 4.5:1 (WCAG AA standard)
#### Scenario: Secondary text contrast
- **WHEN** displaying secondary text (#00cc33) on dark background
- **THEN** contrast ratio is at least 4.5:1
#### Scenario: Button text contrast
- **WHEN** button is in any state (default, hover, active, disabled)
- **THEN** text maintains minimum 4.5:1 contrast with background
#### Scenario: Chart element visibility
- **WHEN** rendering lines and markers on chart
- **THEN** all annotations have sufficient contrast against black background and candles
### Requirement: Simplified button styling
The application SHALL use minimal, flat button design with terminal aesthetic.
#### Scenario: Default button appearance
- **WHEN** rendering buttons in default state
- **THEN** buttons have transparent background, 1px solid #00ff41 border, #00ff41 text, 4px padding, and no rounded corners (border-radius: 0)
#### Scenario: Hover button appearance
- **WHEN** user hovers over button
- **THEN** background changes to #00ff4110 (10% opacity), border glows, and text remains #00ff41
#### Scenario: Active button appearance
- **WHEN** button is active/pressed
- **THEN** background is #00ff4120 (20% opacity), border is 2px solid, and includes pulsing glow animation
#### Scenario: Disabled button appearance
- **WHEN** button is disabled
- **THEN** background is transparent, border is #003311, text is #003311, and no hover effects
#### Scenario: Destructive button styling
- **WHEN** button represents destructive action (delete)
- **THEN** uses #ff0040 (neon red) for border and text instead of green, with matching red glow on hover
### Requirement: Cyber-retro aesthetic elements
The application SHALL include subtle design elements that enhance the hacker theme.
#### Scenario: Scanline effect (optional)
- **WHEN** rendering main container
- **THEN** applies subtle CSS repeating-linear-gradient overlay simulating CRT scanlines with 2px spacing at 5% opacity
#### Scenario: Noise texture (optional)
- **WHEN** rendering background
- **THEN** applies subtle noise texture using CSS filter or background-image at 3% opacity for grain effect
#### Scenario: Typewriter animation for messages
- **WHEN** displaying new feedback message
- **THEN** text appears with brief letter-by-letter typing animation (0.02s per character, max 0.5s total)
#### Scenario: Flicker animation on focus
- **WHEN** user focuses on input field
- **THEN** border shows brief flicker animation (0.1s) simulating electrical surge
#### Scenario: ASCII art branding (optional)
- **WHEN** application loads or in header
- **THEN** displays application name in ASCII art style using monospace font
### Requirement: Responsive dark theme
The application SHALL maintain theme consistency across all components and states.
#### Scenario: Modal dialogs
- **WHEN** displaying confirmation dialogs
- **THEN** modal has dark background (#0d110d), neon green border, monospace font, and terminal-style title (e.g., "> CONFIRM ACTION")
#### Scenario: Input fields
- **WHEN** rendering text inputs or search fields
- **THEN** inputs have transparent background, #00ff41 border, #00ff41 text, #00ff4120 placeholder, and cursor color #00ff41
#### Scenario: Dropdown menus
- **WHEN** displaying filter or select dropdowns
- **THEN** dropdown has dark background (#0d110d), neon green border, #00ff41 option text, hover state with #00ff4120 background
#### Scenario: Scrollbars
- **WHEN** content requires scrolling
- **THEN** custom scrollbar with #003311 track, #00ff41 thumb, and 8px width
#### Scenario: Tooltips
- **WHEN** displaying tooltips on hover
- **THEN** tooltip has dark background (#0d110d), 1px #00ff41 border, monospace font, and terminal-style text
### Requirement: Animation performance
The application SHALL use performant CSS animations that don't impact chart rendering.
#### Scenario: GPU acceleration
- **WHEN** applying animations (glow, pulse, fade)
- **THEN** uses CSS transform and opacity properties with will-change hints for GPU acceleration
#### Scenario: Animation duration
- **WHEN** defining animations
- **THEN** all animations complete within 0.5s, with most hover effects at 0.2s
#### Scenario: Reduced motion support
- **WHEN** user has prefers-reduced-motion enabled
- **THEN** system disables glow animations, typewriter effects, and pulsing, keeping only instant transitions
#### Scenario: Chart performance
- **WHEN** theme is active and chart is rendering
- **THEN** SVG overlay and chart rendering maintains 60fps without jank from theme effects
### Requirement: Tailwind CSS configuration
The Tailwind config SHALL be updated to support hacker theme tokens.
#### Scenario: Custom colors in tailwind.config
- **WHEN** tailwind.config.js is parsed
- **THEN** defines custom colors: matrix: '#00ff41', matrixDim: '#00cc33', matrixDark: '#003311', neonRed: '#ff0040', neonCyan: '#00d4ff', neonYellow: '#ffff00', terminal: '#0a0e0a', terminalLight: '#0d110d'
#### Scenario: Custom font families
- **WHEN** tailwind.config.js is parsed
- **THEN** defines fontFamily: { mono: ['JetBrains Mono', 'Fira Code', 'Courier New', 'monospace'] }
#### Scenario: Custom animations
- **WHEN** tailwind.config.js is parsed
- **THEN** defines keyframes for 'glow-pulse', 'flicker', 'scanline-move' and corresponding animation utilities
#### Scenario: Custom shadows
- **WHEN** tailwind.config.js is parsed
- **THEN** defines boxShadow: { 'glow-sm': '0 0 8px #00ff41', 'glow': '0 0 15px #00ff41, 0 0 30px #00ff4180', 'glow-lg': '0 0 20px #00ff41, 0 0 40px #00ff4180' }
### Requirement: globals.css updates
The globals.css file SHALL define base styles and CSS variables for the hacker theme.
#### Scenario: CSS custom properties
- **WHEN** globals.css is loaded
- **THEN** defines CSS variables: --color-matrix, --color-matrix-dim, --color-matrix-dark, --color-neon-red, --color-neon-cyan, --color-terminal, --font-mono
#### Scenario: Base body styles
- **WHEN** page loads
- **THEN** body element has background: --color-terminal, color: --color-matrix, font-family: --font-mono, and -webkit-font-smoothing: antialiased
#### Scenario: Selection styling
- **WHEN** user selects text
- **THEN** selection background is #00ff4140 (40% opacity) and text is #00ff41
#### Scenario: Scrollbar styling
- **WHEN** globals.css is loaded
- **THEN** defines custom scrollbar styles using ::-webkit-scrollbar pseudo-elements with theme colors

View file

@ -0,0 +1,166 @@
## ADDED Requirements
### Requirement: Select label by clicking marker
The system SHALL allow users to select label annotations by clicking on their marker symbols on the chart.
#### Scenario: Click on break_up marker
- **WHEN** user clicks on a green arrow (break_up) marker on the chart
- **THEN** system sets selectedLabelId state to the annotation ID, highlights the marker with increased size and glow effect, and scrolls to the label in the sidebar list
#### Scenario: Click on break_down marker
- **WHEN** user clicks on a red arrow (break_down) marker on the chart
- **THEN** system sets selectedLabelId state to the annotation ID, highlights the marker with increased size and glow effect, and scrolls to the label in the sidebar list
#### Scenario: Click already selected marker
- **WHEN** user clicks on a marker that is already selected
- **THEN** system deselects the marker by setting selectedLabelId to null and removes highlight effects
#### Scenario: Click different marker while one is selected
- **WHEN** user clicks on a different marker while another marker is already selected
- **THEN** system deselects the previous marker, selects the new marker, and updates the highlight to the new marker
#### Scenario: Tool mode during label selection
- **WHEN** user selects a label marker
- **THEN** selection works regardless of active tool (works in all modes: none, line, delete, break_up, break_down)
### Requirement: Delete selected label with keyboard
The system SHALL allow users to delete the currently selected label annotation using keyboard shortcuts.
#### Scenario: Delete selected label with Delete key
- **WHEN** a label is selected (selectedLabelId is set) and user presses Delete key
- **THEN** system sends DELETE request to `/api/annotations/{id}`, removes marker from display, clears selection state, and triggers annotation refresh
#### Scenario: Delete selected label with Backspace key
- **WHEN** a label is selected and user presses Backspace key
- **THEN** system sends DELETE request to `/api/annotations/{id}`, removes marker from display, clears selection state, and triggers annotation refresh
#### Scenario: No label selected when pressing delete
- **WHEN** no label is selected (selectedLabelId is null) and user presses Delete or Backspace key
- **THEN** system takes no action on labels (may still delete selected line if line is selected)
### Requirement: Label list in sidebar
The Toolbox SHALL display a collapsible section showing all label annotations with interactive controls.
#### Scenario: Display label list section
- **WHEN** Toolbox renders
- **THEN** system displays "Label Annotations" section below the annotation tools with collapse/expand toggle button
#### Scenario: Label list expanded
- **WHEN** "Label Annotations" section is expanded
- **THEN** system displays scrollable list of all label annotations sorted by timestamp (newest first), with each entry showing timestamp, label type badge, and delete button
#### Scenario: Label list collapsed
- **WHEN** user clicks collapse button on "Label Annotations" section
- **THEN** system hides the label list but shows count summary "Labels: X break_up, Y break_down"
#### Scenario: Empty label list
- **WHEN** no label annotations exist in database
- **THEN** section displays message "No labels yet. Click Break Up or Break Down tools to add labels."
#### Scenario: Label entry format
- **WHEN** displaying a label in the list
- **THEN** each entry shows formatted timestamp (e.g., "Feb 12, 14:30"), colored badge ("BREAK UP" in green or "BREAK DOWN" in red), and trash icon delete button
### Requirement: Click label in list to select on chart
The system SHALL allow users to click a label in the sidebar list to select and highlight it on the chart.
#### Scenario: Click label entry in sidebar
- **WHEN** user clicks on a label entry in the sidebar list
- **THEN** system sets selectedLabelId to that annotation ID, highlights the corresponding marker on chart, and centers the chart view on that timestamp
#### Scenario: Click already selected label in list
- **WHEN** user clicks on a label entry that is already selected
- **THEN** system deselects the label by setting selectedLabelId to null and removes highlights
#### Scenario: Selected label visual in list
- **WHEN** a label is selected
- **THEN** the corresponding entry in the sidebar list has a highlighted background and border
### Requirement: Delete label from sidebar
The system SHALL provide delete buttons for each label in the sidebar list.
#### Scenario: Click delete button for label
- **WHEN** user clicks trash icon button next to a label in the sidebar
- **THEN** system sends DELETE request to `/api/annotations/{id}`, removes label from list and chart, clears selection if that label was selected, and triggers annotation refresh
#### Scenario: Delete button styling
- **WHEN** displaying delete buttons in label list
- **THEN** buttons use red/destructive color on hover and show tooltip "Delete this label"
### Requirement: Search and filter labels
The Toolbox label section SHALL provide search and filter controls.
#### Scenario: Filter by label type
- **WHEN** user selects filter dropdown and chooses "Break Up"
- **THEN** system displays only break_up annotations in the list
#### Scenario: Filter by label type - Break Down
- **WHEN** user selects filter dropdown and chooses "Break Down"
- **THEN** system displays only break_down annotations in the list
#### Scenario: Show all labels
- **WHEN** user selects filter dropdown and chooses "All"
- **THEN** system displays all label annotations regardless of type
#### Scenario: Search by timestamp
- **WHEN** user types text into search input field
- **THEN** system filters list to show only labels whose formatted timestamp contains the search text (case-insensitive)
#### Scenario: Combined search and filter
- **WHEN** user has both search text and type filter active
- **THEN** system shows labels that match both criteria (AND logic)
### Requirement: Label count display
The Toolbox SHALL display counts of each label type.
#### Scenario: Display label counts
- **WHEN** Toolbox renders and labels exist
- **THEN** system displays count summary "Break Up: X | Break Down: Y" at top of label section
#### Scenario: Zero labels
- **WHEN** no labels exist in database
- **THEN** count summary displays "Break Up: 0 | Break Down: 0"
#### Scenario: Count updates after delete
- **WHEN** user deletes a label
- **THEN** count summary updates immediately to reflect the new totals
### Requirement: Delete all labels with confirmation
The system SHALL provide a "Delete All Labels" button with confirmation dialog.
#### Scenario: Click Delete All Labels button
- **WHEN** user clicks "Delete All Labels" button in Toolbox
- **THEN** system displays confirmation dialog with message "Delete all label annotations (Break Up and Break Down)? This cannot be undone." and Cancel/Confirm buttons
#### Scenario: User confirms delete all labels
- **WHEN** confirmation dialog is open and user clicks Confirm button
- **THEN** system sends DELETE request to `/api/annotations?type=break_up,break_down`, removes all label markers from chart, clears label list, clears selection state, triggers annotation refresh, and closes dialog
#### Scenario: User cancels delete all labels
- **WHEN** confirmation dialog is open and user clicks Cancel button
- **THEN** system closes dialog without making any API calls or removing any labels
#### Scenario: Delete All Labels button visibility
- **WHEN** one or more label annotations exist
- **THEN** "Delete All Labels" button is enabled with destructive styling
- **WHEN** no label annotations exist
- **THEN** "Delete All Labels" button is disabled with reduced opacity
### Requirement: API support for label operations
The API SHALL support filtering and bulk deletion of label annotations.
#### Scenario: Delete all break_up labels
- **WHEN** DELETE request sent to `/api/annotations?type=break_up`
- **THEN** system deletes all annotations where label_type equals 'break_up' and returns `{ success: true, deleted: <count> }`
#### Scenario: Delete all break_down labels
- **WHEN** DELETE request sent to `/api/annotations?type=break_down`
- **THEN** system deletes all annotations where label_type equals 'break_down' and returns `{ success: true, deleted: <count> }`
#### Scenario: Delete multiple types at once
- **WHEN** DELETE request sent to `/api/annotations?type=break_up,break_down`
- **THEN** system deletes all annotations where label_type is either 'break_up' or 'break_down' and returns `{ success: true, deleted: <count> }`
#### Scenario: Get labels with type filter
- **WHEN** GET request sent to `/api/annotations?type=break_up`
- **THEN** system returns only annotations where label_type equals 'break_up'