Files
headroom/openspec/config.yaml
Santhosh Janardhanan 96f1d0a6e5 feat(dashboard): Enhance dashboard with PageHeader, StatCard, and auth fixes
- Create PageHeader component with title, description, and action slots
- Create StatCard component with trend indicators and icons
- Update dashboard with KPI cards, Quick Actions, and Allocation Preview
- Polish login page with branding and centered layout
- Fix auth redirect: authenticated users accessing /login go to dashboard
- Fix page refresh: auth state persists, no blank page
- Fix sidebar: visible after login, toggle works, state persists
- Fix CSS import: add app.css to layout, fix DaisyUI import path
- Fix breadcrumbs: home icon links to /dashboard
- Add comprehensive E2E and unit tests

Refs: openspec/changes/p03-dashboard-enhancement
Closes: p03-dashboard-enhancement
2026-02-18 18:14:57 -05:00

309 lines
13 KiB
YAML

schema: spec-driven
# Project context - shown to AI when creating artifacts
# This provides essential context about the Headroom project
techstack: |
## Backend (Laravel API)
- **Framework:** Laravel 12 (latest) with PHP 8.4
- **Database:** PostgreSQL (latest, Alpine container)
- **Caching:** Redis (latest, Alpine container) - query + response caching
- **Authentication:** JWT (tymon/jwt-auth package)
- **API Design:** REST with Laravel API Resources
- **API Documentation:** Laravel Scribe (auto-generates SwaggerUI)
- **Testing:** PHPUnit (unit) + Pest (feature)
- **Code Style:** PSR-12, Laravel conventions
- **Container:** Docker (port 3000)
## Frontend (SvelteKit)
- **Framework:** SvelteKit (latest) with Svelte 5
- **Styling:** Tailwind CSS 4 + DaisyUI 5
- **Icons:** Lucide Svelte (modern icon library)
- **Charts:** Recharts
- **Tables:** TanStack Table (React Table for Svelte)
- **Forms:** Superforms + Zod + SvelteKit Form Actions
- **State Management:** Svelte stores (minimal - UI state only)
- **HTTP Client:** Native fetch (no Axios)
- **Testing:** Vitest (unit) + Playwright (E2E)
- **Container:** Docker (port 5173)
## Infrastructure
- **Local Dev:** Docker Compose with code-mounted volumes (hot reload)
- **Reverse Proxy:** Nginx Proxy Manager (existing)
- **Database Volume:** Mounted to ./data/postgres
- **Cache Volume:** Mounted to ./data/redis
- **Secrets:** .env files (all environments)
conventions: |
## Code Style Standards
### Backend (Laravel)
- Follow PSR-12 coding standards
- Use Laravel Pint for linting
- Use PHPStan (level 5+) for static analysis
- Use Laravel conventions for naming (camelCase methods, snake_case DB columns)
- Use API Resources for consistent JSON responses
- Use Form Requests for validation
- Use Policies for authorization
- Use UUIDs for primary keys (prevents ID enumeration)
### Frontend (SvelteKit)
- Use Prettier for formatting
- Use ESLint with Svelte plugin
- Use TypeScript strict mode
- Use SvelteKit file-based routing conventions
- Use $lib alias for imports from src/lib
- Use Zod schemas for validation (shared between frontend and API contracts)
## Git Conventions
- **Branch naming:** `feature/opsx-<change-name>` for OpenSpec changes
- **Commit format:**
```
[Type] Brief description (50 chars max)
Detailed explanation (optional, 72 char wrap)
Refs: openspec/changes/<change-name>
```
- **Types:** feat, fix, refactor, test, docs, chore
- **Granular commits:** One fix = one commit
## API Conventions
- RESTful endpoints with standard HTTP verbs
- Response format: `{ "data": {}, "meta": {}, "links": {} }`
- Error format: `{ "message": "...", "errors": {} }`
- Cache keys pattern: `allocations:month:{YYYY-MM}`, `reports:forecast:{from}:{to}:{hash}`
- TTL: 1 hour (allocations), 15 min (reports), 24 hours (master data)
development_strategy:
approach: "Spec-Driven Development (SDD) + Test-Driven Development (TDD) Hybrid"
description: |
Every capability follows a 4-phase cycle:
## Phase 1: SPEC → TEST (Red Phase)
- Read scenarios from specs/<capability>/spec.md
- Write E2E tests (Playwright) - mark as test.fixme()
- Write API tests (Pest) - mark as ->todo()
- Write unit tests (Pest/Vitest) - mark as ->todo() or test.skip()
- Write component tests (Vitest) - mark as test.skip()
- Commit: "test(<capability>): Add pending tests for all scenarios"
## Phase 2: IMPLEMENT (Green Phase)
- Remove skip/todo marker from one test
- Write MINIMAL code to make it pass
- Run test suite (npm run test, php artisan test, npx playwright test)
- Commit when green: "feat(<capability>): Implement <scenario>"
- Repeat for all scenarios
## Phase 3: REFACTOR (Clean Phase)
- Review for code smells, duplication, performance
- Refactor with confidence (tests guard against regression)
- Run full test suite
- Commit: "refactor(<capability>): <improvement description>"
## Phase 4: DOCUMENT
- Generate API docs: php artisan scribe:generate
- Verify all tests pass
- Commit: "docs(<capability>): Update API documentation"
test_granularity: "Every spec scenario gets a test"
test_organization: "Mirror current structure"
test_types:
- E2E: Playwright tests for critical user journeys
- API: Pest Feature tests for all endpoints
- Unit: Pest/Vitest for internal methods and business logic
- Component: Vitest + Testing Library for Svelte components
pending_markers:
php: "->todo()"
playwright: "test.fixme()"
vitest: "test.skip()"
test_naming:
format: "Descriptive - mirror spec scenario intent"
examples:
- "authenticates user with valid credentials and issues JWT tokens"
- "returns 401 when credentials are invalid"
- "rotates refresh token on each refresh request"
coverage_target: ">70%"
regression_strategy: "Every test is a regression test - run full suite on every PR"
scripts:
backend:
test: "pest"
"test:unit": "pest --filter=Unit"
"test:feature": "pest --filter=Feature"
"test:coverage": "pest --coverage --min=70"
"test:todo": "pest --filter=todo"
lint: "pint"
"lint:fix": "pint --fix"
analyse: "phpstan analyse --level=5"
docs: "scribe:generate"
frontend:
test: "vitest run"
"test:watch": "vitest"
"test:ui": "vitest --ui"
"test:e2e": "playwright test"
"test:e2e:ui": "playwright test --ui"
"test:all": "npm run test && npm run test:e2e"
lint: "eslint ."
"lint:fix": "eslint . --fix"
format: "prettier --check ."
"format:fix": "prettier --write ."
rules:
# Project-level standing instructions (from decision-log.md)
all_changes:
- "Every change must follow SDD+TDD: specs → pending tests → implementation → refactor"
- Every spec scenario must have corresponding tests (E2E, API, Unit, Component)
- Pending tests must be committed before implementation (red phase)
- Changes must end with code review for style, standards, and security
- Verification (/opsx-verify) must check for uncovered code (code not tested)
- Commits must be granular (one scenario = one commit)
- Code coverage must be >70% (enforced in /opsx-verify)
- All tests must pass before merge
- Zero linting errors (Laravel Pint, ESLint, Prettier)
- API documentation must be up-to-date (Scribe generation)
# Documentation Standards
documentation:
- API documentation (Scribe annotations) is MANDATORY for all controllers
- Every endpoint must have @group, @authenticated (if protected), @response annotations
- Update docs/ when making significant decisions (decision-log.md, architecture.md)
- Document new dependencies in both config.yaml techstack AND design.md
- UI decisions go in decision-log.md → "UI Layout Decisions" section
- Architecture changes go in architecture.md → relevant section
# Workflow Loops
workflow:
- "Follow capability-based workflow: Test → Implement → Refactor → Document"
- Do NOT skip phases - each phase has a specific commit
- Run full test suite after EACH implementation commit
- Fix failing tests before moving to next scenario
- API documentation (Scribe) is generated in Phase 4 (Document)
- Loop through scenarios one at a time (not all at once)
# UI Standards (70% data-dense, 30% utilitarian)
ui_standards:
- Use Lucide Svelte for ALL icons (no inline SVGs, no other icon libraries)
- DaisyUI-first approach - use DaisyUI components before building custom
- "Sidebar pattern: Collapsible (expanded ↔ collapsed ↔ hidden)"
- Global month selector in top bar (affects all views)
- Light mode default, dark mode available via toggle
- "Table density: Use table-compact for data-heavy views"
- "Reference apps: Obsidian (minimal chrome) + Jira (hierarchical sidebar)"
# Component Patterns
component_patterns:
- "layout: AppLayout.svelte -> Main wrapper with sidebar + content area"
- "layout: Sidebar.svelte -> Collapsible navigation with sections"
- "layout: TopBar.svelte -> Breadcrumbs, month selector, user menu"
- "layout: Breadcrumbs.svelte -> Auto-generated from route"
- "layout: PageHeader.svelte -> Page title + action buttons slot"
- "state: layoutStore -> sidebarState ('expanded'|'collapsed'|'hidden'), theme"
- "state: periodStore -> selectedMonth (global YYYY-MM format)"
- "state: Persist user preferences to localStorage"
- "navigation: Sections -> PLANNING, REPORTS, ADMIN"
- "navigation: ADMIN section visible only to superuser role"
- "navigation: Active route highlighting required"
# Accessibility Requirements
accessibility:
- "Keyboard navigation: Tab through sidebar, Enter/Space to activate"
- Escape to close mobile drawer
- "Cmd/Ctrl + \ to toggle sidebar (desktop)"
- "ARIA: aria-expanded on sidebar toggle, aria-current='page' on active nav"
- Focus trap in mobile drawer
- Focus restored on drawer close
- All form inputs must have associated labels
# Responsive Design
responsive:
- "≥1280px (xl): Sidebar expanded by default, manual toggle"
- "1024-1279px (lg): Sidebar collapsed by default, manual toggle"
- "768-1023px (md): Sidebar hidden, hamburger menu (drawer overlay)"
- "<768px (sm): Sidebar hidden, hamburger menu (drawer overlay)"
- "Mobile drawer: Full-height overlay with backdrop"
- Close drawer on route change (mobile)
# State Management Patterns
state_management:
- Use Svelte stores for UI state only (not business data)
- Business data comes from API (no client-side caching beyond DaisyUI)
- "Stores: auth, layout, period"
- "localStorage keys: headroom_access_token, headroom_refresh_token, headroom_sidebar_state, headroom_theme"
- Store files go in src/lib/stores/
proposal:
- Include clear Goals and Non-Goals sections
- Reference the 4 personas (Superuser, Manager, Developer, Top Brass)
- Align with monthly capacity planning workflow
- Include data validation rules for any new entities
specs:
- Document all validation rules explicitly
- Include RBAC permissions for each operation
- Define error scenarios and expected responses
- Reference existing data model (team_members, projects, allocations, actuals)
- Use YYYY-MM format for month references
- Each scenario must be testable (clear GIVEN/WHEN/THEN)
design:
- Include database schema changes (migrations needed)
- Define API endpoints with request/response examples
- Specify caching strategy (keys, TTL, invalidation rules)
- Include UI/UX considerations for SvelteKit + DaisyUI
- Document any new dependencies
- Document test approach for each capability
tasks:
- Organize by capability (not by layer)
- "Each capability has 4 phases: Test (Red) → Implement (Green) → Refactor → Document"
- Break implementation into individual scenarios
- Include explicit test tasks (write pending, enable one by one)
- Include API documentation updates as tasks
- Order capabilities by dependency and business priority
# Domain knowledge
context: |
## Project Overview
Headroom is a resource planning and capacity management tool for engineering managers.
It replaces error-prone spreadsheets with structured capacity planning, resource allocation,
and utilization tracking.
## Core Workflow (Monthly Cycle)
1. **Capacity Planning** - Define team availability (holidays, PTO, working days)
2. **Project Setup** - Track projects through lifecycle with approved estimates
3. **Resource Allocation** - Allocate hours per person per project per month
4. **Actuals Tracking** - Log actual hours worked and compare to planned
## Personas & Permissions
- **Superuser:** Full access (setup, config, all projects, all teams)
- **Manager:** Create/edit own projects, allocate own team, view all projects read-only
- **Developer:** View own allocations, log own hours, view assigned projects
- **Top Brass:** View all reports read-only (forecasts, utilization, costs)
## Key Business Rules
- Availability: 0 (unavailable), 0.5 (half day), 1.0 (full day)
- Project allocation indicators: GREEN (100% ±5%), YELLOW (<95%), RED (>105%)
- Monthly aggregate for actuals (not daily)
- Untracked resource for external team time (not billed)
- Validation: Cannot allocate to "Done" or "Cancelled" projects
## Data Model Summary
- team_members: id (UUID), name, role_id, hourly_rate, active
- projects: id (UUID), code, title, status_id, type_id, approved_estimate, forecasted_effort (JSON)
- allocations: id (UUID), project_id, team_member_id, month (YYYY-MM), allocated_hours
- actuals: id (UUID), project_id, team_member_id, month (YYYY-MM), hours_logged
- roles, project_statuses, project_types: Master data tables
- holidays, ptos: Calendar data
## Deferred to Phase 2
- Real-time notifications (WebSocket)
- PDF/CSV exports
- Background jobs (Laravel Queue)
- Audit logging
- Multi-tenancy
- Time-tracking tool integration