# Design: Annotation Features and Deployment Enhancement

## Context

### Current State
The candle annotator has a working annotation system with:
- Line drawing with color selection, visual feedback, selection, and endpoint dragging (Phase 1-4 complete)
- Label markers (break_up/break_down) added by clicking candles
- Delete tool that removes annotations by clicking near them
- SQLite database storing all annotations with geometry and color
- Next.js 16 app with lightweight-charts for visualization
- shadcn/ui components with dark slate theme
- Local development workflow only

### Constraints
- **No breaking changes**: Existing functionality must remain intact
- **No new dependencies**: Use existing Next.js, React, Tailwind, shadcn/ui stack
- **Single-user application**: No authentication or multi-user considerations
- **SQLite database**: Must maintain compatibility with existing schema
- **Lightweight-charts integration**: Chart library API is fixed, work within SVG overlay pattern
- **Performance**: Chart rendering must maintain 60fps during annotation interactions

### Stakeholders
- **Primary user**: Marko (developer/trader creating training data)
- **Deployment target**: Server environment with Docker support
- **Implementation**: Haiku model must be able to follow the implementation plan

## Goals / Non-Goals

**Goals:**
1. Enable efficient bulk annotation management (delete all labels, delete all lines)
2. Provide visibility into all annotations via sidebar list with search/filter
3. Enable one-click production deployment via Docker
4. Transform UI to distinctive hacker/terminal aesthetic while maintaining usability
5. Create implementation plan detailed enough for Haiku model to execute

**Non-Goals:**
1. Multi-user support or authentication
2. Undo/redo functionality (can be added later)
3. Import/export of individual annotations (CSV export already exists)
4. Real-time collaboration features
5. Mobile responsive design (desktop-focused tool)
6. Internationalization (English only)

## Decisions

### Decision 1: Label Selection Architecture

**Choice**: Use separate state management for label selection parallel to existing line selection

**Why?**
- Lines and labels are fundamentally different (geometry vs point markers)
- Existing line selection in `SvgOverlay.tsx` works well, don't disturb it
- Labels rendered by `CandleChart.tsx` using lightweight-charts markers API
- Parallel state (`selectedLabelId` alongside `selectedLineId`) keeps concerns separated

**Alternatives Considered:**
- **Unified selection system**: Single `selectedAnnotationId` for both lines and labels
  - ❌ Rejected: Would require refactoring working line selection code, higher risk
  - ❌ Different selection behaviors (lines: click geometry, labels: click marker)
- **Event bus pattern**: Pub/sub for selection events
  - ❌ Rejected: Over-engineering for single-user app, adds complexity

**Implementation:**
- Add `selectedLabelId` state in `page.tsx`
- Pass `selectedLabelId` and `setSelectedLabelId` to `CandleChart.tsx`
- Make markers clickable via `onClick` handler in marker creation
- Highlight selected marker with custom scale and color properties
- Deselect on Escape key (global keyboard handler in page component)

### Decision 2: Label List UI Structure

**Choice**: Collapsible section within existing Toolbox sidebar with virtualized scrolling

**Why?**
- Keeps all controls in one place (consistency)
- Toolbox already has vertical space for expansion
- Users may have hundreds/thousands of labels, need efficient rendering
- No need for new layout areas or floating panels

**Alternatives Considered:**
- **Separate right sidebar**: New panel on right side of chart
  - ❌ Rejected: Takes screen real estate from chart, awkward horizontal layout
- **Modal/overlay**: Floating panel over chart
  - ❌ Rejected: Blocks chart view, poor UX for browsing annotations while viewing data
- **Bottom panel**: Horizontal list below chart
  - ❌ Rejected: Vertical list more natural for timestamped items, less vertical space for chart

**Implementation:**
- Add `<Collapsible>` section in Toolbox below tool buttons, above Export
- Section header: "Label Annotations (X)" with expand/collapse icon
- When expanded: search input, filter dropdown, scrollable list (max-height: 400px)
- Each list item: formatted timestamp, colored badge, delete button
- Click item to select/highlight on chart
- Use CSS `overflow-y: auto` with custom scrollbar styling (no virtualization needed initially)
- If performance issues with 1000+ items, add `react-window` in future iteration

### Decision 3: API Design for Bulk Operations

**Choice**: Extend existing DELETE `/api/annotations` with query parameters

**Why?**
- RESTful approach: DELETE resource with filters
- No new endpoints to maintain
- Backwards compatible (no query params = existing single-delete behavior still works via `/api/annotations/[id]`)
- Simple to implement and test

**Query Parameter Schema:**
```
DELETE /api/annotations?type=line           // Delete all lines
DELETE /api/annotations?type=break_up       // Delete all break_up labels
DELETE /api/annotations?type=break_down     // Delete all break_down labels
DELETE /api/annotations?type=break_up,break_down  // Delete all labels
DELETE /api/annotations?all=true            // Delete everything (nuclear option)
```

**Alternatives Considered:**
- **POST /api/annotations/bulk-delete**: Separate endpoint
  - ❌ Rejected: Not RESTful (POST for delete), adds complexity
- **DELETE with request body**: `{ types: ['break_up', 'break_down'] }`
  - ❌ Rejected: DELETE with body is controversial in HTTP semantics, some proxies strip bodies
- **Separate endpoints per type**: `/api/annotations/lines`, `/api/annotations/labels`
  - ❌ Rejected: More endpoints to maintain, inconsistent with current design

**Implementation:**
- Modify `src/app/api/annotations/route.ts` DELETE handler
- Parse query params: `const { type, all } = request.nextUrl.searchParams`
- Use Drizzle ORM with conditional WHERE clause
- Return `{ success: true, deleted: <count> }` for confirmation UI

### Decision 4: Docker Strategy - Standalone Output

**Choice**: Next.js standalone output mode with multi-stage build

**Why?**
- Minimal production bundle (~50MB for Next.js runtime vs ~500MB with full node_modules)
- Fast container builds (cached layers for dependencies)
- Official Next.js recommendation for containerization
- Better-sqlite3 works in standalone mode (native module properly bundled)

**Dockerfile Structure:**
```dockerfile
# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
```

**Alternatives Considered:**
- **Full node_modules copy**: Copy entire node_modules to production
  - ❌ Rejected: 5-10x larger images, slower deployments, unnecessary dev dependencies
- **Distroless base images**: Google distroless/nodejs
  - ❌ Rejected: No shell for debugging, alpine is small enough, better-sqlite3 compatibility unclear
- **Docker layer caching with pnpm/yarn**: Different package manager
  - ❌ Rejected: Project uses npm, no reason to change, npm v7+ has similar caching

**Database Persistence:**
- Mount `/app/data` as Docker volume
- SQLite file at `/app/data/candles.db`
- Named volume in docker-compose: `candle-data:/app/data`

### Decision 5: Theme Implementation - CSS Variables + Tailwind Extension

**Choice**: Replace existing CSS variables in `globals.css` with hacker theme values, extend Tailwind config with custom colors and animations

**Why?**
- Minimal refactoring: existing shadcn/ui components already use CSS variables
- Tailwind extension provides utility classes for new theme features (glow effects, animations)
- No component rewrites needed, just style overrides
- Easy to toggle/revert if needed (swap CSS variable values)

**Color Mapping Strategy:**
```css
/* globals.css - override existing variables */
:root {
  --background: 120 100% 4%;        /* #0a0e0a - very dark green */
  --foreground: 120 100% 50%;       /* #00ff41 - matrix green */
  --primary: 120 100% 50%;          /* #00ff41 */
  --destructive: 348 100% 50%;      /* #ff0040 - neon red */
  --border: 120 100% 10%;           /* #003311 - dim green */
  /* ... map all existing variables to hacker theme equivalents */
}
```

**Tailwind Extension:**
```typescript
// tailwind.config.ts - extend existing config
theme: {
  extend: {
    colors: {
      matrix: '#00ff41',
      matrixDim: '#00cc33',
      matrixDark: '#003311',
      neonRed: '#ff0040',
      neonCyan: '#00d4ff',
      // ... keep existing shadcn colors
    },
    fontFamily: {
      mono: ['JetBrains Mono', 'Fira Code', 'Courier New', 'monospace'],
    },
    boxShadow: {
      'glow-sm': '0 0 8px #00ff41',
      'glow': '0 0 15px #00ff41, 0 0 30px rgba(0,255,65,0.5)',
      'glow-lg': '0 0 20px #00ff41, 0 0 40px rgba(0,255,65,0.5)',
    },
    keyframes: {
      'glow-pulse': {
        '0%, 100%': { boxShadow: '0 0 15px #00ff41' },
        '50%': { boxShadow: '0 0 30px #00ff41, 0 0 50px rgba(0,255,65,0.5)' },
      },
      flicker: {
        '0%, 100%': { opacity: '1' },
        '50%': { opacity: '0.8' },
      },
    },
    animation: {
      'glow-pulse': 'glow-pulse 2s ease-in-out infinite',
      'flicker': 'flicker 0.1s ease-in-out',
    },
  },
}
```

**Alternatives Considered:**
- **Complete rewrite with different UI library**: Styled-components, Emotion
  - ❌ Rejected: Massive effort, no benefit, Tailwind + shadcn works well
- **Theme toggle system**: Support multiple themes with switcher
  - ❌ Rejected: Not in requirements, adds complexity, hacker theme is the goal
- **CSS-in-JS for glow effects**: Inline styles or styled-jsx
  - ❌ Rejected: Inconsistent with existing Tailwind approach, harder to maintain

**Font Loading:**
- Add JetBrains Mono via Google Fonts in `layout.tsx` `<head>`
- Fallback chain: JetBrains Mono → Fira Code → Courier New → system monospace
- Set `font-family: var(--font-mono)` on body element

### Decision 6: Feedback Messages - Toast Component

**Choice**: Create reusable `Toast` component using shadcn/ui toast primitive, styled for terminal aesthetic

**Why?**
- Consistent with existing shadcn/ui architecture
- Already have toast primitive in `components/ui/` (likely from shadcn init)
- Position: top-center, auto-dismiss after 4s
- Terminal-style formatting: `> SUCCESS: Operation completed [3 items]`

**Implementation:**
```typescript
// src/components/ui/toast.tsx - style overrides
// Add terminal-style formatting
className="font-mono border-matrix bg-terminal text-matrix"

// Usage in components:
import { useToast } from '@/hooks/use-toast'
const { toast } = useToast()

toast({
  title: "> SUCCESS",
  description: "Deleted all labels [15 items]",
  variant: "default", // green
})

toast({
  title: "> ERROR",
  description: "Failed to delete annotations [code: 500]",
  variant: "destructive", // red
})
```

**Alternatives Considered:**
- **Custom notification system**: Build from scratch
  - ❌ Rejected: Reinventing the wheel, shadcn toast is battle-tested
- **Browser alert()**: Native dialogs
  - ❌ Rejected: Ugly, blocks UI, no styling, poor UX
- **Console.log only**: No visual feedback
  - ❌ Rejected: User won't see feedback, poor UX

## Risks / Trade-offs

### Risk 1: Theme Accessibility
**Risk**: Neon green on black may strain eyes during extended use, contrast issues for colorblind users

**Mitigation:**
- Ensure WCAG AA contrast ratios (4.5:1 for text, 3:1 for UI elements)
- Use #00ff41 which has sufficient contrast on #0a0e0a background
- Provide option to revert theme in future (environment variable: `THEME=classic`)
- Include prefers-reduced-motion support to disable animations

**Trade-off**: Distinctive aesthetic vs universal accessibility (accepting some users may prefer different theme)

### Risk 2: Label List Performance with Large Datasets
**Risk**: 10,000+ labels may cause slow rendering and sluggish scrolling in sidebar list

**Mitigation:**
- Set reasonable max-height (400px) for scrollable area
- If performance issues arise, add pagination or react-window virtualization in follow-up
- Monitor performance during development with test data (1000, 5000, 10000 labels)

**Trade-off**: Simple initial implementation vs premature optimization (YAGNI principle - add virtualization only if needed)

### Risk 3: Docker Image Size for Better-SQLite3
**Risk**: Native SQLite module may require additional build dependencies in alpine, increasing image size

**Mitigation:**
- Node:18-alpine includes necessary build tools (python, make, g++)
- Better-sqlite3 compiles during npm install in build stage
- Final image only includes compiled binary, not build tools
- Test build locally: `docker build --progress=plain .` to verify size (<200MB target)

**Trade-off**: Alpine convenience vs potential build complexity (alpine is still best choice despite native modules)

### Risk 4: Breaking Existing Line Selection
**Risk**: Adding label selection state and keyboard handlers may interfere with existing line selection logic

**Mitigation:**
- Keep line and label selection completely separate (different state variables)
- Keyboard handler checks both states: if label selected, delete label; if line selected, delete line
- Thoroughly test all existing line operations (draw, select, drag, delete) after changes
- Use TypeScript strict mode to catch state management issues

**Trade-off**: Duplicate code for selection logic vs refactoring working code (choose stability)

### Risk 5: Next.js Standalone Mode Compatibility
**Risk**: Standalone output may not include all necessary files (static assets, environment configs)

**Mitigation:**
- Follow official Next.js documentation for standalone mode
- Explicitly copy `.next/static/` and `public/` directories in Dockerfile
- Test docker build locally before committing
- Verify all pages, API routes, and static assets work in container

**Trade-off**: Smaller image size vs potential missing files (standalone is well-tested by community)

### Risk 6: Confirmation Dialog UX
**Risk**: Users may accidentally confirm bulk delete operations

**Mitigation:**
- Use clear, explicit confirmation messages: "Delete all X annotations? This cannot be undone."
- Require deliberate click on "Confirm" button (not Enter key, no auto-focus)
- Show count of items to be deleted in confirmation message
- Use destructive button styling (red) to signal danger
- No undo system (out of scope), but users can re-annotate from CSV data

**Trade-off**: Safety vs speed (prioritize safety for destructive operations)

## Migration Plan

### Phase 1: Label Management (No Deployment Impact)
1. Add `selectedLabelId` state and selection handlers in `CandleChart.tsx`
2. Build label list UI in `Toolbox.tsx` (collapsible section)
3. Implement search/filter functionality
4. Add keyboard delete handler for labels
5. Test with existing database, no schema changes
6. **Deployment**: None (dev only), commit after testing

### Phase 2: API Extensions (Backwards Compatible)
1. Modify `DELETE /api/annotations` to accept query params
2. Add bulk delete logic with Drizzle ORM
3. Create `GET /api/health` endpoint
4. Test bulk operations with Postman/curl
5. **Deployment**: None (API changes backwards compatible), commit after testing

### Phase 3: Hacker Theme (Visual Only)
1. Load JetBrains Mono font in `layout.tsx`
2. Update `globals.css` with new CSS variables
3. Extend `tailwind.config.ts` with custom colors, shadows, animations
4. Apply theme classes to existing components (Toolbox, buttons, inputs)
5. Test visual appearance and contrast ratios
6. **Deployment**: None (CSS/styling only), commit after visual review

### Phase 4: Docker Setup (New Deployment Path)
1. Update `next.config.js` to enable standalone output
2. Create `Dockerfile` with multi-stage build
3. Create `docker-compose.yml` with volume configuration
4. Create `.dockerignore` and `.env.example`
5. Test local build: `docker-compose up --build`
6. Verify database persistence across container restarts
7. Update `DEPLOYMENT.md` with Docker instructions
8. **Deployment**: Push image to registry, deploy to production server

### Rollback Strategy
- **Label Management**: No rollback needed (additive feature, disable by not using)
- **API Extensions**: Backwards compatible, no rollback needed
- **Hacker Theme**: Revert `globals.css` and `tailwind.config.ts` commits
- **Docker**: Rollback to direct Node.js deployment, use existing dev workflow

### Testing Checklist
- [ ] All existing line drawing features work unchanged
- [ ] Label selection highlights correct marker on chart
- [ ] Label list displays all annotations with correct formatting
- [ ] Search/filter correctly narrows label list
- [ ] Delete individual label removes from chart and list
- [ ] Delete all labels removes all markers after confirmation
- [ ] Bulk delete API endpoints return correct counts
- [ ] Health check endpoint returns 200
- [ ] Theme maintains WCAG AA contrast ratios
- [ ] All text uses monospace font
- [ ] Glow effects appear on hover/active states
- [ ] Docker container starts successfully
- [ ] Database persists across container restarts
- [ ] Application accessible on http://localhost:3000 in container

## Open Questions

1. **Should we add label editing (change type)?** 
   - Not in current scope, but consider for future
   - Would require modal dialog to change break_up ↔ break_down

2. **Should label list show price information?**
   - Specs don't mention it, but could be useful
   - Decision: Show timestamp and type only initially, add price in follow-up if requested

3. **Should we limit the number of labels displayed in sidebar?**
   - Pagination vs infinite scroll vs show all
   - Decision: Show all initially, add pagination only if performance issues arise

4. **Should Docker image include sample CSV data?**
   - Useful for testing, but increases image size
   - Decision: No, keep image minimal, provide sample CSV in repo documentation

5. **Should we add keyboard shortcuts for tool switching (e.g., 'L' for line tool)?**
   - Not in requirements, but could enhance UX
   - Decision: Out of scope for this change, consider in future UX iteration

These questions do not block implementation - proceed with spec-defined behavior and defer enhancements.
