239 lines
9.6 KiB
YAML
239 lines
9.6 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 + DaisyUI
|
|
- **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)
|
|
|
|
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
|