diff --git a/CLAUDE.md b/CLAUDE.md index 0046ac0..933b20b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,3 +1,1024 @@ +# Work Order System — Build TODO +> Hand this file to Claude Code. All frontend files use `.mjs` extensions. +> Stack: Go · Pure JS + Web Components · SQL Server · Docker + +--- + +## Table of Contents +- [Design System](#design-system) +- [Project Structure](#project-structure) +- [Phase 1 — Foundation](#phase-1--foundation) +- [Phase 2 — Field Features](#phase-2--field-features) +- [Phase 3 — Integrations & Admin](#phase-3--integrations--admin) +- [Phase 4 — Polish & Optimization](#phase-4--polish--optimization) +- [Component Inventory](#component-inventory) +- [API Endpoints](#api-endpoints) +- [Database Schema](#database-schema) +- [Conventions](#conventions) + +--- + +## Design System + +### Color Palette +```css +:root { + /* Brand */ + --navy: #0D2137; /* Primary dark — sidebar, headers */ + --teal: #0A7EA4; /* Primary accent — buttons, links, active states */ + --teal-lt: #14B8D4; /* Light accent — hover states, highlights */ + --teal-dk: #075E7A; /* Dark accent — pressed states */ + + /* Surfaces */ + --bg: #F0F6FA; /* Page background */ + --surface: #FFFFFF; /* Cards, panels */ + --surface-2: #E8F0F5; /* Inset areas, table stripes */ + --sidebar-bg: #0D2137; /* Sidebar background */ + --sidebar-hover: #153248; + --sidebar-active: #0A7EA4; + + /* Text */ + --text: #1A2E3B; /* Primary text */ + --text-muted: #64748B; /* Secondary / helper text */ + --text-inv: #FFFFFF; /* Text on dark backgrounds */ + + /* Semantic */ + --success: #1D9D6C; + --warning: #E07B39; + --danger: #C0392B; + --info: #0A7EA4; + + /* Borders & Shadows */ + --border: #D1DDE6; + --border-lt: #E8F0F5; + --shadow-sm: 0 1px 3px rgba(0,0,0,.08); + --shadow-md: 0 4px 12px rgba(0,0,0,.10); + --shadow-lg: 0 8px 24px rgba(0,0,0,.12); + + /* Status Pills */ + --status-draft: #94A3B8; + --status-assigned: #0A7EA4; + --status-scheduled: #8B5CF6; + --status-in_progress: #E07B39; + --status-pending_review: #D97706; + --status-closed: #1D9D6C; + + /* Priority */ + --priority-low: #64748B; + --priority-normal: #0A7EA4; + --priority-high: #E07B39; + --priority-urgent: #C0392B; + + /* Spacing */ + --radius-sm: 4px; + --radius: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + + /* Sidebar width */ + --sidebar-w: 260px; + --sidebar-collapsed: 64px; +} +``` + +### Typography +Load via `` in `index.html` — no build step needed: +```html + + + +``` + +```css +:root { + --font-body: 'Inter', 'Segoe UI', system-ui, sans-serif; + --font-mono: 'JetBrains Mono', 'Cascadia Code', monospace; + + --text-xs: 0.70rem; /* 11px — labels, caps */ + --text-sm: 0.813rem; /* 13px — helper, meta */ + --text-base: 0.938rem; /* 15px — body */ + --text-md: 1.063rem; /* 17px — subheadings */ + --text-lg: 1.25rem; /* 20px — section headers */ + --text-xl: 1.5rem; /* 24px — page titles */ + --text-2xl: 2rem; /* 32px — dashboard hero numbers */ + + --weight-normal: 400; + --weight-medium: 500; + --weight-semibold: 600; + --weight-bold: 700; +} +``` + +### Component Design Patterns +- Cards: white background, `var(--border)` border, `var(--radius)` corners, `var(--shadow-sm)` +- Buttons: filled primary = `--teal`, ghost = transparent + `--teal` border, danger = `--danger` +- Inputs: `--border` border, focus ring `--teal` 2px outline-offset, `--radius-sm` corners +- Tables: header row `--surface-2`, alternating rows, sticky header on scroll +- Status pills: colored dot + label, pill shape, light background tint of the status color +- Icon + label pattern everywhere — use Lucide icons loaded via CDN (no npm) + +### Icons +```html + + +``` +Call `lucide.createIcons()` after each render. Use named icons: +`clipboard-list`, `users`, `truck`, `wrench`, `map-pin`, `camera`, `file-invoice`, +`layout-dashboard`, `settings`, `bell`, `chevron-left`, `plus`, `search`, `filter` + +--- + +## Project Structure + +``` +workorder/ +├── CLAUDE.md ← !! READ FIRST — conventions for Claude Code +├── cmd/server/main.go +├── internal/ +│ ├── api/ +│ │ ├── router.go +│ │ ├── middleware/ +│ │ │ ├── auth.go +│ │ │ ├── cors.go +│ │ │ └── logger.go +│ │ └── handlers/ +│ │ ├── auth.go +│ │ ├── workorder.go +│ │ ├── step.go +│ │ ├── resource.go +│ │ ├── attachment.go +│ │ ├── accounting.go +│ │ ├── user.go +│ │ ├── registry.go ← people/vehicle/equipment/material master lists +│ │ ├── dashboard.go +│ │ └── report.go +│ ├── service/ +│ │ ├── workorder.go +│ │ ├── notification.go +│ │ ├── spatial.go +│ │ └── export.go ← CSV/Excel export +│ ├── repository/ +│ │ ├── db.go +│ │ ├── workorder.go +│ │ ├── step.go +│ │ ├── resource.go +│ │ ├── attachment.go +│ │ ├── accounting.go +│ │ ├── user.go +│ │ └── registry.go +│ ├── model/ +│ │ ├── workorder.go +│ │ ├── step.go +│ │ ├── resource.go +│ │ ├── attachment.go +│ │ ├── accounting.go +│ │ ├── user.go +│ │ └── dashboard.go +│ └── config/config.go +│ +├── web/ ← All frontend — served as static files by Go +│ ├── index.html ← App shell, loads fonts, Lucide, Leaflet +│ ├── app.mjs ← custom element + client router +│ │ +│ ├── components/ +│ │ ├── layout/ +│ │ │ ├── app-sidebar.mjs ← Left nav — collapsible, mobile drawer +│ │ │ ├── app-topbar.mjs ← Top bar — breadcrumb, notifications bell, user avatar +│ │ │ ├── app-root.mjs ← Shell that wires sidebar + topbar +
+│ │ │ └── app-mobile-nav.mjs ← Bottom tab bar for mobile (≤768px) +│ │ │ +│ │ ├── work-orders/ +│ │ │ ├── wo-list.mjs ← Searchable, filterable WO list +│ │ │ ├── wo-kanban.mjs ← Kanban board view (by status column) +│ │ │ ├── wo-form.mjs ← Create / edit full form +│ │ │ ├── wo-detail.mjs ← Read-only detail — tabs for each section +│ │ │ ├── wo-checklist.mjs ← Step checklist with check-off + progress bar +│ │ │ ├── wo-resource-panel.mjs← Assign people, vehicles, equipment, materials +│ │ │ ├── wo-photo-panel.mjs ← Photo gallery, capture, before/during/after +│ │ │ ├── wo-map.mjs ← Leaflet map + directions button +│ │ │ ├── wo-accounting.mjs ← GL, cost center, WBS, billing ref fields +│ │ │ ├── wo-timeline.mjs ← Audit/activity log feed +│ │ │ └── wo-print.mjs ← Print-friendly layout for field packets +│ │ │ +│ │ ├── dashboard/ +│ │ │ ├── dash-root.mjs ← Dashboard page shell +│ │ │ ├── dash-kpi-card.mjs ← Reusable stat card (number + trend + icon) +│ │ │ ├── dash-status-chart.mjs← Doughnut chart — WOs by status +│ │ │ ├── dash-priority-bar.mjs← Bar chart — WOs by priority +│ │ │ └── dash-recent-feed.mjs ← Recent activity feed +│ │ │ +│ │ ├── registry/ +│ │ │ ├── people-list.mjs ← Manage crew / technician records +│ │ │ ├── people-form.mjs +│ │ │ ├── vehicle-list.mjs ← Manage fleet / vehicles +│ │ │ ├── vehicle-form.mjs +│ │ │ ├── equipment-list.mjs ← Manage tools & equipment +│ │ │ ├── equipment-form.mjs +│ │ │ ├── material-list.mjs ← Manage materials / inventory +│ │ │ └── material-form.mjs +│ │ │ +│ │ ├── users/ +│ │ │ ├── user-list.mjs ← User management (admin only) +│ │ │ ├── user-form.mjs ← Create / edit user, assign role +│ │ │ └── user-profile.mjs ← Current user profile + password change +│ │ │ +│ │ ├── reports/ +│ │ │ ├── report-root.mjs ← Reports landing page +│ │ │ ├── report-by-status.mjs +│ │ │ ├── report-by-cost.mjs +│ │ │ └── report-export.mjs ← CSV / Excel download triggers +│ │ │ +│ │ └── shared/ +│ │ ├── ui-badge.mjs ← — status + priority pills +│ │ ├── ui-button.mjs ← — primary/ghost/danger variants +│ │ ├── ui-card.mjs ← — surface container +│ │ ├── ui-dialog.mjs ← — modal with backdrop +│ │ ├── ui-drawer.mjs ← — slide-in panel (mobile forms) +│ │ ├── ui-toast.mjs ← — success/error notifications +│ │ ├── ui-spinner.mjs ← — loading state +│ │ ├── ui-empty.mjs ← — empty state illustration + CTA +│ │ ├── ui-confirm.mjs ← — "Are you sure?" dialog +│ │ ├── ui-search.mjs ← — debounced search input +│ │ ├── ui-tabs.mjs ← — tab bar + panels +│ │ ├── ui-avatar.mjs ← — initials or photo avatar +│ │ └── ui-tooltip.mjs ← — hover tooltip +│ │ +│ ├── lib/ +│ │ ├── api.mjs ← Fetch wrapper, auth header, error handling +│ │ ├── router.mjs ← Hash/history client router +│ │ ├── store.mjs ← Reactive state (lightweight signal pattern) +│ │ ├── auth.mjs ← JWT storage, decode, role checks +│ │ ├── format.mjs ← Date, currency, phone formatters +│ │ ├── validate.mjs ← Form field validators +│ │ └── utils.mjs ← Misc helpers, debounce, deepMerge +│ │ +│ └── styles/ +│ ├── global.css ← CSS custom properties (design tokens above) +│ ├── reset.css ← Modern CSS reset +│ ├── typography.css ← Base font rules +│ ├── forms.css ← Shared input/select/textarea styles +│ ├── tables.css ← Shared table styles +│ └── print.css ← Print overrides for wo-print.mjs +│ +├── migrations/ +│ ├── 001_initial.sql +│ ├── 002_resources.sql +│ ├── 003_attachments.sql +│ ├── 004_accounting.sql +│ ├── 005_users_roles.sql +│ └── 006_audit_log.sql +│ +├── uploads/ ← Bind-mounted in Docker +├── Dockerfile +├── docker-compose.yml +├── .env.example +└── go.mod +``` + +--- + +## Phase 1 — Foundation +**Goal:** Running app with shell, sidebar, auth, and WO CRUD. + +### 1.1 CLAUDE.md (create first) +- [ ] Document `.mjs` extension convention for all frontend JS modules +- [ ] Document Go conventions: package names, error wrapping, named DB params +- [ ] Document CSS convention: always use design token vars, never hardcoded hex +- [ ] Document component convention: Shadow DOM, `#private` fields, custom events +- [ ] List all CDN dependencies and their globals (`L` for Leaflet, `lucide`, `Chart`) + +### 1.2 Go Project Bootstrap +- [ ] `go mod init github.com/yourorg/workorder` +- [ ] Add dependencies: `chi/v5`, `sqlx`, `go-mssqldb`, `golang-jwt/jwt/v5`, `google/uuid`, `joho/godotenv` +- [ ] `internal/config/config.go` — load from env: `ADDR`, `DB_DSN`, `JWT_SECRET`, `UPLOAD_PATH`, `BASE_URL` +- [ ] `internal/repository/db.go` — `sqlx.Connect`, pool settings (max open 25, max idle 5, lifetime 5min) +- [ ] `cmd/server/main.go` — wire config → db → router → `http.ListenAndServe` + +### 1.3 Database — Migration 001 +```sql +-- work_orders table (full schema as planned) +-- Computed wo_number column: 'WO-' + zero-padded id +-- status CHECK constraint +-- priority CHECK constraint +-- Indexes on status, parent, scheduled_start +``` + +### 1.4 Auth +- [ ] `migrations/005_users_roles.sql` + ```sql + CREATE TABLE users ( + id INT IDENTITY PRIMARY KEY, + username NVARCHAR(100) NOT NULL UNIQUE, + email NVARCHAR(200) NOT NULL UNIQUE, + display_name NVARCHAR(200), + password_hash NVARCHAR(200) NOT NULL, -- bcrypt + role NVARCHAR(30) NOT NULL DEFAULT 'viewer', + -- admin | dispatcher | field_tech | viewer + avatar_url NVARCHAR(500), + active BIT NOT NULL DEFAULT 1, + last_login DATETIME2, + created_at DATETIME2 NOT NULL DEFAULT GETUTCDATE() + ); + -- Seed one admin user + ``` +- [ ] `POST /api/auth/login` — bcrypt compare, return `{ token, user }` with 8hr JWT +- [ ] `POST /api/auth/refresh` — accepts valid token, returns new token +- [ ] `GET /api/auth/me` — current user from token claims +- [ ] JWT middleware: attach user to `context.Context`, return 401 JSON on failure +- [ ] Role helper: `RequireRole(roles ...string)` middleware + +### 1.5 Work Order Backend (CRUD) +- [ ] `model/workorder.go` — `WorkOrder`, `WorkOrderListItem`, `WorkOrderDetail` structs with `db:` and `json:` tags +- [ ] `repository/workorder.go` + - `List(ctx, filters)` — status, search, priority, parentType, page/limit + - `GetByID(ctx, id)` — single WO + - `Create(ctx, wo)` — insert + return generated ID + - `Update(ctx, wo)` — partial update, always set `updated_at = GETUTCDATE()` + - `UpdateStatus(ctx, id, status, userID)` — transition + audit log insert + - `Delete(ctx, id)` — soft delete (add `deleted_at` column) + - `GetDetail(ctx, id)` — joins WO + steps + resources + attachments + accounting in one call +- [ ] Handlers: `List`, `Get`, `Create`, `Update`, `Delete`, `UpdateStatus` +- [ ] Paginated response: `{ data: [...], meta: { page, per_page, total } }` + +### 1.6 Frontend Shell +- [ ] `web/index.html` + - Load Google Fonts (Inter + JetBrains Mono) + - Load Lucide CDN + - Load Leaflet CSS + JS CDN + - Load Chart.js CDN + - ` + + + + + + + +``` + +--- + +*Start with Phase 1 in order. Each checkbox is one commit. Don't skip CLAUDE.md — it must exist before any code is written.* + +--- + # Work Order System — Technical Build Plan **Stack:** Go (backend API) · Pure JavaScript + Web Components (frontend) · SQL Server (MSSQL) · Docker