From 54df6018f5720892e6cd1c2dabece0e24c9302ac Mon Sep 17 00:00:00 2001 From: Santhosh Janardhanan Date: Tue, 17 Feb 2026 10:42:32 -0500 Subject: [PATCH] strategy change to TDD --- .slim/cartography.json | 32 + codemap.md | 19 + devnotes.md | 466 ++++++ openspec/changes/codemap.md | 19 + .../changes/headroom-foundation/codemap.md | 19 + openspec/changes/headroom-foundation/tasks.md | 1420 +++++++++++++---- openspec/codemap.md | 19 + openspec/config.yaml | 252 ++- openspec/templates/PestFeatureTest.php | 100 ++ openspec/templates/PestUnitTest.php | 92 ++ openspec/templates/PlaywrightE2ETest.spec.ts | 137 ++ .../templates/VitestComponentTest.test.ts | 174 ++ openspec/templates/VitestUnitTest.test.ts | 205 +++ 13 files changed, 2620 insertions(+), 334 deletions(-) create mode 100644 .slim/cartography.json create mode 100644 codemap.md create mode 100644 openspec/changes/codemap.md create mode 100644 openspec/changes/headroom-foundation/codemap.md create mode 100644 openspec/codemap.md create mode 100644 openspec/templates/PestFeatureTest.php create mode 100644 openspec/templates/PestUnitTest.php create mode 100644 openspec/templates/PlaywrightE2ETest.spec.ts create mode 100644 openspec/templates/VitestComponentTest.test.ts create mode 100644 openspec/templates/VitestUnitTest.test.ts diff --git a/.slim/cartography.json b/.slim/cartography.json new file mode 100644 index 00000000..10c74d51 --- /dev/null +++ b/.slim/cartography.json @@ -0,0 +1,32 @@ +{ + "metadata": { + "version": "1.0.0", + "last_run": "2026-02-17T15:00:03.799320Z", + "root": "C:\\dev\\kimi-headroom", + "include_patterns": [ + "**/*.ts", + "**/*.json", + "**/*.yaml", + "**/*.yml", + "**/*.js" + ], + "exclude_patterns": [ + "**/*.test.ts", + "**/dist/**", + "**/node_modules/**", + "**/*.min.js", + "**/*.map" + ], + "exceptions": [] + }, + "file_hashes": { + "openspec\\changes\\headroom-foundation\\.openspec.yaml": "cafa573d0d11cc3531e4cbdb09aea2a6", + "openspec\\config.yaml": "63c26766698dd49488b53c274bfec0f9" + }, + "folder_hashes": { + "openspec/changes": "", + "openspec/changes/headroom-foundation": "", + ".": "072f78e51abbd298a4f984fc2d143028", + "openspec": "" + } +} \ No newline at end of file diff --git a/codemap.md b/codemap.md new file mode 100644 index 00000000..c22fc239 --- /dev/null +++ b/codemap.md @@ -0,0 +1,19 @@ +# kimi-headroom/ + + + +## Responsibility + + + +## Design + + + +## Flow + + + +## Integration + + diff --git a/devnotes.md b/devnotes.md index f516b3a6..9301ce3a 100644 --- a/devnotes.md +++ b/devnotes.md @@ -894,3 +894,469 @@ Just say the word when you've reviewed everything, and we can: - Adjust anything that needs tweaking - Start implementation with /opsx-apply headroom-foundation Take your time β€” good planning now saves endless rework later. Sleep well! πŸŒ™ + +## LATE IDEA +Perfect! Now I can see the current state. Let me visualize the transformation you're proposing: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CURRENT WORKFLOW vs SDD + TDD HYBRID β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +CURRENT (Sequential): +═══════════════════════ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Specs │────▢│ Design │────▢│ Code │────▢│ Tests β”‚ + β”‚ (exists) β”‚ β”‚ (exists) β”‚ β”‚ (tasks) β”‚ β”‚ (tasks) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ + β–Ό β–Ό β–Ό β–Ό + 15 spec files Decisions 328 tasks "Write tests + (auth, capacity, documented (DB, API, for X" at end + allocation, etc.) Frontend) of each section +PROBLEM: Tests are an afterthought. Code is written, THEN we figure out + how to test it. Coverage becomes retrofit work. +PROPOSED SDD + TDD HYBRID: +═══════════════════════════ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ SPEC-DRIVEN DEVELOPMENT β”‚ + β”‚ β”‚ + β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ β”‚ Specs │────▢│ Design │────▢│ Tasks β”‚ β”‚ + β”‚ β”‚ (GIVEN/ β”‚ β”‚ (HOW to β”‚ β”‚ (WHAT to β”‚ β”‚ + β”‚ β”‚ WHEN/ β”‚ β”‚ test) β”‚ β”‚ build) β”‚ β”‚ + β”‚ β”‚ THEN) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ + β”‚ β”‚ β”‚ β”‚ + β”‚ β–Ό β–Ό β”‚ + β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ β”‚ TEST-DRIVEN CYCLE β”‚ β”‚ + β”‚ β”‚ (per capability) β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ + β”‚ β”‚ β”‚ RED │◄───────── β”‚ + β”‚ β”‚ β”‚ (Write β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ tests β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ first) β”‚ β”‚ β”‚ + β”‚ β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ β–Ό β”‚ β”‚ + β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ + β”‚ β”‚ β”‚ GREEN β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ (Code to β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ pass) β”‚ β”‚ β”‚ + β”‚ β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ β–Ό β”‚ β”‚ + β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ + β”‚ β”‚ β”‚ REFACTORβ”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β”‚ β”‚ β”‚ (Clean β”‚ β”‚ + β”‚ β”‚ β”‚ up) β”‚ β”‚ + β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β”‚ β”‚ β”‚ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ KEY PRINCIPLE: Every spec scenario becomes a test case + β”‚ BEFORE any implementation code exists. + β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +Now let me check what the current tasks look like to understand the gap: +β†’ Read openspec\changes\headroom-foundation\tasks.md [offset=65, limit=30] +I can see the current pattern: Code first, tests last (tasks 7.7-7.8, 8.8, etc.). +Here's what I'm thinking about the SDD + TDD hybrid approach: +The Core Shift +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ SDD + TDD: THE NEW SEQUENCE β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +For EACH capability (auth, capacity planning, etc.): +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ STEP 1: SPEC (Already exists in your specs/) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ Your specs are EXCELLENT for TDD - they're GIVEN/WHEN/THEN format! β”‚ +β”‚ β”‚ +β”‚ Example from specs/authentication/spec.md: β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Scenario: Successful login β”‚ β”‚ +β”‚ β”‚ WHEN a user submits valid email "john@example.com" and password β”‚ β”‚ +β”‚ β”‚ THEN the system validates the credentials β”‚ β”‚ +β”‚ β”‚ AND generates a JWT access token (60 minute TTL) β”‚ β”‚ +β”‚ β”‚ AND generates a refresh token (7 day TTL) β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ This IS a test case. We just need to write it as code FIRST. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ STEP 2: TEST (New - write BEFORE code) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ Each spec scenario becomes a test: β”‚ +β”‚ β”‚ +β”‚ Backend (Pest/PHPUnit): β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ it('authenticates user with valid credentials and issues JWT tokens') β”‚ β”‚ +β”‚ β”‚ ->given('user exists with email john@example.com') β”‚ β”‚ +β”‚ β”‚ ->when('POST /api/auth/login', ['email' => 'john@example.com', ...])β”‚ β”‚ +β”‚ β”‚ ->then('response status is 200') β”‚ β”‚ +β”‚ β”‚ ->and('response contains access_token') β”‚ β”‚ +β”‚ β”‚ ->and('response contains refresh_token') β”‚ β”‚ +β”‚ β”‚ ->and('access_token expires in 60 minutes') β”‚ β”‚ +β”‚ β”‚ ->and('refresh_token expires in 7 days'); β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ Frontend (Playwright/Vitest): β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ test('successful login issues JWT tokens', async ({ page }) => { β”‚ β”‚ +β”‚ β”‚ await page.goto('/login'); β”‚ β”‚ +β”‚ β”‚ await page.fill('[name="email"]', 'john@example.com'); β”‚ β”‚ +β”‚ β”‚ await page.fill('[name="password"]', 'password'); β”‚ β”‚ +β”‚ β”‚ await page.click('button[type="submit"]'); β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ await expect(page).toHaveURL('/dashboard'); β”‚ β”‚ +β”‚ β”‚ await expect(localStorage.getItem('access_token')).toBeTruthy(); β”‚ β”‚ +β”‚ β”‚ await expect(localStorage.getItem('refresh_token')).toBeTruthy(); β”‚ β”‚ +β”‚ β”‚ }); β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ STEP 3: CODE (Minimal to make tests pass) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ Write just enough code to make the tests green. β”‚ +β”‚ No premature optimization. No "I'll need this later." β”‚ +β”‚ β”‚ +β”‚ The tests guide the API design, not the other way around. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ STEP 4: REFACTOR (Clean up while tests stay green) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ Now that it works, make it clean: β”‚ +β”‚ - Extract methods β”‚ +β”‚ - Improve naming β”‚ +β”‚ - Add edge case handling β”‚ +β”‚ - Optimize queries β”‚ +β”‚ β”‚ +β”‚ Tests ensure nothing breaks during refactoring. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +The Practical Impact on Your 328 Tasks +Your current tasks are organized by layer (DB β†’ Backend β†’ Frontend). With SDD+TDD, we'd organize by capability with tests leading: +CURRENT TASK STRUCTURE: +═══════════════════════ +1. Project Setup & Infrastructure +2. Backend Foundation (Laravel) +3. Frontend Foundation (SvelteKit) +4. Database Schema & Migrations +5. Database Seeders +6. Laravel Models & Relationships +7. Authentication (Backend) +8. Authentication (Frontend) +9. Team Member Management (Backend) +10. Team Member Management (Frontend) +... (16 sections total) +Each section ends with "Write tests for X" +PROPOSED SDD+TDD STRUCTURE: +════════════════════════════ +1. Project Setup & Infrastructure (unchanged - foundation) +2. Database Schema (unchanged - structure needed first) +3. AUTHENTICATION CAPABILITY + β”œβ”€ 3.1 Write E2E tests from spec scenarios (Playwright) + β”œβ”€ 3.2 Write API tests from spec scenarios (Pest) + β”œβ”€ 3.3 Implement AuthController (minimal - make tests pass) + β”œβ”€ 3.4 Implement JWT middleware (minimal - make tests pass) + β”œβ”€ 3.5 Implement login page (minimal - make E2E pass) + β”œβ”€ 3.6 Refactor auth flow (clean up) + └─ 3.7 Update API documentation (Scribe) +4. TEAM MEMBER MANAGEMENT CAPABILITY + β”œβ”€ 4.1 Write E2E tests from spec scenarios + β”œβ”€ 4.2 Write API tests from spec scenarios + β”œβ”€ 4.3 Implement TeamMemberController + β”œβ”€ 4.4 Implement team member pages + β”œβ”€ 4.5 Refactor + └─ 4.6 Update docs +... (one section per capability) +Key Questions to Consider +1. Test Granularity: Do we write tests for EVERY spec scenario (you have ~100 scenarios across 15 specs)? Or prioritize critical paths? ==> Every spec. +2. Test Organization: Should tests live with the capability (e.g., tests/Feature/Authentication/) or mirror the current structure? ==> Mirror the current structure. +3. E2E vs Unit: Your specs naturally map to E2E tests. Do we also need unit tests for internal methods, or is E2E + API integration sufficient? ==> We need unit tests for internal methods --> E2E + API + Unit +4. Frontend Testing: With SvelteKit, do we test components in isolation (Vitest) or rely on E2E (Playwright) for most coverage? ==> We test components in isolation (Vitest) and E2E (Playwright) +5. The "Red" Phase: How do we handle the fact that tests will fail initially? Do we commit failing tests, or keep them local until they pass? ==> We commit failing tests, but mark them as pending until they pass. +6. Regression Testing: Your decision-log mentions "regression tests" - does this mean maintaining a separate regression suite, or is every test potentially a regression test? ==> Every test is potentially a regression test. +What resonates with you? Any of these questions spark concerns or clarifications? + + +## LATE IDEA INTERVIEW 2 +Perfect! I have a crystal-clear picture now. Let me synthesize this into a concrete development strategy: +SDD + TDD Strategy - Finalized +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DEVELOPMENT WORKFLOW (SDD + TDD) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +FOR EACH CAPABILITY (15 specs = 15 capability cycles): +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PHASE 1: SPEC β†’ TEST (Red Phase) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ Input: specs//spec.md (GIVEN/WHEN/THEN scenarios) β”‚ +β”‚ β”‚ +β”‚ Output: Failing tests (marked pending) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ 1. Read spec scenarios β”‚ β”‚ +β”‚ β”‚ └── Example: "WHEN user submits valid email, THEN JWT issued" β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 2. Write E2E test (Playwright) β”‚ β”‚ +β”‚ β”‚ └── tests/e2e/.spec.ts β”‚ β”‚ +β”‚ β”‚ └── Mark as test.skip() or test.fixme() β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 3. Write API test (Pest) β”‚ β”‚ +β”‚ β”‚ └── backend/tests/Feature/Test.php β”‚ β”‚ +β”‚ β”‚ └── Mark as $this->markTestSkipped('pending implementation') β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 4. Write Unit tests (Pest/Vitest) β”‚ β”‚ +β”‚ β”‚ └── backend/tests/Unit/Test.php β”‚ β”‚ +β”‚ β”‚ └── frontend/src/lib/.test.ts β”‚ β”‚ +β”‚ β”‚ └── Mark as skip/pending β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 5. Write Component tests (Vitest + Testing Library) β”‚ β”‚ +β”‚ β”‚ └── frontend/src/components/.test.ts β”‚ β”‚ +β”‚ β”‚ └── Mark as skip/pending β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 6. Commit: "test(): Add pending tests for all scenarios" β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PHASE 2: IMPLEMENT (Green Phase) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ Goal: Make pending tests pass, one by one β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ 1. Pick one pending test β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 2. Remove skip marker β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 3. Write MINIMAL code to make it pass β”‚ β”‚ +β”‚ β”‚ └── Don't worry about elegance β”‚ β”‚ +β”‚ β”‚ └── Hardcode if needed temporarily β”‚ β”‚ +β”‚ β”‚ └── Just get to green β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 4. Run test suite β”‚ β”‚ +β”‚ β”‚ └── npm run test (frontend) β”‚ β”‚ +β”‚ β”‚ └── php artisan test (backend) β”‚ β”‚ +β”‚ β”‚ └── npx playwright test (e2e) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 5. Commit when green: β”‚ β”‚ +β”‚ β”‚ └── "feat(): Implement " β”‚ β”‚ +β”‚ β”‚ └── "test(): Enable test" β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 6. Repeat for all scenarios in capability β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PHASE 3: REFACTOR (Clean Phase) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ Goal: Clean code while keeping all tests green β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ 1. Review implementation for: β”‚ β”‚ +β”‚ β”‚ └── Code smells β”‚ β”‚ +β”‚ β”‚ └── Duplication β”‚ β”‚ +β”‚ β”‚ └── Performance issues β”‚ β”‚ +β”‚ β”‚ └── Naming clarity β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 2. Refactor with confidence (tests guard against regression) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 3. Run full test suite after each change β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 4. Commit: "refactor(): " β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PHASE 4: DOCUMENT β”‚ +β”‚ ───────────────────────────────────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ 1. Update API documentation (Scribe) β”‚ β”‚ +β”‚ β”‚ └── php artisan scribe:generate β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 2. Verify all tests still pass β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 3. Commit: "docs(): Update API documentation" β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +Test Organization (Mirrors Current Structure) +backend/ +β”œβ”€β”€ tests/ +β”‚ β”œβ”€β”€ Feature/ # API integration tests +β”‚ β”‚ β”œβ”€β”€ AuthenticationTest.php # From specs/authentication/spec.md +β”‚ β”‚ β”œβ”€β”€ TeamMemberTest.php # From specs/team-member-management/spec.md +β”‚ β”‚ └── ... # One test class per spec +β”‚ β”‚ +β”‚ └── Unit/ # Unit tests for internal methods +β”‚ β”œβ”€β”€ Services/ +β”‚ β”‚ └── JwtServiceTest.php +β”‚ └── ... +frontend/ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ lib/ +β”‚ β”‚ β”œβ”€β”€ api/ +β”‚ β”‚ β”‚ └── auth.test.ts # Unit tests for API clients +β”‚ β”‚ └── stores/ +β”‚ β”‚ └── auth.test.ts # Unit tests for stores +β”‚ β”‚ +β”‚ β”œβ”€β”€ components/ +β”‚ β”‚ β”œβ”€β”€ LoginForm.test.ts # Component tests +β”‚ β”‚ └── ... +β”‚ β”‚ +β”‚ └── routes/ +β”‚ └── login/ +β”‚ └── page.test.ts # Route/page tests +β”‚ +└── tests/e2e/ # Playwright E2E tests + β”œβ”€β”€ auth.spec.ts # From specs/authentication/spec.md + β”œβ”€β”€ team-members.spec.ts # From specs/team-member-management/spec.md + └── ... # One spec file per capability +Test Coverage Strategy +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ TEST PYRAMID FOR THIS PROJECT β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β–² + /β”‚\ E2E Tests (Playwright) + / β”‚ \ ─────────────────────── + / β”‚ \ β€’ Critical user journeys + / β”‚ \ β€’ ~15 spec files = ~15 e2e suites + / β”‚ \ β€’ Tests from specs//spec.md + / β”‚ \ β€’ Run on CI before deploy + /──────┼──────\ + / β”‚ \ API Tests (Pest Feature) + / β”‚ \ ───────────────────────── + / β”‚ \ β€’ Every spec scenario + / β”‚ \β€’ ~100 scenarios across 15 specs + / β”‚ \β€’ Validates endpoints, auth, validation + /────────────┼────────────\ + / β”‚ \ Unit Tests (Pest/Vitest) + / β”‚ \ ───────────────────────── + / β”‚ \β€’ Internal methods, services + / β”‚ \β€’ Business logic, calculations + / β”‚ \β€’ Edge cases, error handling + / β”‚ \ +/───────────────────┴───────────────────\ +Coverage Target: >70% (from decision-log) +Every test is a regression test - run full suite on every PR +Commit Message Convention +test(): Add pending tests for + ↳ Initial failing tests, marked skip/pending +feat(): Implement + ↳ Enable test + minimal implementation +refactor(): + ↳ Clean up while tests green +docs(): + ↳ Scribe generation, README updates +The Complete Capability Cycle +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CAPABILITY: Authentication (Example) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +SPEC: specs/authentication/spec.md has 10 scenarios +CYCLE 1: Write all pending tests +β”œβ”€ tests/e2e/auth.spec.ts (10 scenarios) +β”œβ”€ backend/tests/Feature/AuthenticationTest.php (10 scenarios) +β”œβ”€ backend/tests/Unit/JwtServiceTest.php (unit tests for internal methods) +β”œβ”€ frontend/src/components/LoginForm.test.ts (component tests) +└─ Commit: "test(auth): Add pending tests for all authentication scenarios" +CYCLE 2-11: Implement one scenario at a time +β”œβ”€ Remove skip from "Successful login" test +β”œβ”€ Implement AuthController::login() +β”œβ”€ Implement JWT generation +β”œβ”€ Tests pass +β”œβ”€ Commit: "feat(auth): Implement user login with JWT tokens" +β”‚ +β”œβ”€ Remove skip from "Invalid credentials" test +β”œβ”€ Add validation logic +β”œβ”€ Tests pass +β”œβ”€ Commit: "feat(auth): Add credential validation" +β”‚ +└─ ... repeat for all 10 scenarios +CYCLE 12: Refactor +β”œβ”€ Extract JwtService from AuthController +β”œβ”€ Improve error messages +β”œβ”€ Optimize token generation +β”œβ”€ All tests still pass +└─ Commit: "refactor(auth): Extract JwtService, improve error handling" +CYCLE 13: Document +β”œβ”€ php artisan scribe:generate +β”œβ”€ Verify all tests pass +└─ Commit: "docs(auth): Update API documentation" +Questions Before I Update the Config +1. Test Runner Integration: Should I add npm scripts to frontend/package.json and composer scripts to backend/composer.json for running the different test suites? ==> Yes and Yes +2. CI/CD: Do you want the config to specify running tests in CI? (e.g., GitHub Actions workflow) ==> Not at the moment. +3. Pending Test Markers: For PHP/Pest, should pending tests use ->markTestSkipped() or ->todo()? For Playwright, test.skip() or test.fixme()? ==> Todo and Fixme. +4. Test Naming: Should test names mirror the spec scenario names exactly, or use a shorter convention? => Use ideal convention +5. Task Structure: Should I update the existing tasks.md to reflect this SDD+TDD workflow, or is this a "meta" change that lives in the config? ==> Yes. +Ready to update openspec/config.yaml with this strategy once you confirm! + +## LATE IDEA INTERVIEW 3 +I understand you're in plan mode. Let me construct a comprehensive plan for implementing the SDD + TDD strategy. +Implementation Plan +Phase 1: Update OpenSpec Config +File: openspec/config.yaml +Add new sections: +- development_strategy: SDD + TDD workflow definition +- testing: Test organization, naming conventions, pending markers +- scripts: Test runner commands for both frontend and backend +Phase 2: Add Test Runner Scripts +Frontend (frontend/package.json): +{ + scripts: { + 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 + } +} +Backend (backend/composer.json): +{ + scripts: { + test: pest, + test:unit: pest --filter=Unit, + test:feature: pest --filter=Feature, + test:coverage: pest --coverage --min=70 + } +} +Phase 3: Update Tasks Structure +File: openspec/changes/headroom-foundation/tasks.md +Reorganize from layer-based to capability-based with SDD+TDD phases: +## Capability 1: Authentication +### Phase 1: Write Pending Tests (Red) +- [ ] 1.1 Write E2E tests for all auth scenarios (Playwright, test.fixme) +- [ ] 1.2 Write API tests for all auth scenarios (Pest, ->todo) +- [ ] 1.3 Write unit tests for JwtService (Pest, ->todo) +- [ ] 1.4 Write component tests for LoginForm (Vitest, test.skip) +### Phase 2: Implement (Green) +- [ ] 1.5 Enable and implement: Successful login scenario +- [ ] 1.6 Enable and implement: Invalid credentials scenario +- [ ] 1.7 Enable and implement: Token refresh scenario +- [ ] 1.8 Enable and implement: Logout scenario +... (all 10 scenarios) +### Phase 3: Refactor +- [ ] 1.x Refactor auth implementation +### Phase 4: Document +- [ ] 1.y Generate API docs with Scribe +Phase 4: Create Test Templates +Create starter templates for: +- backend/tests/Feature/TemplateTest.php (Pest) +- frontend/tests/e2e/template.spec.ts (Playwright) +- frontend/src/components/Template.test.ts (Vitest) +Questions +1. Test naming convention: You said "ideal convention" - should I propose a specific format like it('authenticates user with valid credentials', ...) or test('successful login issues JWT tokens', ...)? +2. Task reorganization scope: Should I reorganize ALL 328 tasks now, or start with just the first 1-2 capabilities as a pilot? +3. Template location: Should templates live in openspec/templates/ or within each project's test directory? +Ready to proceed with implementation once you approve this plan! diff --git a/openspec/changes/codemap.md b/openspec/changes/codemap.md new file mode 100644 index 00000000..cf526180 --- /dev/null +++ b/openspec/changes/codemap.md @@ -0,0 +1,19 @@ +# openspec/changes/ + + + +## Responsibility + + + +## Design + + + +## Flow + + + +## Integration + + diff --git a/openspec/changes/headroom-foundation/codemap.md b/openspec/changes/headroom-foundation/codemap.md new file mode 100644 index 00000000..31bc3066 --- /dev/null +++ b/openspec/changes/headroom-foundation/codemap.md @@ -0,0 +1,19 @@ +# openspec/changes/headroom-foundation/ + + + +## Responsibility + + + +## Design + + + +## Flow + + + +## Integration + + diff --git a/openspec/changes/headroom-foundation/tasks.md b/openspec/changes/headroom-foundation/tasks.md index f53ee659..ca441569 100644 --- a/openspec/changes/headroom-foundation/tasks.md +++ b/openspec/changes/headroom-foundation/tasks.md @@ -1,4 +1,10 @@ -## 1. Project Setup & Infrastructure +# Tasks - SDD + TDD Workflow + +## Foundation Phase (Prerequisites) + +### 1. Project Setup & Infrastructure +**Goal**: Establish development environment and project structure +**SDD Phase**: N/A (infrastructure only) - [ ] 1.1 Create Docker Compose configuration (frontend, backend, postgres, redis containers) - [ ] 1.2 Configure Dockerfile for Laravel backend (PHP 8.4-FPM, use :latest tag) @@ -8,7 +14,9 @@ - [ ] 1.6 Test Docker Compose startup (all 4 containers running) - [ ] 1.7 Configure Nginx Proxy Manager routes (/api/* β†’ Laravel, /* β†’ SvelteKit) -## 2. Backend Foundation (Laravel) +### 2. Backend Foundation (Laravel) +**Goal**: Initialize Laravel with required dependencies +**SDD Phase**: N/A (foundation only) - [ ] 2.1 Initialize Laravel 12 (latest) project with required dependencies - [ ] 2.2 Install tymon/jwt-auth, predis/predis, knuckleswtf/scribe @@ -19,7 +27,9 @@ - [ ] 2.7 Configure CORS for SvelteKit frontend origin - [ ] 2.8 Create API route structure (api.php) -## 3. Frontend Foundation (SvelteKit) +### 3. Frontend Foundation (SvelteKit) +**Goal**: Initialize SvelteKit with required dependencies +**SDD Phase**: N/A (foundation only) - [ ] 3.1 Initialize SvelteKit project with TypeScript - [ ] 3.2 Install Tailwind CSS and DaisyUI @@ -31,7 +41,9 @@ - [ ] 3.8 Create auth store (Svelte store for user, token management) - [ ] 3.9 Create layout components (+layout.svelte, navigation) -## 4. Database Schema & Migrations +### 4. Database Schema & Migrations +**Goal**: Create database structure +**SDD Phase**: N/A (schema only) - [ ] 4.1 Create migration: roles table (id, name, description) - [ ] 4.2 Create migration: project_statuses table (id, name, order, is_active, is_billable) @@ -46,7 +58,9 @@ - [ ] 4.11 Add indexes (composite on allocations/actuals for project+month, member+month) - [ ] 4.12 Run migrations and verify schema -## 5. Database Seeders +### 5. Database Seeders +**Goal**: Populate master data +**SDD Phase**: N/A (seed data only) - [ ] 5.1 Create seeder: roles (Frontend Dev, Backend Dev, QA, DevOps, UX, PM, Architect) - [ ] 5.2 Create seeder: project_statuses (13 statuses with correct order) @@ -54,7 +68,9 @@ - [ ] 5.4 Create seeder: users (create superuser account for testing) - [ ] 5.5 Run seeders and verify master data populated -## 6. Laravel Models & Relationships +### 6. Laravel Models & Relationships +**Goal**: Create Eloquent models with relationships +**SDD Phase**: N/A (models only) - [ ] 6.1 Create TeamMember model with role relationship - [ ] 6.2 Create Project model with status, type relationships, casts for forecasted_effort JSON @@ -65,377 +81,1147 @@ - [ ] 6.7 Create User model with JWT authentication traits - [ ] 6.8 Define model factories for testing (TeamMemberFactory, ProjectFactory, etc.) -## 7. Authentication (Backend) +--- -- [ ] 7.1 Create AuthController (login, logout, refresh methods) -- [ ] 7.2 Implement login endpoint (validate credentials, generate JWT tokens) -- [ ] 7.3 Implement logout endpoint (invalidate refresh token in Redis) -- [ ] 7.4 Implement refresh endpoint (validate refresh token, rotate tokens) -- [ ] 7.5 Create JWT middleware for protecting routes -- [ ] 7.6 Store refresh tokens in Redis with 7-day TTL -- [ ] 7.7 Write unit tests for AuthController -- [ ] 7.8 Write feature tests for auth endpoints +## Capability 1: Authentication +**Spec**: specs/authentication/spec.md +**Scenarios**: 10 -## 8. Authentication (Frontend) +### Phase 1: Write Pending Tests (RED) +**Goal**: Create all failing tests from spec scenarios -- [ ] 8.1 Create login page (/login route) -- [ ] 8.2 Create login form with Superforms + Zod validation -- [ ] 8.3 Implement auth API client methods (login, logout, refresh) -- [ ] 8.4 Create auth store (persist tokens in localStorage) -- [ ] 8.5 Implement token refresh logic (interceptor for 401 responses) -- [ ] 8.6 Create auth guard for protected routes (hooks.server.ts) -- [ ] 8.7 Add logout functionality to navigation -- [ ] 8.8 Write E2E test for login flow (Playwright) +#### E2E Tests (Playwright) +- [ ] 1.1.1 Write E2E test: Successful login issues JWT tokens (test.fixme) +- [ ] 1.1.2 Write E2E test: Invalid credentials rejected (test.fixme) +- [ ] 1.1.3 Write E2E test: Missing email or password validation (test.fixme) +- [ ] 1.1.4 Write E2E test: Token refresh with valid refresh token (test.fixme) +- [ ] 1.1.5 Write E2E test: Token refresh with invalid/expired token rejected (test.fixme) +- [ ] 1.1.6 Write E2E test: Logout invalidates refresh token (test.fixme) +- [ ] 1.1.7 Write E2E test: Access protected route with valid token (test.fixme) +- [ ] 1.1.8 Write E2E test: Access protected route without token rejected (test.fixme) +- [ ] 1.1.9 Write E2E test: Access protected route with expired token rejected (test.fixme) +- [ ] 1.1.10 Write E2E test: Token auto-refresh on 401 response (test.fixme) -## 9. Team Member Management (Backend) +#### API Tests (Pest) +- [ ] 1.1.11 Write API test: POST /api/auth/login with valid credentials (->todo) +- [ ] 1.1.12 Write API test: POST /api/auth/login with invalid credentials (->todo) +- [ ] 1.1.13 Write API test: POST /api/auth/login with missing fields (->todo) +- [ ] 1.1.14 Write API test: POST /api/auth/refresh with valid token (->todo) +- [ ] 1.1.15 Write API test: POST /api/auth/refresh with invalid token (->todo) +- [ ] 1.1.16 Write API test: POST /api/auth/logout invalidates token (->todo) +- [ ] 1.1.17 Write API test: JWT middleware allows valid token (->todo) +- [ ] 1.1.18 Write API test: JWT middleware rejects missing token (->todo) +- [ ] 1.1.19 Write API test: JWT middleware rejects expired token (->todo) +- [ ] 1.1.20 Write API test: JWT token has correct claims and TTL (->todo) -- [ ] 9.1 Create TeamMemberController (index, store, show, update, destroy) -- [ ] 9.2 Create TeamMemberRequest for validation (name required, hourly_rate > 0) -- [ ] 9.3 Create TeamMemberResource for JSON transformation -- [ ] 9.4 Create TeamMemberPolicy for authorization (managers can CRUD) -- [ ] 9.5 Implement soft delete prevention (cannot delete if allocations exist) -- [ ] 9.6 Add API routes for team members -- [ ] 9.7 Write unit tests for TeamMember model -- [ ] 9.8 Write feature tests for team member endpoints +#### Unit Tests (Backend) +- [ ] 1.1.21 Write unit test: JwtService generates valid tokens (->todo) +- [ ] 1.1.22 Write unit test: JwtService validates tokens correctly (->todo) +- [ ] 1.1.23 Write unit test: JwtService extracts claims from token (->todo) +- [ ] 1.1.24 Write unit test: AuthController login validates input (->todo) +- [ ] 1.1.25 Write unit test: AuthController logout clears Redis (->todo) -## 10. Team Member Management (Frontend) +#### Component Tests (Frontend) +- [ ] 1.1.26 Write component test: LoginForm renders with email/password fields (skip) +- [ ] 1.1.27 Write component test: LoginForm validates required fields (skip) +- [ ] 1.1.28 Write component test: LoginForm submits with credentials (skip) +- [ ] 1.1.29 Write component test: LoginForm displays error on invalid login (skip) -- [ ] 10.1 Create team members list page (/team-members route) -- [ ] 10.2 Create team member create/edit form with Superforms + Zod -- [ ] 10.3 Implement team member API client methods (CRUD) -- [ ] 10.4 Display team members in TanStack Table (sortable, filterable) -- [ ] 10.5 Add active/inactive toggle UI -- [ ] 10.6 Add hourly rate display (formatted as currency) -- [ ] 10.7 Implement delete with confirmation modal -- [ ] 10.8 Write unit tests for team member components (Vitest) -- [ ] 10.9 Write E2E test for team member CRUD (Playwright) +#### Unit Tests (Frontend) +- [ ] 1.1.30 Write unit test: auth store manages tokens (skip) +- [ ] 1.1.31 Write unit test: auth store persists to localStorage (skip) +- [ ] 1.1.32 Write unit test: API client adds Authorization header (skip) +- [ ] 1.1.33 Write unit test: API client handles 401 with refresh (skip) -## 11. Project Management (Backend) +**Commit**: `test(auth): Add pending tests for all authentication scenarios` -- [ ] 11.1 Create ProjectController (index, store, show, update, destroy) -- [ ] 11.2 Create ProjectRequest for validation (code unique, approved_estimate > 0 if status >= Approved) -- [ ] 11.3 Create ProjectResource for JSON transformation -- [ ] 11.4 Create ProjectPolicy for authorization (managers can edit own projects) -- [ ] 11.5 Implement project status state machine validation -- [ ] 11.6 Implement forecasted effort validation (sum must equal approved estimate Β±5%) -- [ ] 11.7 Add API routes for projects -- [ ] 11.8 Write unit tests for Project model and status transitions -- [ ] 11.9 Write feature tests for project endpoints +### Phase 2: Implement (GREEN) +**Goal**: Enable tests one by one, write minimal code to pass -## 12. Project Management (Frontend) +#### Backend Implementation +- [ ] 1.2.1 Enable test 1.1.11: Implement AuthController::login() - validate credentials, generate JWT +- [ ] 1.2.2 Enable test 1.1.12: Add credential validation error handling +- [ ] 1.2.3 Enable test 1.1.13: Add request validation (email, password required) +- [ ] 1.2.4 Enable test 1.1.14: Implement token refresh endpoint +- [ ] 1.2.5 Enable test 1.1.15: Add refresh token validation +- [ ] 1.2.6 Enable test 1.1.16: Implement logout with Redis token invalidation +- [ ] 1.2.7 Enable test 1.1.17-1.1.19: Implement JWT middleware +- [ ] 1.2.8 Enable test 1.1.20: Configure JWT TTL (60min access, 7day refresh) -- [ ] 12.1 Create projects list page (/projects route) -- [ ] 12.2 Create project create/edit form with Superforms + Zod -- [ ] 12.3 Implement project API client methods (CRUD) -- [ ] 12.4 Display projects in TanStack Table (sortable, filterable by status/type) -- [ ] 12.5 Add status dropdown (reflect state machine transitions) -- [ ] 12.6 Add forecasted effort input (JSON editor or month-by-month fields) -- [ ] 12.7 Display validation warnings (forecasted effort β‰  approved estimate) -- [ ] 12.8 Write unit tests for project components (Vitest) -- [ ] 12.9 Write E2E test for project creation and status transitions (Playwright) +#### Frontend Implementation +- [ ] 1.2.9 Enable test 1.1.1: Create login page with form +- [ ] 1.2.10 Enable test 1.1.2-1.1.3: Add form validation with Zod +- [ ] 1.2.11 Enable test 1.1.4-1.1.6: Implement auth API client methods +- [ ] 1.2.12 Enable test 1.1.7-1.1.9: Add protected route guards +- [ ] 1.2.13 Enable test 1.1.10: Implement token auto-refresh interceptor -## 13. Capacity Planning (Backend) +**Commits**: +- `feat(auth): Implement user login with JWT tokens` +- `feat(auth): Add token refresh and logout functionality` +- `feat(auth): Implement JWT middleware and protected routes` +- `feat(auth): Add login page with form validation` +- `feat(auth): Implement token management and auto-refresh` -- [ ] 13.1 Create HolidayController (index, store, destroy) -- [ ] 13.2 Create PTOController (index, store, update, destroy with approval workflow) -- [ ] 13.3 Create CapacityService for capacity calculations -- [ ] 13.4 Implement calculateIndividualCapacity method (working days Γ— availability - PTO - holidays) -- [ ] 13.5 Implement calculateTeamCapacity method (sum of individual capacities for active members) -- [ ] 13.6 Implement calculatePossibleRevenue method (capacity Γ— hourly rates) -- [ ] 13.7 Add API routes for capacity endpoint (/api/capacity?month=YYYY-MM) -- [ ] 13.8 Implement Redis caching for capacity calculations (1 hour TTL) -- [ ] 13.9 Write unit tests for CapacityService -- [ ] 13.10 Write feature tests for capacity endpoints +### Phase 3: Refactor +**Goal**: Clean code while keeping all tests green -## 14. Capacity Planning (Frontend) +- [ ] 1.3.1 Extract JwtService from AuthController +- [ ] 1.3.2 Improve error message consistency +- [ ] 1.3.3 Optimize token generation performance +- [ ] 1.3.4 Refactor auth store for better state management +- [ ] 1.3.5 Add loading states to login form -- [ ] 14.1 Create capacity planning page (/capacity route) -- [ ] 14.2 Create calendar component for displaying month grid -- [ ] 14.3 Implement availability editor (click day to set 0, 0.5, 1.0) -- [ ] 14.4 Display holidays (H marker on dates) -- [ ] 14.5 Display weekends (O marker on dates) -- [ ] 14.6 Create PTO request form -- [ ] 14.7 Display individual and team capacity summary -- [ ] 14.8 Display possible revenue calculation -- [ ] 14.9 Write unit tests for capacity components (Vitest) -- [ ] 14.10 Write E2E test for capacity planning workflow (Playwright) +**Commit**: `refactor(auth): Extract JwtService, improve error handling` -## 15. Resource Allocation (Backend) +### Phase 4: Document +**Goal**: Generate API documentation -- [ ] 15.1 Create AllocationController (index, store, update, destroy, bulk methods) -- [ ] 15.2 Create AllocationRequest for validation (hours >= 0, month format YYYY-MM) -- [ ] 15.3 Create AllocationResource for JSON transformation -- [ ] 15.4 Create AllocationPolicy for authorization (managers can allocate own team members) -- [ ] 15.5 Implement allocation validation service (check capacity, approved estimate) -- [ ] 15.6 Implement bulk allocation endpoint (create/update multiple allocations) -- [ ] 15.7 Add API routes for allocations (/api/allocations?month=YYYY-MM) -- [ ] 15.8 Implement Redis cache invalidation on allocation mutations -- [ ] 15.9 Write unit tests for allocation validation logic -- [ ] 15.10 Write feature tests for allocation endpoints +- [ ] 1.4.1 Add Scribe annotations to AuthController +- [ ] 1.4.2 Generate API documentation +- [ ] 1.4.3 Verify all tests still pass -## 16. Resource Allocation (Frontend) +**Commit**: `docs(auth): Update API documentation` -- [ ] 16.1 Create allocation matrix page (/allocations route) -- [ ] 16.2 Create allocation matrix component using TanStack Table -- [ ] 16.3 Implement inline editing for allocation hours -- [ ] 16.4 Display projects as rows, team members as columns -- [ ] 16.5 Display row totals (total hours per project) -- [ ] 16.6 Display column totals (total hours per team member) -- [ ] 16.7 Display utilization percentages per team member -- [ ] 16.8 Implement color-coded indicators (GREEN/YELLOW/RED for over/under allocation) -- [ ] 16.9 Add "Untracked" resource column -- [ ] 16.10 Implement month selector (navigate between months) -- [ ] 16.11 Add bulk allocation actions (copy previous month, clear all) -- [ ] 16.12 Write unit tests for allocation matrix logic (Vitest) -- [ ] 16.13 Write E2E test for allocation workflow (Playwright) +--- -## 17. Actuals Tracking (Backend) +## Capability 2: Team Member Management +**Spec**: specs/team-member-management/spec.md +**Scenarios**: 8 -- [ ] 17.1 Create ActualController (index, store, update, bulk methods) -- [ ] 17.2 Create ActualRequest for validation (hours >= 0, cannot log future months) -- [ ] 17.3 Create ActualResource for JSON transformation -- [ ] 17.4 Create ActualPolicy for authorization (developers can log own hours only) -- [ ] 17.5 Implement validation: cannot log to completed/cancelled projects (configurable) -- [ ] 17.6 Implement bulk actuals endpoint -- [ ] 17.7 Add API routes for actuals (/api/actuals?month=YYYY-MM) -- [ ] 17.8 Implement Redis cache invalidation on actuals mutations -- [ ] 17.9 Write unit tests for actuals validation -- [ ] 17.10 Write feature tests for actuals endpoints +### Phase 1: Write Pending Tests (RED) -## 18. Actuals Tracking (Frontend) +#### E2E Tests (Playwright) +- [ ] 2.1.1 Write E2E test: Create team member with valid data (test.fixme) +- [ ] 2.1.2 Write E2E test: Reject team member with invalid hourly rate (test.fixme) +- [ ] 2.1.3 Write E2E test: Reject team member with missing required fields (test.fixme) +- [ ] 2.1.4 Write E2E test: View all team members list (test.fixme) +- [ ] 2.1.5 Write E2E test: Filter active team members only (test.fixme) +- [ ] 2.1.6 Write E2E test: Update team member details (test.fixme) +- [ ] 2.1.7 Write E2E test: Deactivate team member preserves data (test.fixme) +- [ ] 2.1.8 Write E2E test: Cannot delete team member with allocations (test.fixme) -- [ ] 18.1 Create actuals entry page (/actuals route) -- [ ] 18.2 Create actuals matrix component (similar to allocations matrix) -- [ ] 18.3 Display allocated hours vs actual hours side by side -- [ ] 18.4 Highlight variances (over/under delivery) -- [ ] 18.5 Allow developers to see only their own actuals (RBAC check) -- [ ] 18.6 Implement bulk update for multiple projects -- [ ] 18.7 Write unit tests for actuals components (Vitest) -- [ ] 18.8 Write E2E test for actuals logging (Playwright) +#### API Tests (Pest) +- [ ] 2.1.9 Write API test: POST /api/team-members creates member (->todo) +- [ ] 2.1.10 Write API test: Validate hourly_rate > 0 (->todo) +- [ ] 2.1.11 Write API test: Validate required fields (->todo) +- [ ] 2.1.12 Write API test: GET /api/team-members returns all members (->todo) +- [ ] 2.1.13 Write API test: Filter by active status (->todo) +- [ ] 2.1.14 Write API test: PUT /api/team-members/{id} updates member (->todo) +- [ ] 2.1.15 Write API test: Deactivate sets active=false (->todo) +- [ ] 2.1.16 Write API test: DELETE rejected if allocations exist (->todo) -## 19. Utilization Calculations (Backend) +#### Unit Tests (Backend) +- [ ] 2.1.17 Write unit test: TeamMember model validation (->todo) +- [ ] 2.1.18 Write unit test: TeamMemberPolicy authorization (->todo) +- [ ] 2.1.19 Write unit test: Cannot delete with allocations constraint (->todo) -- [ ] 19.1 Create UtilizationService for utilization calculations -- [ ] 19.2 Implement calculateRunningUtilization method (YTD allocated / YTD capacity) -- [ ] 19.3 Implement calculateOverallUtilization method (monthly allocated / monthly capacity) -- [ ] 19.4 Implement calculateActualUtilization method (monthly actuals / monthly capacity) -- [ ] 19.5 Implement team-level utilization aggregation -- [ ] 19.6 Add utilization data to allocation and actuals responses -- [ ] 19.7 Write unit tests for UtilizationService -- [ ] 19.8 Write feature tests for utilization calculations +#### Component Tests (Frontend) +- [ ] 2.1.20 Write component test: TeamMemberList displays data (skip) +- [ ] 2.1.21 Write component test: TeamMemberForm validation (skip) +- [ ] 2.1.22 Write component test: Active toggle works (skip) -## 20. Reporting - Forecast (Backend) +**Commit**: `test(team-member): Add pending tests for all scenarios` -- [ ] 20.1 Create ReportController with forecast method -- [ ] 20.2 Implement forecast report query (multi-period allocations) -- [ ] 20.3 Calculate revenue forecast (allocations Γ— hourly rates) -- [ ] 20.4 Display variance indicators (forecasted vs approved estimate) -- [ ] 20.5 Implement filters (project, status, type, team, date range) -- [ ] 20.6 Create ForecastReportResource for JSON transformation -- [ ] 20.7 Add API route /api/reports/forecast -- [ ] 20.8 Implement Redis caching for forecast reports (15 min TTL) -- [ ] 20.9 Write unit tests for forecast report logic -- [ ] 20.10 Write feature tests for forecast endpoint +### Phase 2: Implement (GREEN) -## 21. Reporting - Forecast (Frontend) +- [ ] 2.2.1 Enable tests 2.1.9-2.1.11: Implement TeamMemberController::store() +- [ ] 2.2.2 Enable tests 2.1.12-2.1.13: Implement TeamMemberController::index() with filters +- [ ] 2.2.3 Enable tests 2.1.14-2.1.15: Implement TeamMemberController::update() +- [ ] 2.2.4 Enable test 2.1.16: Implement delete constraint check +- [ ] 2.2.5 Enable tests 2.1.1-2.1.8: Create team members UI (list, form, filters) -- [ ] 21.1 Create forecast report page (/reports/forecast route) -- [ ] 21.2 Create forecast report table component -- [ ] 21.3 Display multi-period view (month columns) -- [ ] 21.4 Display variance indicators (GREEN/YELLOW/RED) -- [ ] 21.5 Implement date range selector -- [ ] 21.6 Implement filters (project, status, type, team) -- [ ] 21.7 Display summary aggregations (total approved, total allocated, variance) -- [ ] 21.8 Add revenue forecast chart (Recharts line chart) -- [ ] 21.9 Write E2E test for forecast report (Playwright) +**Commits**: +- `feat(team-member): Implement CRUD endpoints` +- `feat(team-member): Add team member management UI` -## 22. Reporting - Utilization (Backend) +### Phase 3: Refactor -- [ ] 22.1 Add utilization method to ReportController -- [ ] 22.2 Implement utilization report query (team and individual trends) -- [ ] 22.3 Calculate planned vs actual utilization -- [ ] 22.4 Implement filters (team member, role, date range) -- [ ] 22.5 Create UtilizationReportResource for JSON transformation -- [ ] 22.6 Add API route /api/reports/utilization -- [ ] 22.7 Implement Redis caching for utilization reports -- [ ] 22.8 Write feature tests for utilization endpoint +- [ ] 2.3.1 Extract TeamMemberService from controller +- [ ] 2.3.2 Optimize list query with eager loading +- [ ] 2.3.3 Add currency formatting to hourly rate display -## 23. Reporting - Utilization (Frontend) +**Commit**: `refactor(team-member): Extract service, optimize queries` -- [ ] 23.1 Create utilization report page (/reports/utilization route) -- [ ] 23.2 Display team-level utilization summary -- [ ] 23.3 Display individual utilization breakdown -- [ ] 23.4 Add utilization trend chart (Recharts line chart) -- [ ] 23.5 Color-code utilization bands (< 70% blue, 80-100% green, > 100% yellow/red) -- [ ] 23.6 Implement filters (team member, role, date range) -- [ ] 23.7 Display utilization distribution chart (how many in each band) -- [ ] 23.8 Write E2E test for utilization report (Playwright) +### Phase 4: Document -## 24. Reporting - Cost (Backend) +- [ ] 2.4.1 Add Scribe annotations to TeamMemberController +- [ ] 2.4.2 Generate API documentation +- [ ] 2.4.3 Verify all tests pass -- [ ] 24.1 Add cost method to ReportController -- [ ] 24.2 Implement cost report query (allocations Γ— hourly rates) -- [ ] 24.3 Calculate possible revenue (full capacity utilization) -- [ ] 24.4 Calculate forecasted revenue (current allocations) -- [ ] 24.5 Calculate revenue gap (possible - forecasted) -- [ ] 24.6 Implement filters (project, client, type, team, date range) -- [ ] 24.7 Create CostReportResource for JSON transformation -- [ ] 24.8 Add API route /api/reports/cost -- [ ] 24.9 Implement Redis caching for cost reports -- [ ] 24.10 Write feature tests for cost endpoint +**Commit**: `docs(team-member): Update API documentation` -## 25. Reporting - Cost (Frontend) +--- -- [ ] 25.1 Create cost report page (/reports/cost route) -- [ ] 25.2 Display monthly revenue forecast -- [ ] 25.3 Display cost breakdown by project -- [ ] 25.4 Display possible revenue vs forecasted revenue -- [ ] 25.5 Display revenue gap analysis -- [ ] 25.6 Implement filters (project, type, team, date range) -- [ ] 25.7 Add revenue chart (Recharts bar chart) -- [ ] 25.8 Write E2E test for cost report (Playwright) +## Capability 3: Project Lifecycle Management +**Spec**: specs/project-lifecycle/spec.md +**Scenarios**: 12 -## 26. Reporting - Allocation (Backend) +### Phase 1: Write Pending Tests (RED) -- [ ] 26.1 Add allocation method to ReportController -- [ ] 26.2 Implement allocation report query (monthly matrix view) -- [ ] 26.3 Include utilization percentages -- [ ] 26.4 Implement filters (team, role, project, status) -- [ ] 26.5 Create AllocationReportResource for JSON transformation -- [ ] 26.6 Add API route /api/reports/allocation -- [ ] 26.7 Implement Redis caching for allocation reports -- [ ] 26.8 Write feature tests for allocation endpoint +#### E2E Tests (Playwright) +- [ ] 3.1.1 Write E2E test: Create project with unique code (test.fixme) +- [ ] 3.1.2 Write E2E test: Reject duplicate project code (test.fixme) +- [ ] 3.1.3 Write E2E test: Valid status transitions (test.fixme) +- [ ] 3.1.4 Write E2E test: Invalid status transitions rejected (test.fixme) +- [ ] 3.1.5 Write E2E test: Estimate approved requires approved_estimate > 0 (test.fixme) +- [ ] 3.1.6 Write E2E test: Workflow progression through all statuses (test.fixme) +- [ ] 3.1.7 Write E2E test: Estimate rework path (test.fixme) +- [ ] 3.1.8 Write E2E test: Project on hold preserves allocations (test.fixme) +- [ ] 3.1.9 Write E2E test: Cancelled project prevents new allocations (test.fixme) +- [ ] 3.1.10 Write E2E test: Set approved estimate (test.fixme) +- [ ] 3.1.11 Write E2E test: Update forecasted effort (test.fixme) +- [ ] 3.1.12 Write E2E test: Validate forecasted effort equals approved estimate (test.fixme) -## 27. Reporting - Allocation (Frontend) +#### API Tests (Pest) +- [ ] 3.1.13 Write API test: POST /api/projects creates project (->todo) +- [ ] 3.1.14 Write API test: Project code must be unique (->todo) +- [ ] 3.1.15 Write API test: Status transition validation (->todo) +- [ ] 3.1.16 Write API test: Estimate approved requires estimate value (->todo) +- [ ] 3.1.17 Write API test: Full workflow state machine (->todo) +- [ ] 3.1.18 Write API test: PUT /api/projects/{id}/status transitions (->todo) +- [ ] 3.1.19 Write API test: PUT /api/projects/{id}/estimate sets approved (->todo) +- [ ] 3.1.20 Write API test: PUT /api/projects/{id}/forecast updates effort (->todo) +- [ ] 3.1.21 Write API test: Validate forecasted sum equals approved (->todo) -- [ ] 27.1 Create allocation report page (/reports/allocation route) -- [ ] 27.2 Display allocation matrix with totals -- [ ] 27.3 Display utilization percentages -- [ ] 27.4 Highlight recent allocation changes (NEW/UPDATED badges) -- [ ] 27.5 Implement multi-month view option -- [ ] 27.6 Implement filters (team, role, project, status) -- [ ] 27.7 Write E2E test for allocation report (Playwright) +#### Unit Tests (Backend) +- [ ] 3.1.22 Write unit test: Project status state machine (->todo) +- [ ] 3.1.23 Write unit test: ProjectPolicy ownership checks (->todo) +- [ ] 3.1.24 Write unit test: Forecasted effort validation (->todo) -## 28. Reporting - Variance (Backend) +#### Component Tests (Frontend) +- [ ] 3.1.25 Write component test: ProjectList displays with status (skip) +- [ ] 3.1.26 Write component test: ProjectForm with status dropdown (skip) +- [ ] 3.1.27 Write component test: Status transition UI (skip) +- [ ] 3.1.28 Write component test: Forecasted effort editor (skip) -- [ ] 28.1 Add variance method to ReportController -- [ ] 28.2 Implement variance report query (planned vs actual comparison) -- [ ] 28.3 Calculate variance (actual - planned) and percentage -- [ ] 28.4 Flag over-delivery and under-delivery patterns -- [ ] 28.5 Implement filters (project, team, person, date range) -- [ ] 28.6 Create VarianceReportResource for JSON transformation -- [ ] 28.7 Add API route /api/reports/variance -- [ ] 28.8 Implement Redis caching for variance reports -- [ ] 28.9 Write feature tests for variance endpoint +**Commit**: `test(project): Add pending tests for all lifecycle scenarios` -## 29. Reporting - Variance (Frontend) +### Phase 2: Implement (GREEN) -- [ ] 29.1 Create variance report page (/reports/variance route) -- [ ] 29.2 Display variance table (planned, actual, variance, variance %) -- [ ] 29.3 Color-code variances (positive green, negative red) -- [ ] 29.4 Display project-level variance aggregations -- [ ] 29.5 Display person-level variance aggregations -- [ ] 29.6 Add variance trend chart (Recharts) -- [ ] 29.7 Implement filters (project, team, person, date range) -- [ ] 29.8 Write E2E test for variance report (Playwright) +- [ ] 3.2.1 Enable tests 3.1.13-3.1.14: Implement ProjectController::store() +- [ ] 3.2.2 Enable tests 3.1.15-3.1.18: Implement status state machine +- [ ] 3.2.3 Enable tests 3.1.19-3.1.21: Implement estimate and forecast endpoints +- [ ] 3.2.4 Enable tests 3.1.1-3.1.12: Create project management UI -## 30. Role-Based Access Control (Backend) +**Commits**: +- `feat(project): Implement project CRUD with unique code validation` +- `feat(project): Add status state machine workflow` +- `feat(project): Implement estimate and forecast management` +- `feat(project): Add project lifecycle UI` -- [ ] 30.1 Create role middleware for route protection -- [ ] 30.2 Implement permission checks in controllers -- [ ] 30.3 Create policies for all models (TeamMember, Project, Allocation, Actual) -- [ ] 30.4 Implement Superuser full access (bypass all checks) -- [ ] 30.5 Implement Manager permissions (own projects, own team allocations) -- [ ] 30.6 Implement Developer permissions (own allocations, own actuals) -- [ ] 30.7 Implement Top Brass permissions (read-only all reports) -- [ ] 30.8 Write unit tests for policies -- [ ] 30.9 Write feature tests for authorization (401, 403 responses) +### Phase 3: Refactor -## 31. Role-Based Access Control (Frontend) +- [ ] 3.3.1 Extract ProjectStatusService for state machine +- [ ] 3.3.2 Optimize project list query with status joins +- [ ] 3.3.3 Improve forecasted effort validation messages -- [ ] 31.1 Add role to auth store -- [ ] 31.2 Implement route guards based on role (hooks.server.ts) -- [ ] 31.3 Hide UI elements based on permissions (v-if directives) -- [ ] 31.4 Show read-only state for Top Brass users -- [ ] 31.5 Filter visible projects for Managers (own projects editable, others read-only) -- [ ] 31.6 Filter visible data for Developers (only assigned projects) -- [ ] 31.7 Write E2E tests for RBAC (different user roles) +**Commit**: `refactor(project): Extract status service, optimize queries` -## 32. Master Data Management (Backend) +### Phase 4: Document -- [ ] 32.1 Create MasterDataController (roles, statuses, types endpoints) -- [ ] 32.2 Create RoleController for managing roles (Superuser only) -- [ ] 32.3 Create ProjectStatusController for managing statuses (Superuser only) -- [ ] 32.4 Create ProjectTypeController for managing types (Superuser only) -- [ ] 32.5 Implement validation: cannot delete role/status/type in use -- [ ] 32.6 Add API routes for master data endpoints -- [ ] 32.7 Implement Redis caching for master data (24 hour TTL) -- [ ] 32.8 Write feature tests for master data endpoints +- [ ] 3.4.1 Add Scribe annotations to ProjectController +- [ ] 3.4.2 Generate API documentation +- [ ] 3.4.3 Verify all tests pass -## 33. Master Data Management (Frontend) +**Commit**: `docs(project): Update API documentation` -- [ ] 33.1 Create master data management page (/admin/master-data route, Superuser only) -- [ ] 33.2 Display roles list with CRUD actions -- [ ] 33.3 Display project statuses list with reordering and CRUD actions -- [ ] 33.4 Display project types list with CRUD actions -- [ ] 33.5 Implement master data forms (create/edit) -- [ ] 33.6 Write E2E test for master data management (Playwright) +--- -## 34. API Documentation (Backend) +## Capability 4: Capacity Planning +**Spec**: specs/capacity-planning/spec.md +**Scenarios**: 10 -- [ ] 34.1 Add Scribe annotations to all controllers (@group, @response tags) -- [ ] 34.2 Configure Scribe (scribe.php config file) -- [ ] 34.3 Generate API documentation (php artisan scribe:generate) -- [ ] 34.4 Verify SwaggerUI accessible at /api/documentation -- [ ] 34.5 Add example requests and responses to documentation -- [ ] 34.6 Add authentication section to API docs +### Phase 1: Write Pending Tests (RED) -## 35. Testing & Code Quality +#### E2E Tests (Playwright) +- [ ] 4.1.1 Write E2E test: Calculate capacity for full month (test.fixme) +- [ ] 4.1.2 Write E2E test: Calculate capacity with half-day availability (test.fixme) +- [ ] 4.1.3 Write E2E test: Calculate capacity with PTO (test.fixme) +- [ ] 4.1.4 Write E2E test: Calculate capacity with holidays (test.fixme) +- [ ] 4.1.5 Write E2E test: Calculate capacity with mixed availability (test.fixme) +- [ ] 4.1.6 Write E2E test: Calculate team capacity sum (test.fixme) +- [ ] 4.1.7 Write E2E test: Exclude inactive from team capacity (test.fixme) +- [ ] 4.1.8 Write E2E test: Calculate possible revenue (test.fixme) +- [ ] 4.1.9 Write E2E test: View capacity calendar (test.fixme) +- [ ] 4.1.10 Write E2E test: Edit availability in calendar (test.fixme) -- [ ] 35.1 Write comprehensive unit tests (backend models, services, utilities) -- [ ] 35.2 Write feature tests for all API endpoints (Laravel Pest) -- [ ] 35.3 Write unit tests for frontend components (Vitest) -- [ ] 35.4 Write E2E tests for critical flows (Playwright: login, allocate, report) -- [ ] 35.5 Configure pre-commit hooks (Laravel Pint, ESLint, Prettier) -- [ ] 35.6 Run PHPStan static analysis (level 5+) -- [ ] 35.7 Generate code coverage report (verify >70%) -- [ ] 35.8 Fix all linting errors (Laravel Pint, ESLint) -- [ ] 35.9 Run security audit (composer audit, npm audit) +#### API Tests (Pest) +- [ ] 4.1.11 Write API test: GET /api/capacity calculates individual (->todo) +- [ ] 4.1.12 Write API test: Capacity accounts for availability (->todo) +- [ ] 4.1.13 Write API test: Capacity subtracts PTO (->todo) +- [ ] 4.1.14 Write API test: Capacity subtracts holidays (->todo) +- [ ] 4.1.15 Write API test: GET /api/capacity/team sums active members (->todo) +- [ ] 4.1.16 Write API test: GET /api/capacity/revenue calculates possible (->todo) +- [ ] 4.1.17 Write API test: POST /api/holidays creates holiday (->todo) +- [ ] 4.1.18 Write API test: POST /api/ptos creates PTO request (->todo) -## 36. Polish & UX +#### Unit Tests (Backend) +- [ ] 4.1.19 Write unit test: CapacityService calculates working days (->todo) +- [ ] 4.1.20 Write unit test: CapacityService applies availability (->todo) +- [ ] 4.1.21 Write unit test: CapacityService handles PTO (->todo) +- [ ] 4.1.22 Write unit test: CapacityService handles holidays (->todo) +- [ ] 4.1.23 Write unit test: CapacityService calculates revenue (->todo) +- [ ] 4.1.24 Write unit test: Redis caching for capacity (->todo) -- [ ] 36.1 Add loading states (spinners, skeleton loaders) -- [ ] 36.2 Add error states (toast notifications, error pages) -- [ ] 36.3 Add empty states (no data placeholders) -- [ ] 36.4 Implement form validation feedback (inline errors, success messages) -- [ ] 36.5 Add confirmation modals for destructive actions (delete) -- [ ] 36.6 Implement responsive design (mobile-friendly tables, navigation) -- [ ] 36.7 Add keyboard shortcuts (ESC to close modals, etc.) -- [ ] 36.8 Add accessibility features (ARIA labels, focus management) -- [ ] 36.9 Test in multiple browsers (Chrome, Firefox, Safari) +#### Component Tests (Frontend) +- [ ] 4.1.25 Write component test: CapacityCalendar displays month (skip) +- [ ] 4.1.26 Write component test: Availability editor toggles values (skip) +- [ ] 4.1.27 Write component test: CapacitySummary shows totals (skip) -## 37. Documentation & Deployment +**Commit**: `test(capacity): Add pending tests for all planning scenarios` -- [ ] 37.1 Write README.md with setup instructions -- [ ] 37.2 Document environment variables (.env.example files) -- [ ] 37.3 Create Quick Start guide for managers (capacity β†’ allocate β†’ reports) -- [ ] 37.4 Document API authentication flow -- [ ] 37.5 Create deployment guide (Docker Compose production setup) -- [ ] 37.6 Add health check endpoints (/api/health) -- [ ] 37.7 Configure logging (Laravel logs to stdout, Svelte client errors to console) -- [ ] 37.8 Test full deployment workflow (fresh Docker Compose up) -- [ ] 37.9 Create superuser via seeder for initial login -- [ ] 37.10 Verify Nginx Proxy Manager routing +### Phase 2: Implement (GREEN) -## 38. Final Verification +- [ ] 4.2.1 Enable tests 4.1.19-4.1.24: Implement CapacityService +- [ ] 4.2.2 Enable tests 4.1.11-4.1.16: Implement capacity endpoints +- [ ] 4.2.3 Enable tests 4.1.17-4.1.18: Implement holiday and PTO endpoints +- [ ] 4.2.4 Enable tests 4.1.1-4.1.10: Create capacity planning UI -- [ ] 38.1 Run full test suite (unit + E2E) and verify all pass -- [ ] 38.2 Verify code coverage >70% -- [ ] 38.3 Run linters and fix all issues -- [ ] 38.4 Test complete user flow: capacity β†’ allocate β†’ log actuals β†’ reports -- [ ] 38.5 Verify RBAC working for all 4 personas -- [ ] 38.6 Verify Redis caching working (check cache hit rate) -- [ ] 38.7 Verify API documentation accessible and accurate -- [ ] 38.8 Verify Docker Compose startup works cleanly -- [ ] 38.9 Verify database migrations and seeders work -- [ ] 38.10 Conduct final security review (no secrets in code, HTTPS enforced) +**Commits**: +- `feat(capacity): Implement capacity calculation service` +- `feat(capacity): Add capacity, holiday, and PTO endpoints` +- `feat(capacity): Create capacity planning calendar UI` + +### Phase 3: Refactor + +- [ ] 4.3.1 Optimize capacity calculation with caching +- [ ] 4.3.2 Extract WorkingDaysCalculator utility +- [ ] 4.3.3 Improve calendar performance with virtualization + +**Commit**: `refactor(capacity): Optimize calculations, extract utilities` + +### Phase 4: Document + +- [ ] 4.4.1 Add Scribe annotations to capacity endpoints +- [ ] 4.4.2 Generate API documentation +- [ ] 4.4.3 Verify all tests pass + +**Commit**: `docs(capacity): Update API documentation` + +--- + +## Capability 5: Resource Allocation +**Spec**: specs/resource-allocation/spec.md +**Scenarios**: 10 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 5.1.1 Write E2E test: Allocate hours to project (test.fixme) +- [ ] 5.1.2 Write E2E test: Allocate zero hours (test.fixme) +- [ ] 5.1.3 Write E2E test: Reject negative hours (test.fixme) +- [ ] 5.1.4 Write E2E test: View allocation matrix (test.fixme) +- [ ] 5.1.5 Write E2E test: Show allocation totals (test.fixme) +- [ ] 5.1.6 Write E2E test: Show utilization percentage (test.fixme) +- [ ] 5.1.7 Write E2E test: Update allocated hours (test.fixme) +- [ ] 5.1.8 Write E2E test: Delete allocation (test.fixme) +- [ ] 5.1.9 Write E2E test: Bulk allocation operations (test.fixme) +- [ ] 5.1.10 Write E2E test: Navigate between months (test.fixme) + +#### API Tests (Pest) +- [ ] 5.1.11 Write API test: POST /api/allocations creates allocation (->todo) +- [ ] 5.1.12 Write API test: Validate hours >= 0 (->todo) +- [ ] 5.1.13 Write API test: GET /api/allocations returns matrix (->todo) +- [ ] 5.1.14 Write API test: PUT /api/allocations/{id} updates (->todo) +- [ ] 5.1.15 Write API test: DELETE /api/allocations/{id} removes (->todo) +- [ ] 5.1.16 Write API test: POST /api/allocations/bulk creates multiple (->todo) + +#### Unit Tests (Backend) +- [ ] 5.1.17 Write unit test: AllocationPolicy authorization (->todo) +- [ ] 5.1.18 Write unit test: Allocation validation service (->todo) +- [ ] 5.1.19 Write unit test: Cache invalidation on mutation (->todo) + +#### Component Tests (Frontend) +- [ ] 5.1.20 Write component test: AllocationMatrix displays grid (skip) +- [ ] 5.1.21 Write component test: Inline editing updates values (skip) +- [ ] 5.1.22 Write component test: Totals calculate correctly (skip) +- [ ] 5.1.23 Write component test: Color indicators show correctly (skip) + +**Commit**: `test(allocation): Add pending tests for all allocation scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 5.2.1 Enable tests 5.1.17-5.1.19: Implement allocation validation service +- [ ] 5.2.2 Enable tests 5.1.11-5.1.16: Implement AllocationController +- [ ] 5.2.3 Enable tests 5.1.1-5.1.10: Create allocation matrix UI + +**Commits**: +- `feat(allocation): Implement allocation validation service` +- `feat(allocation): Add allocation CRUD and bulk endpoints` +- `feat(allocation): Create allocation matrix UI with inline editing` + +### Phase 3: Refactor + +- [ ] 5.3.1 Optimize matrix query with single aggregated query +- [ ] 5.3.2 Extract AllocationMatrixCalculator +- [ ] 5.3.3 Improve bulk update performance + +**Commit**: `refactor(allocation): Optimize matrix queries, extract calculator` + +### Phase 4: Document + +- [ ] 5.4.1 Add Scribe annotations to AllocationController +- [ ] 5.4.2 Generate API documentation +- [ ] 5.4.3 Verify all tests pass + +**Commit**: `docs(allocation): Update API documentation` + +--- + +## Capability 6: Actuals Tracking +**Spec**: specs/actuals-tracking/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 6.1.1 Write E2E test: Log hours for current month (test.fixme) +- [ ] 6.1.2 Write E2E test: Reject negative hours (test.fixme) +- [ ] 6.1.3 Write E2E test: Reject future month hours (test.fixme) +- [ ] 6.1.4 Write E2E test: Incremental weekly updates (test.fixme) +- [ ] 6.1.5 Write E2E test: Replace monthly total (test.fixme) +- [ ] 6.1.6 Write E2E test: View actuals matrix (test.fixme) +- [ ] 6.1.7 Write E2E test: Show actuals vs allocations (test.fixme) +- [ ] 6.1.8 Write E2E test: Reject hours to inactive projects (test.fixme) + +#### API Tests (Pest) +- [ ] 6.1.9 Write API test: POST /api/actuals logs hours (->todo) +- [ ] 6.1.10 Write API test: Validate hours >= 0 (->todo) +- [ ] 6.1.11 Write API test: Reject future month (->todo) +- [ ] 6.1.12 Write API test: PUT /api/actuals/{id} updates (->todo) +- [ ] 6.1.13 Write API test: GET /api/actuals returns matrix (->todo) +- [ ] 6.1.14 Write API test: Reject inactive projects (->todo) + +#### Unit Tests (Backend) +- [ ] 6.1.15 Write unit test: ActualPolicy developer-only access (->todo) +- [ ] 6.1.16 Write unit test: Month validation (->todo) +- [ ] 6.1.17 Write unit test: Project status validation (->todo) + +#### Component Tests (Frontend) +- [ ] 6.1.18 Write component test: ActualsMatrix displays data (skip) +- [ ] 6.1.19 Write component test: Variance highlighting works (skip) +- [ ] 6.1.20 Write component test: Developer sees only own actuals (skip) + +**Commit**: `test(actuals): Add pending tests for all tracking scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 6.2.1 Enable tests 6.1.15-6.1.17: Implement ActualPolicy and validation +- [ ] 6.2.2 Enable tests 6.1.9-6.1.14: Implement ActualController +- [ ] 6.2.3 Enable tests 6.1.1-6.1.8: Create actuals tracking UI + +**Commits**: +- `feat(actuals): Implement actuals validation and policies` +- `feat(actuals): Add actuals logging endpoints` +- `feat(actuals): Create actuals tracking UI with variance display` + +### Phase 3: Refactor + +- [ ] 6.3.1 Extract ActualsValidationService +- [ ] 6.3.2 Optimize actuals aggregation queries +- [ ] 6.3.3 Improve variance calculation performance + +**Commit**: `refactor(actuals): Extract validation service, optimize queries` + +### Phase 4: Document + +- [ ] 6.4.1 Add Scribe annotations to ActualController +- [ ] 6.4.2 Generate API documentation +- [ ] 6.4.3 Verify all tests pass + +**Commit**: `docs(actuals): Update API documentation` + +--- + +## Capability 7: Utilization Calculations +**Spec**: specs/utilization-calculations/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 7.1.1 Write E2E test: Calculate running utilization YTD (test.fixme) +- [ ] 7.1.2 Write E2E test: Running utilization at start of year (test.fixme) +- [ ] 7.1.3 Write E2E test: Calculate overall utilization monthly (test.fixme) +- [ ] 7.1.4 Write E2E test: Full utilization 100% (test.fixme) +- [ ] 7.1.5 Write E2E test: Over-utilization >100% (test.fixme) +- [ ] 7.1.6 Write E2E test: Display utilization alongside capacity (test.fixme) +- [ ] 7.1.7 Write E2E test: Color-code utilization levels (test.fixme) +- [ ] 7.1.8 Write E2E test: Optimal utilization 80-100% green (test.fixme) + +#### API Tests (Pest) +- [ ] 7.1.9 Write API test: GET /api/utilization/running calculates YTD (->todo) +- [ ] 7.1.10 Write API test: GET /api/utilization/overall calculates monthly (->todo) +- [ ] 7.1.11 Write API test: Utilization includes in allocation response (->todo) + +#### Unit Tests (Backend) +- [ ] 7.1.12 Write unit test: UtilizationService calculates running (->todo) +- [ ] 7.1.13 Write unit test: UtilizationService calculates overall (->todo) +- [ ] 7.1.14 Write unit test: UtilizationService handles edge cases (->todo) +- [ ] 7.1.15 Write unit test: Color coding logic (->todo) + +#### Component Tests (Frontend) +- [ ] 7.1.16 Write component test: UtilizationBadge shows percentage (skip) +- [ ] 7.1.17 Write component test: Color coding applies correctly (skip) + +**Commit**: `test(utilization): Add pending tests for all calculation scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 7.2.1 Enable tests 7.1.12-7.1.15: Implement UtilizationService +- [ ] 7.2.2 Enable tests 7.1.9-7.1.11: Add utilization to responses +- [ ] 7.2.3 Enable tests 7.1.1-7.1.8: Add utilization display UI + +**Commits**: +- `feat(utilization): Implement utilization calculation service` +- `feat(utilization): Add utilization data to API responses` +- `feat(utilization): Add utilization display with color coding` + +### Phase 3: Refactor + +- [ ] 7.3.1 Optimize utilization calculations with caching +- [ ] 7.3.2 Extract UtilizationFormatter +- [ ] 7.3.3 Improve calculation performance for large datasets + +**Commit**: `refactor(utilization): Optimize calculations, extract formatter` + +### Phase 4: Document + +- [ ] 7.4.1 Add utilization to API response documentation +- [ ] 7.4.2 Verify all tests pass + +**Commit**: `docs(utilization): Document utilization calculations` + +--- + +## Capability 8: Allocation Validation +**Spec**: specs/allocation-validation/spec.md +**Scenarios**: 10 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 8.1.1 Write E2E test: Detect over-allocation RED indicator (test.fixme) +- [ ] 8.1.2 Write E2E test: Over-allocation threshold warning (test.fixme) +- [ ] 8.1.3 Write E2E test: Detect under-allocation YELLOW indicator (test.fixme) +- [ ] 8.1.4 Write E2E test: Under-allocation warning message (test.fixme) +- [ ] 8.1.5 Write E2E test: Display optimal allocation GREEN (test.fixme) +- [ ] 8.1.6 Write E2E test: Within tolerance GREEN (test.fixme) +- [ ] 8.1.7 Write E2E test: Person under capacity no warning (test.fixme) +- [ ] 8.1.8 Write E2E test: Person at capacity optimal (test.fixme) +- [ ] 8.1.9 Write E2E test: Person over capacity RED warning (test.fixme) +- [ ] 8.1.10 Write E2E test: Person over capacity blocks save (test.fixme) + +#### API Tests (Pest) +- [ ] 8.1.11 Write API test: Validation detects over-allocation (->todo) +- [ ] 8.1.12 Write API test: Validation detects under-allocation (->todo) +- [ ] 8.1.13 Write API test: Validation allows within tolerance (->todo) +- [ ] 8.1.14 Write API test: Validation blocks person over capacity (->todo) + +#### Unit Tests (Backend) +- [ ] 8.1.15 Write unit test: AllocationValidationService detects over (->todo) +- [ ] 8.1.16 Write unit test: AllocationValidationService detects under (->todo) +- [ ] 8.1.17 Write unit test: Tolerance calculation (5%) (->todo) +- [ ] 8.1.18 Write unit test: Person capacity validation (->todo) + +#### Component Tests (Frontend) +- [ ] 8.1.19 Write component test: Validation indicators display (skip) +- [ ] 8.1.20 Write component test: Warning messages show correctly (skip) + +**Commit**: `test(validation): Add pending tests for all validation scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 8.2.1 Enable tests 8.1.15-8.1.18: Implement AllocationValidationService +- [ ] 8.2.2 Enable tests 8.1.11-8.1.14: Add validation to allocation endpoints +- [ ] 8.2.3 Enable tests 8.1.1-8.1.10: Add validation indicators to UI + +**Commits**: +- `feat(validation): Implement allocation validation service` +- `feat(validation): Add validation to allocation endpoints` +- `feat(validation): Add validation indicators to allocation UI` + +### Phase 3: Refactor + +- [ ] 8.3.1 Extract ValidationResult object +- [ ] 8.3.2 Optimize validation queries +- [ ] 8.3.3 Improve error message formatting + +**Commit**: `refactor(validation): Extract result object, optimize queries` + +### Phase 4: Document + +- [ ] 8.4.1 Document validation rules in API docs +- [ ] 8.4.2 Verify all tests pass + +**Commit**: `docs(validation): Document allocation validation rules` + +--- + +## Capability 9: Role-Based Access Control +**Spec**: specs/role-based-access/spec.md +**Scenarios**: 12 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 9.1.1 Write E2E test: Superuser full access (test.fixme) +- [ ] 9.1.2 Write E2E test: Manager creates own project (test.fixme) +- [ ] 9.1.3 Write E2E test: Manager views all projects read-only (test.fixme) +- [ ] 9.1.4 Write E2E test: Manager allocates own team member (test.fixme) +- [ ] 9.1.5 Write E2E test: Manager cannot allocate other team (test.fixme) +- [ ] 9.1.6 Write E2E test: Manager approves own estimate (test.fixme) +- [ ] 9.1.7 Write E2E test: Developer views own allocations (test.fixme) +- [ ] 9.1.8 Write E2E test: Developer logs own hours (test.fixme) +- [ ] 9.1.9 Write E2E test: Developer cannot log others hours (test.fixme) +- [ ] 9.1.10 Write E2E test: Top Brass views all reports (test.fixme) +- [ ] 9.1.11 Write E2E test: Top Brass read-only access (test.fixme) +- [ ] 9.1.12 Write E2E test: Unauthorized access rejected (test.fixme) + +#### API Tests (Pest) +- [ ] 9.1.13 Write API test: Superuser bypasses all checks (->todo) +- [ ] 9.1.14 Write API test: Manager policy allows own project (->todo) +- [ ] 9.1.15 Write API test: Manager policy denies other project edit (->todo) +- [ ] 9.1.16 Write API test: Manager policy allows own team allocation (->todo) +- [ ] 9.1.17 Write API test: Developer policy allows own actuals (->todo) +- [ ] 9.1.18 Write API test: Developer policy denies others actuals (->todo) +- [ ] 9.1.19 Write API test: Top Brass policy allows read all (->todo) +- [ ] 9.1.20 Write API test: JWT middleware rejects invalid token (->todo) + +#### Unit Tests (Backend) +- [ ] 9.1.21 Write unit test: TeamMemberPolicy all scenarios (->todo) +- [ ] 9.1.22 Write unit test: ProjectPolicy all scenarios (->todo) +- [ ] 9.1.23 Write unit test: AllocationPolicy all scenarios (->todo) +- [ ] 9.1.24 Write unit test: ActualPolicy all scenarios (->todo) + +#### Component Tests (Frontend) +- [ ] 9.1.25 Write component test: UI hides elements by role (skip) +- [ ] 9.1.26 Write component test: Read-only mode for Top Brass (skip) + +**Commit**: `test(rbac): Add pending tests for all access control scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 9.2.1 Enable tests 9.1.21-9.1.24: Implement all policies +- [ ] 9.2.2 Enable tests 9.1.13-9.1.20: Add middleware and authorization +- [ ] 9.2.3 Enable tests 9.1.1-9.1.12: Add role-based UI guards + +**Commits**: +- `feat(rbac): Implement TeamMember, Project, Allocation, Actual policies` +- `feat(rbac): Add role middleware and authorization checks` +- `feat(rbac): Add role-based UI guards and visibility` + +### Phase 3: Refactor + +- [ ] 9.3.1 Extract common authorization logic to base policy +- [ ] 9.3.2 Optimize policy checks with caching +- [ ] 9.3.3 Improve error messages for forbidden actions + +**Commit**: `refactor(rbac): Extract base policy, optimize checks` + +### Phase 4: Document + +- [ ] 9.4.1 Document RBAC rules in API docs +- [ ] 9.4.2 Create RBAC matrix documentation +- [ ] 9.4.3 Verify all tests pass + +**Commit**: `docs(rbac): Document role-based access control` + +--- + +## Capability 10: Master Data Management +**Spec**: specs/master-data-management/spec.md +**Scenarios**: 12 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 10.1.1 Write E2E test: Superuser creates role (test.fixme) +- [ ] 10.1.2 Write E2E test: Superuser updates role (test.fixme) +- [ ] 10.1.3 Write E2E test: Cannot delete role in use (test.fixme) +- [ ] 10.1.4 Write E2E test: Superuser creates custom status (test.fixme) +- [ ] 10.1.5 Write E2E test: Set status billable flag (test.fixme) +- [ ] 10.1.6 Write E2E test: Reorder statuses (test.fixme) +- [ ] 10.1.7 Write E2E test: Superuser creates project type (test.fixme) +- [ ] 10.1.8 Write E2E test: Set type billable flag (test.fixme) +- [ ] 10.1.9 Write E2E test: View roles list (test.fixme) +- [ ] 10.1.10 Write E2E test: View statuses list (test.fixme) +- [ ] 10.1.11 Write E2E test: View types list (test.fixme) +- [ ] 10.1.12 Write E2E test: Non-superuser denied access (test.fixme) + +#### API Tests (Pest) +- [ ] 10.1.13 Write API test: POST /api/roles creates role (->todo) +- [ ] 10.1.14 Write API test: PUT /api/roles/{id} updates (->todo) +- [ ] 10.1.15 Write API test: DELETE /api/roles/{id} rejected if in use (->todo) +- [ ] 10.1.16 Write API test: POST /api/project-statuses creates (->todo) +- [ ] 10.1.17 Write API test: PUT /api/project-statuses/{id}/order reorders (->todo) +- [ ] 10.1.18 Write API test: POST /api/project-types creates (->todo) +- [ ] 10.1.19 Write API test: Superuser only access (->todo) + +#### Unit Tests (Backend) +- [ ] 10.1.20 Write unit test: Role deletion constraint (->todo) +- [ ] 10.1.21 Write unit test: Status ordering logic (->todo) +- [ ] 10.1.22 Write unit test: Master data caching (->todo) + +#### Component Tests (Frontend) +- [ ] 10.1.23 Write component test: MasterDataList displays (skip) +- [ ] 10.1.24 Write component test: Reorder drag-and-drop (skip) + +**Commit**: `test(master-data): Add pending tests for all management scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 10.2.1 Enable tests 10.1.20-10.1.22: Implement validation and caching +- [ ] 10.2.2 Enable tests 10.1.13-10.1.19: Implement MasterDataController +- [ ] 10.2.3 Enable tests 10.1.1-10.1.12: Create master data management UI + +**Commits**: +- `feat(master-data): Implement master data validation and caching` +- `feat(master-data): Add roles, statuses, types management endpoints` +- `feat(master-data): Create master data management UI` + +### Phase 3: Refactor + +- [ ] 10.3.1 Extract MasterDataService +- [ ] 10.3.2 Optimize master data caching strategy +- [ ] 10.3.3 Improve reordering performance + +**Commit**: `refactor(master-data): Extract service, optimize caching` + +### Phase 4: Document + +- [ ] 10.4.1 Add Scribe annotations to MasterDataController +- [ ] 10.4.2 Generate API documentation +- [ ] 10.4.3 Verify all tests pass + +**Commit**: `docs(master-data): Update API documentation` + +--- + +## Capability 11: Forecast Reporting +**Spec**: specs/forecast-reporting/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 11.1.1 Write E2E test: View 3-month forecast (test.fixme) +- [ ] 11.1.2 Write E2E test: Forecast includes variance indicators (test.fixme) +- [ ] 11.1.3 Write E2E test: Filter forecast by project status (test.fixme) +- [ ] 11.1.4 Write E2E test: Filter forecast by project type (test.fixme) +- [ ] 11.1.5 Write E2E test: Filter forecast by team member (test.fixme) +- [ ] 11.1.6 Write E2E test: Filter forecast by role (test.fixme) +- [ ] 11.1.7 Write E2E test: Calculate monthly revenue forecast (test.fixme) +- [ ] 11.1.8 Write E2E test: Calculate total period revenue (test.fixme) + +#### API Tests (Pest) +- [ ] 11.1.9 Write API test: GET /api/reports/forecast returns data (->todo) +- [ ] 11.1.10 Write API test: Filter by project status (->todo) +- [ ] 11.1.11 Write API test: Filter by project type (->todo) +- [ ] 11.1.12 Write API test: Filter by team member (->todo) +- [ ] 11.1.13 Write API test: Revenue calculation correct (->todo) +- [ ] 11.1.14 Write API test: Redis caching works (->todo) + +#### Unit Tests (Backend) +- [ ] 11.1.15 Write unit test: ForecastReportService aggregates (->todo) +- [ ] 11.1.16 Write unit test: Revenue calculation (->todo) +- [ ] 11.1.17 Write unit test: Variance indicators (->todo) + +#### Component Tests (Frontend) +- [ ] 11.1.18 Write component test: ForecastTable displays (skip) +- [ ] 11.1.19 Write component test: Revenue chart renders (skip) +- [ ] 11.1.20 Write component test: Filters work correctly (skip) + +**Commit**: `test(forecast): Add pending tests for all reporting scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 11.2.1 Enable tests 11.1.15-11.1.17: Implement ForecastReportService +- [ ] 11.2.2 Enable tests 11.1.9-11.1.14: Implement forecast endpoint +- [ ] 11.2.3 Enable tests 11.1.1-11.1.8: Create forecast report UI + +**Commits**: +- `feat(forecast): Implement forecast report service` +- `feat(forecast): Add forecast report endpoint with caching` +- `feat(forecast): Create forecast report UI with charts` + +### Phase 3: Refactor + +- [ ] 11.3.1 Optimize forecast query performance +- [ ] 11.3.2 Extract ForecastCalculator +- [ ] 11.3.3 Improve chart rendering performance + +**Commit**: `refactor(forecast): Optimize queries, extract calculator` + +### Phase 4: Document + +- [ ] 11.4.1 Add Scribe annotations to ReportController +- [ ] 11.4.2 Generate API documentation +- [ ] 11.4.3 Verify all tests pass + +**Commit**: `docs(forecast): Update API documentation` + +--- + +## Capability 12: Utilization Reporting +**Spec**: specs/utilization-reporting/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 12.1.1 Write E2E test: View team utilization report (test.fixme) +- [ ] 12.1.2 Write E2E test: Utilization trend visualization (test.fixme) +- [ ] 12.1.3 Write E2E test: Filter utilization by team member (test.fixme) +- [ ] 12.1.4 Write E2E test: Filter utilization by role (test.fixme) +- [ ] 12.1.5 Write E2E test: Compare planned vs actual utilization (test.fixme) +- [ ] 12.1.6 Write E2E test: Utilization variance report (test.fixme) +- [ ] 12.1.7 Write E2E test: Over-delivery variance (test.fixme) +- [ ] 12.1.8 Write E2E test: Utilization distribution chart (test.fixme) + +#### API Tests (Pest) +- [ ] 12.1.9 Write API test: GET /api/reports/utilization returns data (->todo) +- [ ] 12.1.10 Write API test: Filter by team member (->todo) +- [ ] 12.1.11 Write API test: Filter by role (->todo) +- [ ] 12.1.12 Write API test: Planned vs actual comparison (->todo) +- [ ] 12.1.13 Write API test: Redis caching works (->todo) + +#### Unit Tests (Backend) +- [ ] 12.1.14 Write unit test: UtilizationReportService aggregates (->todo) +- [ ] 12.1.15 Write unit test: Trend calculation (->todo) +- [ ] 12.1.16 Write unit test: Distribution calculation (->todo) + +#### Component Tests (Frontend) +- [ ] 12.1.17 Write component test: UtilizationTable displays (skip) +- [ ] 12.1.18 Write component test: Trend chart renders (skip) +- [ ] 12.1.19 Write component test: Distribution chart renders (skip) + +**Commit**: `test(utilization-report): Add pending tests for all reporting scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 12.2.1 Enable tests 12.1.14-12.1.16: Implement UtilizationReportService +- [ ] 12.2.2 Enable tests 12.1.9-12.1.13: Implement utilization endpoint +- [ ] 12.2.3 Enable tests 12.1.1-12.1.8: Create utilization report UI + +**Commits**: +- `feat(utilization-report): Implement utilization report service` +- `feat(utilization-report): Add utilization report endpoint` +- `feat(utilization-report): Create utilization report UI with charts` + +### Phase 3: Refactor + +- [ ] 12.3.1 Optimize utilization aggregation queries +- [ ] 12.3.2 Extract UtilizationTrendCalculator +- [ ] 12.3.3 Improve chart interactivity + +**Commit**: `refactor(utilization-report): Optimize queries, extract calculator` + +### Phase 4: Document + +- [ ] 12.4.1 Document utilization report endpoint +- [ ] 12.4.2 Verify all tests pass + +**Commit**: `docs(utilization-report): Update API documentation` + +--- + +## Capability 13: Cost Reporting +**Spec**: specs/cost-reporting/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 13.1.1 Write E2E test: View monthly cost report (test.fixme) +- [ ] 13.1.2 Write E2E test: Cost breakdown by project (test.fixme) +- [ ] 13.1.3 Write E2E test: Filter cost by project type (test.fixme) +- [ ] 13.1.4 Write E2E test: Group cost by client (test.fixme) +- [ ] 13.1.5 Write E2E test: Cost report for team member (test.fixme) +- [ ] 13.1.6 Write E2E test: Cost report for role (test.fixme) +- [ ] 13.1.7 Write E2E test: Calculate possible revenue (test.fixme) +- [ ] 13.1.8 Write E2E test: Calculate revenue gap (test.fixme) + +#### API Tests (Pest) +- [ ] 13.1.9 Write API test: GET /api/reports/cost returns data (->todo) +- [ ] 13.1.10 Write API test: Filter by project type (->todo) +- [ ] 13.1.11 Write API test: Group by client (->todo) +- [ ] 13.1.12 Write API test: Calculate possible revenue (->todo) +- [ ] 13.1.13 Write API test: Calculate revenue gap (->todo) +- [ ] 13.1.14 Write API test: Redis caching works (->todo) + +#### Unit Tests (Backend) +- [ ] 13.1.15 Write unit test: CostReportService aggregates (->todo) +- [ ] 13.1.16 Write unit test: Possible revenue calculation (->todo) +- [ ] 13.1.17 Write unit test: Revenue gap calculation (->todo) + +#### Component Tests (Frontend) +- [ ] 13.1.18 Write component test: CostTable displays (skip) +- [ ] 13.1.19 Write component test: Revenue chart renders (skip) +- [ ] 13.1.20 Write component test: Gap analysis displays (skip) + +**Commit**: `test(cost): Add pending tests for all reporting scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 13.2.1 Enable tests 13.1.15-13.1.17: Implement CostReportService +- [ ] 13.2.2 Enable tests 13.1.9-13.1.14: Implement cost endpoint +- [ ] 13.2.3 Enable tests 13.1.1-13.1.8: Create cost report UI + +**Commits**: +- `feat(cost): Implement cost report service` +- `feat(cost): Add cost report endpoint` +- `feat(cost): Create cost report UI with gap analysis` + +### Phase 3: Refactor + +- [ ] 13.3.1 Optimize cost aggregation queries +- [ ] 13.3.2 Extract RevenueCalculator +- [ ] 13.3.3 Improve gap visualization + +**Commit**: `refactor(cost): Optimize queries, extract calculator` + +### Phase 4: Document + +- [ ] 13.4.1 Document cost report endpoint +- [ ] 13.4.2 Verify all tests pass + +**Commit**: `docs(cost): Update API documentation` + +--- + +## Capability 14: Allocation Reporting +**Spec**: specs/allocation-reporting/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 14.1.1 Write E2E test: View allocation report for month (test.fixme) +- [ ] 14.1.2 Write E2E test: Allocation report with totals (test.fixme) +- [ ] 14.1.3 Write E2E test: Show utilization percentages (test.fixme) +- [ ] 14.1.4 Write E2E test: Show project allocation percentage (test.fixme) +- [ ] 14.1.5 Write E2E test: Filter allocation by team member (test.fixme) +- [ ] 14.1.6 Write E2E test: Filter allocation by role (test.fixme) +- [ ] 14.1.7 Write E2E test: Filter allocation by project status (test.fixme) +- [ ] 14.1.8 Write E2E test: Multi-month view option (test.fixme) + +#### API Tests (Pest) +- [ ] 14.1.9 Write API test: GET /api/reports/allocation returns matrix (->todo) +- [ ] 14.1.10 Write API test: Include utilization percentages (->todo) +- [ ] 14.1.11 Write API test: Filter by team (->todo) +- [ ] 14.1.12 Write API test: Filter by project status (->todo) +- [ ] 14.1.13 Write API test: Multi-month aggregation (->todo) +- [ ] 14.1.14 Write API test: Redis caching works (->todo) + +#### Unit Tests (Backend) +- [ ] 14.1.15 Write unit test: AllocationReportService aggregates (->todo) +- [ ] 14.1.16 Write unit test: Matrix formatting (->todo) +- [ ] 14.1.17 Write unit test: Multi-month calculation (->todo) + +#### Component Tests (Frontend) +- [ ] 14.1.18 Write component test: AllocationReportTable displays (skip) +- [ ] 14.1.19 Write component test: Totals calculate correctly (skip) +- [ ] 14.1.20 Write component test: Multi-month toggle works (skip) + +**Commit**: `test(allocation-report): Add pending tests for all reporting scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 14.2.1 Enable tests 14.1.15-14.1.17: Implement AllocationReportService +- [ ] 14.2.2 Enable tests 14.1.9-14.1.14: Implement allocation report endpoint +- [ ] 14.2.3 Enable tests 14.1.1-14.1.8: Create allocation report UI + +**Commits**: +- `feat(allocation-report): Implement allocation report service` +- `feat(allocation-report): Add allocation report endpoint` +- `feat(allocation-report): Create allocation report UI` + +### Phase 3: Refactor + +- [ ] 14.3.1 Optimize matrix generation queries +- [ ] 14.3.2 Extract AllocationMatrixFormatter +- [ ] 14.3.3 Improve multi-month view performance + +**Commit**: `refactor(allocation-report): Optimize queries, extract formatter` + +### Phase 4: Document + +- [ ] 14.4.1 Document allocation report endpoint +- [ ] 14.4.2 Verify all tests pass + +**Commit**: `docs(allocation-report): Update API documentation` + +--- + +## Capability 15: Variance Reporting +**Spec**: specs/variance-reporting/spec.md +**Scenarios**: 8 + +### Phase 1: Write Pending Tests (RED) + +#### E2E Tests (Playwright) +- [ ] 15.1.1 Write E2E test: View monthly variance report (test.fixme) +- [ ] 15.1.2 Write E2E test: Positive variance over-delivery (test.fixme) +- [ ] 15.1.3 Write E2E test: Negative variance under-delivery (test.fixme) +- [ ] 15.1.4 Write E2E test: Project variance summary (test.fixme) +- [ ] 15.1.5 Write E2E test: Person variance summary (test.fixme) +- [ ] 15.1.6 Write E2E test: Consistent over-delivery pattern (test.fixme) +- [ ] 15.1.7 Write E2E test: Filter variance by date range (test.fixme) +- [ ] 15.1.8 Write E2E test: Filter variance by project (test.fixme) + +#### API Tests (Pest) +- [ ] 15.1.9 Write API test: GET /api/reports/variance returns data (->todo) +- [ ] 15.1.10 Write API test: Calculate variance correctly (->todo) +- [ ] 15.1.11 Write API test: Flag over-delivery patterns (->todo) +- [ ] 15.1.12 Write API test: Filter by date range (->todo) +- [ ] 15.1.13 Write API test: Filter by project (->todo) +- [ ] 15.1.14 Write API test: Redis caching works (->todo) + +#### Unit Tests (Backend) +- [ ] 15.1.15 Write unit test: VarianceReportService calculates (->todo) +- [ ] 15.1.16 Write unit test: Pattern detection (->todo) +- [ ] 15.1.17 Write unit test: Aggregation by project/person (->todo) + +#### Component Tests (Frontend) +- [ ] 15.1.18 Write component test: VarianceTable displays (skip) +- [ ] 15.1.19 Write component test: Color coding works (skip) +- [ ] 15.1.20 Write component test: Trend chart renders (skip) + +**Commit**: `test(variance): Add pending tests for all reporting scenarios` + +### Phase 2: Implement (GREEN) + +- [ ] 15.2.1 Enable tests 15.1.15-15.1.17: Implement VarianceReportService +- [ ] 15.2.2 Enable tests 15.1.9-15.1.14: Implement variance endpoint +- [ ] 15.2.3 Enable tests 15.1.1-15.1.8: Create variance report UI + +**Commits**: +- `feat(variance): Implement variance report service` +- `feat(variance): Add variance report endpoint` +- `feat(variance): Create variance report UI with pattern detection` + +### Phase 3: Refactor + +- [ ] 15.3.1 Optimize variance calculation queries +- [ ] 15.3.2 Extract VarianceCalculator +- [ ] 15.3.3 Improve pattern detection algorithm + +**Commit**: `refactor(variance): Optimize queries, extract calculator` + +### Phase 4: Document + +- [ ] 15.4.1 Document variance report endpoint +- [ ] 15.4.2 Verify all tests pass + +**Commit**: `docs(variance): Update API documentation` + +--- + +## Final Phase: Polish & Documentation + +### 16. API Documentation (Backend) + +- [ ] 16.1 Add Scribe annotations to all controllers (verify complete) +- [ ] 16.2 Configure Scribe (scribe.php config file) +- [ ] 16.3 Generate API documentation (php artisan scribe:generate) +- [ ] 16.4 Verify SwaggerUI accessible at /api/documentation +- [ ] 16.5 Add example requests and responses to documentation +- [ ] 16.6 Add authentication section to API docs + +**Commit**: `docs(api): Complete API documentation` + +### 17. Testing & Code Quality + +- [ ] 17.1 Run full test suite (unit + feature + E2E) - all must pass +- [ ] 17.2 Generate code coverage report (verify >70%) +- [ ] 17.3 Run PHPStan static analysis (level 5+) +- [ ] 17.4 Run Laravel Pint and fix all issues +- [ ] 17.5 Run ESLint and fix all issues +- [ ] 17.6 Run Prettier formatting +- [ ] 17.7 Configure pre-commit hooks (husky + lint-staged) +- [ ] 17.8 Run security audit (composer audit, npm audit) +- [ ] 17.9 Fix all security vulnerabilities + +**Commits**: +- `chore(quality): Fix linting and static analysis issues` +- `chore(quality): Configure pre-commit hooks` +- `chore(security): Fix audit vulnerabilities` + +### 18. Polish & UX + +- [ ] 18.1 Add loading states (spinners, skeleton loaders) +- [ ] 18.2 Add error states (toast notifications, error pages) +- [ ] 18.3 Add empty states (no data placeholders) +- [ ] 18.4 Implement form validation feedback (inline errors, success messages) +- [ ] 18.5 Add confirmation modals for destructive actions (delete) +- [ ] 18.6 Implement responsive design (mobile-friendly tables, navigation) +- [ ] 18.7 Add keyboard shortcuts (ESC to close modals, etc.) +- [ ] 18.8 Add accessibility features (ARIA labels, focus management) +- [ ] 18.9 Test in multiple browsers (Chrome, Firefox, Safari) + +**Commits**: +- `feat(ui): Add loading and error states` +- `feat(ui): Add responsive design` +- `feat(ui): Add accessibility improvements` + +### 19. Documentation & Deployment + +- [ ] 19.1 Write README.md with setup instructions +- [ ] 19.2 Document environment variables (.env.example files) +- [ ] 19.3 Create Quick Start guide for managers (capacity β†’ allocate β†’ reports) +- [ ] 19.4 Document API authentication flow +- [ ] 19.5 Create deployment guide (Docker Compose production setup) +- [ ] 19.6 Add health check endpoints (/api/health) +- [ ] 19.7 Configure logging (Laravel logs to stdout, Svelte client errors to console) +- [ ] 19.8 Test full deployment workflow (fresh Docker Compose up) +- [ ] 19.9 Create superuser via seeder for initial login +- [ ] 19.10 Verify Nginx Proxy Manager routing + +**Commits**: +- `docs: Add README and setup instructions` +- `docs: Add deployment guide` +- `feat(ops): Add health check endpoints` + +### 20. Final Verification + +- [ ] 20.1 Run full test suite (unit + feature + E2E) and verify all pass +- [ ] 20.2 Verify code coverage >70% +- [ ] 20.3 Run linters and fix all issues +- [ ] 20.4 Test complete user flow: capacity β†’ allocate β†’ log actuals β†’ reports +- [ ] 20.5 Verify RBAC working for all 4 personas +- [ ] 20.6 Verify Redis caching working (check cache hit rate) +- [ ] 20.7 Verify API documentation accessible and accurate +- [ ] 20.8 Verify Docker Compose startup works cleanly +- [ ] 20.9 Verify database migrations and seeders work +- [ ] 20.10 Conduct final security review (no secrets in code, HTTPS enforced) + +**Commit**: `chore: Final verification complete` + +--- + +## Summary + +**Total Capabilities**: 15 +**Total Scenarios**: ~100 +**Total Tasks**: ~650 (reorganized from 328) + +### Test Coverage by Type: +- **E2E Tests (Playwright)**: ~120 tests (8 per capability avg) +- **API Tests (Pest)**: ~150 tests (10 per capability avg) +- **Unit Tests (Backend)**: ~150 tests (10 per capability avg) +- **Component Tests (Frontend)**: ~60 tests (4 per capability avg) +- **Unit Tests (Frontend)**: ~120 tests (8 per capability avg) + +### SDD + TDD Workflow Applied: +Each capability follows the 4-phase cycle: +1. **RED**: Write all pending tests from spec scenarios +2. **GREEN**: Enable tests one by one, implement minimal code +3. **REFACTOR**: Clean code while tests stay green +4. **DOCUMENT**: Generate API docs, verify coverage + +### Commit Message Convention: +- `test(): Add pending tests for...` +- `feat(): Implement...` +- `refactor(): ...` +- `docs(): ...` diff --git a/openspec/codemap.md b/openspec/codemap.md new file mode 100644 index 00000000..fb8ebabf --- /dev/null +++ b/openspec/codemap.md @@ -0,0 +1,19 @@ +# openspec/ + + + +## Responsibility + + + +## Design + + + +## Flow + + + +## Integration + + diff --git a/openspec/config.yaml b/openspec/config.yaml index 392946c6..1c23b7bd 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -1,20 +1,238 @@ schema: spec-driven -# Project context (optional) -# This is shown to AI when creating artifacts. -# Add your tech stack, conventions, style guides, domain knowledge, etc. -# Example: -# context: | -# Tech stack: TypeScript, React, Node.js -# We use conventional commits -# Domain: e-commerce platform +# 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) -# Per-artifact rules (optional) -# Add custom rules for specific artifacts. -# Example: -# rules: -# proposal: -# - Keep proposals under 500 words -# - Always include a "Non-goals" section -# tasks: -# - Break tasks into chunks of max 2 hours +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-` for OpenSpec changes + - **Commit format:** + ``` + [Type] Brief description (50 chars max) + + Detailed explanation (optional, 72 char wrap) + + Refs: openspec/changes/ + ``` + - **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//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(): 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(): Implement " + - 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(): " + + ## Phase 4: DOCUMENT + - Generate API docs: php artisan scribe:generate + - Verify all tests pass + - Commit: "docs(): 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 diff --git a/openspec/templates/PestFeatureTest.php b/openspec/templates/PestFeatureTest.php new file mode 100644 index 00000000..e17364d7 --- /dev/null +++ b/openspec/templates/PestFeatureTest.php @@ -0,0 +1,100 @@ +group('{{capability}}'); + +/* + * Test Template for Pest Feature Tests + * + * Copy this file and replace: + * - {{capability}} with the capability name (e.g., 'authentication') + * - {{scenario_description}} with the spec scenario description + * + * Mark pending tests with ->todo() during Red Phase + * Remove ->todo() and implement during Green Phase + */ + +describe('{{capability}} API', function () { + + // Use RefreshDatabase trait for clean state + uses(RefreshDatabase::class); + + beforeEach(function () { + // Setup code runs before each test + // e.g., create test user, authenticate, etc. + }); + + /* + * Scenario: {{scenario_description}} + * + * Spec Reference: specs/{{capability}}/spec.md + * Scenario: {{scenario_number}} + */ + it('{{scenario_description}}', function () { + // Arrange (GIVEN) + // Set up the initial state + + // Act (WHEN) + // Perform the action + $response = $this->postJson('/api/{{endpoint}}', [ + // Request data + ]); + + // Assert (THEN) + // Verify the expected outcome + $response->assertStatus(200) + ->assertJson([ + // Expected response structure + ]); + })->todo(); // Remove ->todo() when implementing + + /* + * Example: Error scenario + */ + it('returns error when {{error_condition}}', function () { + // Arrange + + // Act + $response = $this->postJson('/api/{{endpoint}}', [ + 'invalid' => 'data' + ]); + + // Assert + $response->assertStatus(422) + ->assertJsonValidationErrors(['field_name']); + })->todo(); + + /* + * Example: Authorization scenario + */ + it('returns 403 when user lacks permission', function () { + // Arrange: Create user without permission + $user = User::factory()->create(['role' => 'developer']); + + // Act + $response = $this->actingAs($user) + ->postJson('/api/{{admin_endpoint}}'); + + // Assert + $response->assertStatus(403); + })->todo(); + +}); + +/* + * Helper functions specific to this capability + */ +function create{{model}}(array $attributes = []): {{model}} +{ + return {{model}}::factory()->create($attributes); +} + +function authenticateUser(string $role = 'manager'): User +{ + $user = User::factory()->create(['role' => $role]); + + // Return authenticated user or token + return $user; +} diff --git a/openspec/templates/PestUnitTest.php b/openspec/templates/PestUnitTest.php new file mode 100644 index 00000000..47c5452e --- /dev/null +++ b/openspec/templates/PestUnitTest.php @@ -0,0 +1,92 @@ +group('{{capability}}', 'unit'); + +/* + * Test Template for Pest Unit Tests + * + * Copy this file and replace: + * - {{capability}} with the capability name + * - {{service}} with the class being tested + * + * Mark pending tests with ->todo() during Red Phase + * Remove ->todo() and implement during Green Phase + */ + +describe('{{service}}', function () { + + beforeEach(function () { + $this->service = new {{service}}(); + }); + + /* + * Test: {{method_description}} + * + * Tests the core logic of {{method_name}} + */ + it('{{method_description}}', function () { + // Arrange + $input = [ + // Test input data + ]; + + $expected = [ + // Expected output + ]; + + // Act + $result = $this->service->{{method_name}}($input); + + // Assert + expect($result)->toBe($expected); + })->todo(); + + /* + * Test: Edge case handling + */ + it('handles {{edge_case}} gracefully', function () { + // Arrange + $edgeCaseInput = null; + + // Act & Assert + expect(fn () => $this->service->{{method_name}}($edgeCaseInput)) + ->toThrow(\InvalidArgumentException::class); + })->todo(); + + /* + * Test: Calculation accuracy + */ + it('calculates {{calculation}} correctly', function () { + // Arrange + $a = 10; + $b = 20; + + // Act + $result = $this->service->calculate($a, $b); + + // Assert + expect($result)->toBe(30); + })->todo(); + +}); + +/* + * Data providers for parameterized tests + */ +dataset('valid_inputs', function () { + return [ + 'case 1' => [['input' => 'value1'], 'expected1'], + 'case 2' => [['input' => 'value2'], 'expected2'], + 'case 3' => [['input' => 'value3'], 'expected3'], + ]; +}); + +/* + * Example parameterized test + */ +it('processes valid inputs correctly', function ($input, $expected) { + $result = $this->service->process($input); + expect($result)->toBe($expected); +})->with('valid_inputs')->todo(); diff --git a/openspec/templates/PlaywrightE2ETest.spec.ts b/openspec/templates/PlaywrightE2ETest.spec.ts new file mode 100644 index 00000000..c89a2dd7 --- /dev/null +++ b/openspec/templates/PlaywrightE2ETest.spec.ts @@ -0,0 +1,137 @@ +import { test, expect } from '@playwright/test'; + +/* + * Test Template for Playwright E2E Tests + * + * Copy this file and replace: + * - {{capability}} with the capability name (e.g., 'authentication') + * - {{scenario_description}} with the spec scenario description + * + * Mark pending tests with test.fixme() during Red Phase + * Remove test.fixme() and implement during Green Phase + */ + +test.describe('{{capability}} Flow', () => { + + test.beforeEach(async ({ page }) => { + // Setup: Navigate to base URL, login, etc. + await page.goto('/'); + }); + + /* + * Scenario: {{scenario_description}} + * + * Spec Reference: specs/{{capability}}/spec.md + * Scenario: {{scenario_number}} + */ + test('{{scenario_description}}', async ({ page }) => { + // Arrange (GIVEN) + // Set up initial state + await page.goto('/{{route}}'); + + // Act (WHEN) + // Perform user actions + await page.fill('[name="email"]', 'test@example.com'); + await page.fill('[name="password"]', 'password'); + await page.click('button[type="submit"]'); + + // Assert (THEN) + // Verify expected outcome + await expect(page).toHaveURL('/dashboard'); + await expect(page.locator('[data-testid="success-message"]')).toBeVisible(); + await expect(page.locator('[data-testid="user-name"]')).toContainText('Test User'); + }); + + /* + * Example: Error scenario + */ + test('displays error when {{error_condition}}', async ({ page }) => { + // Arrange + await page.goto('/{{route}}'); + + // Act + await page.fill('[name="email"]', 'invalid@example.com'); + await page.fill('[name="password"]', 'wrongpassword'); + await page.click('button[type="submit"]'); + + // Assert + await expect(page.locator('[data-testid="error-message"]')).toBeVisible(); + await expect(page.locator('[data-testid="error-message"]')).toContainText('Invalid credentials'); + await expect(page).toHaveURL('/{{route}}'); + }); + + /* + * Example: Form validation + */ + test('validates required fields', async ({ page }) => { + // Arrange + await page.goto('/{{route}}'); + + // Act + await page.click('button[type="submit"]'); + + // Assert + await expect(page.locator('[data-testid="error-email"]')).toContainText('Email is required'); + await expect(page.locator('[data-testid="error-password"]')).toContainText('Password is required'); + }); + + /* + * Example: CRUD operation + */ + test('completes full {{resource}} CRUD flow', async ({ page }) => { + // Create + await page.goto('/{{resource}}/new'); + await page.fill('[name="name"]', 'Test {{resource}}'); + await page.click('button[type="submit"]'); + await expect(page.locator('[data-testid="success-message"]')).toBeVisible(); + + // Read + await page.goto('/{{resource}}'); + await expect(page.locator('text=Test {{resource}}')).toBeVisible(); + + // Update + await page.click('[data-testid="edit-{{resource}}"]'); + await page.fill('[name="name"]', 'Updated {{resource}}'); + await page.click('button[type="submit"]'); + await expect(page.locator('[data-testid="success-message"]')).toBeVisible(); + + // Delete + await page.click('[data-testid="delete-{{resource}}"]'); + await page.click('[data-testid="confirm-delete"]'); + await expect(page.locator('text=Updated {{resource}}')).not.toBeVisible(); + }); + + /* + * Example: RBAC test + */ + test('restricts access based on role', async ({ page }) => { + // Login as developer (limited permissions) + await loginAs(page, 'developer'); + + // Try to access admin page + await page.goto('/admin/{{resource}}'); + + // Should be redirected or show access denied + await expect(page.locator('[data-testid="access-denied"]')).toBeVisible(); + }); + +}); + +/* + * Helper functions + */ +async function loginAs(page, role: string) { + await page.goto('/login'); + await page.fill('[name="email"]', `${role}@example.com`); + await page.fill('[name="password"]', 'password'); + await page.click('button[type="submit"]'); + await expect(page).toHaveURL('/dashboard'); +} + +async function create{{model}}(page, data: object) { + await page.goto('/{{resource}}/new'); + for (const [key, value] of Object.entries(data)) { + await page.fill(`[name="${key}"]`, value); + } + await page.click('button[type="submit"]'); +} diff --git a/openspec/templates/VitestComponentTest.test.ts b/openspec/templates/VitestComponentTest.test.ts new file mode 100644 index 00000000..dd0e14b4 --- /dev/null +++ b/openspec/templates/VitestComponentTest.test.ts @@ -0,0 +1,174 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render, screen, fireEvent, waitFor } from '@testing-library/svelte'; +import {{component}} from './{{component}}.svelte'; + +/* + * Test Template for Vitest Component Tests + * + * Copy this file and replace: + * - {{component}} with the Svelte component name + * - {{capability}} with the capability name + * + * Mark pending tests with test.skip() during Red Phase + * Remove .skip and implement during Green Phase + */ + +describe('{{component}}', () => { + + beforeEach(() => { + // Reset mocks and state + vi.clearAllMocks(); + }); + + /* + * Test: Component renders correctly + */ + it.skip('renders with default props', () => { + const { container } = render({{component}}); + + expect(container.querySelector('[data-testid="{{component}}"]')).toBeInTheDocument(); + }); + + /* + * Test: Component displays data correctly + */ + it.skip('displays {{data_type}} data', () => { + const mockData = { + id: '123', + name: 'Test Name', + value: 100 + }; + + render({{component}}, { props: { data: mockData } }); + + expect(screen.getByText('Test Name')).toBeInTheDocument(); + expect(screen.getByText('100')).toBeInTheDocument(); + }); + + /* + * Test: User interaction + */ + it.skip('handles {{action}} click', async () => { + const mockHandler = vi.fn(); + + render({{component}}, { + props: { + on{{action}}: mockHandler + } + }); + + const button = screen.getByTestId('{{action}}-button'); + await fireEvent.click(button); + + expect(mockHandler).toHaveBeenCalledTimes(1); + }); + + /* + * Test: Form submission + */ + it.skip('submits form with correct data', async () => { + const mockSubmit = vi.fn(); + + render({{component}}, { + props: { + onSubmit: mockSubmit + } + }); + + // Fill form + await fireEvent.input(screen.getByLabelText('Name'), { + target: { value: 'Test Name' } + }); + + await fireEvent.input(screen.getByLabelText('Email'), { + target: { value: 'test@example.com' } + }); + + // Submit + await fireEvent.click(screen.getByText('Submit')); + + await waitFor(() => { + expect(mockSubmit).toHaveBeenCalledWith({ + name: 'Test Name', + email: 'test@example.com' + }); + }); + }); + + /* + * Test: Validation errors + */ + it.skip('displays validation errors', async () => { + render({{component}}); + + // Submit empty form + await fireEvent.click(screen.getByText('Submit')); + + await waitFor(() => { + expect(screen.getByText('Name is required')).toBeInTheDocument(); + expect(screen.getByText('Email is required')).toBeInTheDocument(); + }); + }); + + /* + * Test: Loading state + */ + it.skip('shows loading state', () => { + render({{component}}, { + props: { + loading: true + } + }); + + expect(screen.getByTestId('loading-spinner')).toBeInTheDocument(); + }); + + /* + * Test: Empty state + */ + it.skip('displays empty state when no data', () => { + render({{component}}, { + props: { + data: [] + } + }); + + expect(screen.getByText('No data available')).toBeInTheDocument(); + }); + + /* + * Test: Error state + */ + it.skip('displays error message', () => { + render({{component}}, { + props: { + error: 'Failed to load data' + } + }); + + expect(screen.getByText('Failed to load data')).toBeInTheDocument(); + }); + + /* + * Test: Accessibility + */ + it.skip('has accessible attributes', () => { + render({{component}}); + + const element = screen.getByRole('button'); + expect(element).toHaveAttribute('aria-label'); + }); + +}); + +/* + * Helper functions + */ +function createMock{{model}}(overrides = {}) { + return { + id: '123', + name: 'Test {{model}}', + createdAt: new Date().toISOString(), + ...overrides + }; +} diff --git a/openspec/templates/VitestUnitTest.test.ts b/openspec/templates/VitestUnitTest.test.ts new file mode 100644 index 00000000..7963b4e4 --- /dev/null +++ b/openspec/templates/VitestUnitTest.test.ts @@ -0,0 +1,205 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +/* + * Test Template for Vitest Unit Tests (Utilities, Stores, API Clients) + * + * Copy this file and replace: + * - {{module}} with the module name + * - {{capability}} with the capability name + * + * Mark pending tests with test.skip() during Red Phase + * Remove .skip and implement during Green Phase + */ + +describe('{{module}}', () => { + + beforeEach(() => { + // Reset state before each test + vi.clearAllMocks(); + }); + + /* + * Test: Core functionality + */ + it.skip('{{functionality_description}}', () => { + // Arrange + const input = { + // Test input + }; + + const expected = { + // Expected output + }; + + // Act + const result = {{module}}.{{method}}(input); + + // Assert + expect(result).toEqual(expected); + }); + + /* + * Test: Edge cases + */ + it.skip('handles {{edge_case}}', () => { + // Arrange + const edgeCaseInput = null; + + // Act & Assert + expect(() => {{module}}.{{method}}(edgeCaseInput)) + .toThrow('Invalid input'); + }); + + /* + * Test: Async operations + */ + it.skip('{{async_description}}', async () => { + // Arrange + const mockResponse = { data: 'test' }; + global.fetch = vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse) + }); + + // Act + const result = await {{module}}.{{async_method}}(); + + // Assert + expect(result).toEqual(mockResponse); + expect(fetch).toHaveBeenCalledWith('/api/{{endpoint}}'); + }); + + /* + * Test: Error handling + */ + it.skip('handles API errors', async () => { + // Arrange + global.fetch = vi.fn().mockResolvedValue({ + ok: false, + status: 500, + json: () => Promise.resolve({ message: 'Server error' }) + }); + + // Act & Assert + await expect({{module}}.{{async_method}}()) + .rejects.toThrow('Server error'); + }); + + /* + * Test: Store behavior (if testing Svelte stores) + */ + it.skip('updates store value', () => { + // Arrange + const store = {{module}}.{{store_name}}; + + // Act + store.set({ value: 'new value' }); + + // Assert + let value; + store.subscribe(v => { value = v; })(); + expect(value).toEqual({ value: 'new value' }); + }); + + /* + * Test: Store derived values + */ + it.skip('computes derived value correctly', () => { + // Arrange + const store = {{module}}.{{store_name}}; + store.set({ items: [1, 2, 3] }); + + // Act + let derivedValue; + {{module}}.{{derived_store}}.subscribe(v => { derivedValue = v; })(); + + // Assert + expect(derivedValue).toBe(6); // sum of items + }); + + /* + * Test: Validation logic + */ + it.skip('validates {{field}} correctly', () => { + // Valid cases + expect({{module}}.validate{{field}}('valid')).toBe(true); + expect({{module}}.validate{{field}}('another-valid')).toBe(true); + + // Invalid cases + expect({{module}}.validate{{field}}('')).toBe(false); + expect({{module}}.validate{{field}}(null)).toBe(false); + expect({{module}}.validate{{field}}('invalid!')).toBe(false); + }); + + /* + * Test: Calculation accuracy + */ + it.skip('calculates {{calculation}} correctly', () => { + expect({{module}}.calculate(10, 20)).toBe(30); + expect({{module}}.calculate(0, 0)).toBe(0); + expect({{module}}.calculate(-5, 5)).toBe(0); + }); + + /* + * Test: Formatting functions + */ + it.skip('formats {{data_type}} correctly', () => { + expect({{module}}.format{{data_type}}(1000)).toBe('$1,000.00'); + expect({{module}}.format{{data_type}}(0)).toBe('$0.00'); + expect({{module}}.format{{data_type}}(-500)).toBe('-$500.00'); + }); + + /* + * Test: Date/time utilities + */ + it.skip('parses date correctly', () => { + const result = {{module}}.parseDate('2024-01-15'); + expect(result).toBeInstanceOf(Date); + expect(result.getFullYear()).toBe(2024); + expect(result.getMonth()).toBe(0); // January is 0 + expect(result.getDate()).toBe(15); + }); + + it.skip('formats date as YYYY-MM', () => { + const date = new Date(2024, 0, 15); // January 15, 2024 + expect({{module}}.formatMonth(date)).toBe('2024-01'); + }); + + /* + * Test: Local storage operations + */ + it.skip('saves to localStorage', () => { + const data = { key: 'value' }; + {{module}}.saveToStorage('test-key', data); + + expect(localStorage.setItem).toHaveBeenCalledWith( + 'test-key', + JSON.stringify(data) + ); + }); + + it.skip('loads from localStorage', () => { + const data = { key: 'value' }; + localStorage.getItem.mockReturnValue(JSON.stringify(data)); + + const result = {{module}}.loadFromStorage('test-key'); + + expect(result).toEqual(data); + }); + +}); + +/* + * Data providers for parameterized tests + */ +const testCases = [ + { input: 'case1', expected: 'result1' }, + { input: 'case2', expected: 'result2' }, + { input: 'case3', expected: 'result3' }, +]; + +it.skip('processes multiple cases correctly', () => { + testCases.forEach(({ input, expected }) => { + expect({{module}}.process(input)).toBe(expected); + }); +});