Files
headroom/devnotes.md

1363 lines
88 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dev Notes
I am trying to solve a peculiar issue that I am facing in my work. I manage a team of developers. I manage multiple projects at the same time.
Facts:
- The projects have different stages in their lifetime.
- Select developers are assigned to a project.
- These developers will have hours allocated for each project.
- Essentially, there is a matrix of projects <-> devs.
- Then there is the actual hours they burn in the project.
What I need out of this product:
- A way to get the allocations for each month for the team.
- Get a forecast for future
- Plan resourcing
- Billing forecasts
- Record keeping of PRojects, team, billing.
So far I have jotted down some data. let us brainstorm and if needed I can share what I have noted (either all at once or as pieces.). The product is not named as of now.
## Interview 1
- How big is your team? (5 devs? 20?)
- 10-15 folks
- How many concurrent projects typically?
- 10-12 in various phases.
- Is this just for you as a manager, or will devs also use it?
- I have ideated 4 personas. (Superuser, Managers, Devs and Top Brass)
- Any existing tools you're using (spreadsheets, Jira, etc.)?
- I use a spreadsheet and it is a nightmare.
- Allocation = planned hours (what you intend to assign)
- Example: A project might have 120 hours estimate. There, 10 hours for UX, 40 hrs for Dev, 30 hrs for QA, 10 hrs for PM, 10 hrs for Architect... These are the "allocations" for each person.
- Actual/Burned = real hours worked (what actually happened)
- Yes.
1. Do you track at project level, or sub-project/task level too?
- Project level only.
2. Any integration needs? (invoicing, accounting software)
- No.
3. Technical preference? (web app, CLI, spreadsheet template)
- Web App
---
Now I have a clearer picture. Let me visualize this:
Your Scope
┌─────────────────────────────────────────────────────────────────┐
│ PERSONAS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ SUPERUSER MANAGERS DEVS TOP BRASS │
│ ──────── ─────── ───── ───────── │
│ • Setup • Plan resources • See • Reports │
│ • Config • Assign allocations • allocations│ • Forecasts│
│ • Admin • Track burn • Log hours • Budget │
│ • Report │
│ │
└─────────────────────────────────────────────────────────────────┘
The Data Model
┌─────────────────────────────────────────────────────────────────┐
│ PROJECTS │
│ ──────────────────────────────────────────────────────────── │
│ • id, name, client │
│ • stage: Discovery → Design → Dev → QA → Deploy → Live │
│ • start_date, end_date (planned) │
│ • billing_type: T&M / Fixed / Retainer │
│ • hourly_rate (for billing) │
└───────────────────────┬─────────────────────────────────────────┘
│ 1:N (one project has many allocations)
┌─────────────────────────────────────────────────────────────────┐
│ ALLOCATIONS │
│ ──────────────────────────────────────────────────────────── │
│ • id │
│ • project_id │
│ • role: UX, Dev, QA, PM, Architect │
│ • developer_id (optional - can assign to role vs person) │
│ • estimated_hours │
│ • period: Jan 2026, Feb 2026... (monthly breakdown) │
└───────────────────────┬─────────────────────────────────────────┘
│ 1:N (track actuals against allocation)
┌─────────────────────────────────────────────────────────────────┐
│ ACTUALS │
│ ──────────────────────────────────────────────────────────── │
│ • id │
│ • allocation_id │
│ • developer_id │
│ • date │
│ • hours_logged │
│ • notes (optional) │
└─────────────────────────────────────────────────────────────────┘
---
I am skipping the schematic diagram for now because that did not capture the big picture.
See my comments inline and later an explainer.
The Outputs You Need
| Output | What It Means |
|--------|---------------|
| Monthly Allocation | Who is assigned to what, for how many hours, this month | ==> YES
| Forecast | Given current allocations + burn rate → what does next 3 months look like? | ==> YES
| Resource Plan | Who's overallocated? Underallocated? Available for new work? | ==> YES YES YES! This is the most important piece
| Billing Forecast | Hours × Rate = Revenue per project/client | ==> YES
| Record Keeping | Audit trail of what was planned vs what happened | ==> YES
---
Key Insights I'm Seeing
1. Role vs Person allocation - You mentioned "10 hrs for Dev" not "10 hrs for Santhosh" - this is smart. Allows flexible staffing.
- WRONG. Please see my explainer in below section.
2. The allocation breakdown - Your 120hr example (UX:10, Dev:40, QA:30, PM:10, Arch:10) is essentially a budget per project.
- Yes. Each person will have different billing rates. So, these allocations are $$$
3. The "matrix" you mentioned - That's really a capacity view: "Dev A is 60% on Project X, 40% on Project Y this month"
---
A few more questions:
1. Stages - Do projects move through stages sequentially, or work happens across stages in parallel?
- See the explainer section.
2. Historical data - Will you import past projects, or start fresh?
- No. Its a Greenfield.
3. MVP definition - What's the one thing this tool MUST do first? (e.g., just track allocations? Or include time entry?)
- 3 things.
- Team setup
- Capacity planning
- Project onboarding/status.
- Respective reports of the above (see the outputs for each area in my explainer)
- Further,
- Project to Resource allocation
- Resources monthly allocation (because resources will be allocated for multiple projects for every month)
- Detailed reporting.
**EXPLAINER**
We need to revise this. Before all these, every month, I do a capacity planning. That is when I look at any holiday's team members' PTO plans etc.
Capacity tracking
• List of team members
o Team
o Name
o Hourly rate
• Days of month
• Holidays
• PTOs
• Weekends
• Availability
o 0
o 1
o .5
o Or percentage
Output of this exercise:
**Individual capacity**
**Summarize total available person days as Team capacity**
**Total possible revenue**
Project Data
• Status
o NA/Support
o Initial
o Gathering estimates
o Estimate pending approval
o Estimate rework
o Estimate approved
o Funded
o Scheduled
o In-progress
o Ready for prod
o Done
o On-hold
o Cancelled
• Project ID
• Type cost head
o Project
o Support
• Project title
• Approved estimate
• Forecasted effort
Output of this part:
**Month-wise forecast**
**Total hours forecasted per month should be matching the respective months capacity**
**Identifiers for over forecast, under forecast should be there**
Resource Allocation
For a selected month =>
• All projects forecasted for that month should display, with forecasted total hours.
• Hours allocated (calculated field)
• Allocation for the project (calculated % field)
• All resources in columns
• Allocated hours for each team member against the project.
• Indicators for over allocation of project and resource should be there.
• Have an untracked resource to accommodate the hours for someone from other team.
Project-Resource mapping actuals
• Similar to resource allocation
• Instead of allocation, actual times logged to be accumulated here (Monthly). --> This is a manual process. As of now, no integration with Time tracking tool.
Output of this part:
- **Running utilization** --> A %age calculation of how much are they allocated vs How much capacity they had until now.
- **overall utilization** --> %age of how much they are allocated for each month.
(displayed along with the capacity)
---
For team members
• Project allocations should be tabulated
• New allocations should be shown in notification
• Team member can split the allocated monthly hours for each project into weekly or daily splits.
• The same can be used for time logging.
Output of this phase:
- Team members know how much they are allocated for each project --> Do not overcharge or undercharge any project.
Overall Reports
1. Forecast summary multi-period
2. Utilization summary
3. Cost summary
We need a lot more debating before we touch the code.
## INTERVIEW 2
Thank you for the detailed explainer - this changes my understanding significantly. Let me re-frame and ask some clarifying questions.
---
Revised Understanding
┌─────────────────────────────────────────────────────────────────┐
│ MONTHLY CAPACITY PLANNING CYCLE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ STEP 1: CAPACITY STEP 2: PROJECTS │
│ ─────────────────── ───────────────────── │
│ • Team members • Project status │
│ • Hourly rates • Forecasted effort │
│ • Holidays/PTO • Month-wise forecast │
│ • Availability % │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ INDIVIDUAL CAPACITY │ │
│ │ TEAM CAPACITY (person-days) │ │
│ │ POSSIBLE REVENUE ($) │ │
│ └─────────────────────────────────────────┘ │
│ │
│ STEP 3: RESOURCE ALLOCATION (per month) │
│ ──────────────────────────────────────────── │
│ • Which project gets which person, how many hours │
│ • Check: Project over-allocated? Person over-allocated? │
│ │
│ STEP 4: ACTUALS (manual entry) │
│ ───────────────────────────────────── │
│ • What actually got logged │
│ • Running utilization vs Overall utilization │
│ │
└─────────────────────────────────────────────────────────────────┘
---
Schematic diagram looks good.
Questions for Clarification
1. Availability model
You mentioned 0, 1, 0.5 or percentage. Can you give me an example?
- Is it like: A person is 100% available (1.0) = 8 hours/day?
- Or does 0.5 mean they only work 4 hours?
- Or does it mean they're 50% on this project, 50% on another?
==> Hours per day must be configurable per project. 1 means, 100% of a productive day. .5 means half of that and so on. I dont want to make it too granular thats why I had stops on 1, .5 and 0. Then there are H - holidays and O- weekend offs.
2. The "untracked resource"
You mentioned: "Have an untracked resource to accommodate the hours for someone from other team."
- Is this for contractors/freelancers who aren't in your team list?
- Or for internal overhead (meetings, training)?
==> We might have some time allocated for DevOps team which is not part of my team but might out bill to another team. For that purpose.
3. Team structure
You have "Team" in the member list. Does this mean sub-teams? (e.g., "Frontend", "Backend", "Design")
=> Yes. Read that as "Role"
4. Project types
"Cost head" - Project vs Support. What's the difference? Support = ongoing maintenance?
=> Yes. Project is billed to another team. Support is ongoing Ops Support.
5. Billing rates
- Per person hourly rate - is this what you charge the client?
- Or is there a markup/profit margin calculation?
=> Per person hourly rate.
6. The "over/under forecast" indicators
- Over forecast = project needs more hours than team capacity?
- Under forecast = capacity exceeds project needs?
- What action do you take when you see these?
==> Scenario is like, there say there is a project of 100hrs that spans over 2 months. I may be put 80hrs in first month and rest in the following. What if I mess up the splitting? Aftereffects of those mess ups are... examples here:
- Over forecast = Approved estimate is 100hrs. but we allocated 120hrs. --> We are going to overcharge the customer. Unhappy customer/expect escalation
- Under forecast = Approved is 100hr, we allocated 80hrs. --> We will undercharge the customer. Happy customer, unhappy manager. Get ready for the song.
- No action needed. There must be a clear indicator that stands out. So that we can course correct the allocation.
## INTERVIEW 3
So "over/under forecast" is about allocation vs approved estimate, NOT allocation vs capacity. Right?
==> In the project's context, yes. it is allocation vs approved. (For the future phases, there will be over/under forecase for resources - that will be based on individual's allocation vs their capacity. May be we can keep that aside for now.)
Project "X" has Approved Estimate: 100hrs
Month 1 allocation: 80hrs → Under-forecast (OK) ==> Not OK. Because this money is my salary! We always try to be on par - 100%. If it is under-forecast, call that out.
Month 2 allocation: 50hrs → Over-forecast (WARNING: will overcharge) ==> Yes. RED!
Two more quick questions:
1. Untracked resource billing - Is this billed at a different rate, or just tracked as a cost without revenue? ==> no billing tracked for them. it is like the joker in a deck of cards. We may just park some hours there.
2. Time logging - For "Project-Resource mapping actuals", do you just log total hours per month per person per project? Or daily? ==> MONTHLY, but might update weekly (incrementally)
---
Summary So Far
┌─────────────────────────────────────────────────────────────────┐
│ CAPACIT (working name?) │ ==> I am unable to decide on a name. Need help. :D
│ Resource Planning & Capacity Tool │
├─────────────────────────────────────────────────────────────────┤
│ │
│ CORE CONCEPTS: │
│ ───────────── │
│ • Person has: Name, Role/Team, Hourly Rate, Availability │ ==> CORRECT
│ • Availability: 1=full day, .5=half day, 0=unavailable │ ==> CORRECT. 0 = unavailable or PTO
│ • Plus Holidays (H), Weekends (O) │ ==> CORRECT
│ │
│ PROJECT: │
│ ─────── │
│ • Status: NA/Support → Initial → Estimates → Funded → ... │ ==> CORRECT
│ • Type: Project (billable) / Support (ops) │ ==> CORRECT
│ • Approved Estimate: total hours approved │ ==> CORRECT
│ • Forecasted Effort: how you split across months │ ==> CORRECT
│ │
│ ALLOCATION: │
│ ────────── │
│ • Month-by-month, project-by-person hours │ ==> CORRECT
│ • Compare to approved estimate → over/under indicator │ ==> CORRECT
│ • Untracked resource bucket for external team time │ ==> CORRECT
│ │
│ ACTUALS: │
│ ─────── │
│ • Manual time entry (monthly aggregate) │ ==> CORRECT
│ • Running utilization vs Overall utilization │ ==> CORRECT
│ │
│ REPORTS: │
│ ──────── │
│ • Forecast summary (multi-period) │ ==> CORRECT
│ • Utilization summary │ ==> CORRECT
│ • Cost summary │ ==> CORRECT
│ │
└─────────────────────────────────────────────────────────────────┘
If it is good to record it now, here are some things I would like to call out:
- All reports must be highly customizable with filters.
- Need to define taxonomy for all configurable items, and must have a master data for those.
- Support for multi-tenancy.
Yes, it captures the essense. When do we get into the weeds?
## RESPONSE
Excellent - this is great detail. Let me capture these additions:
Additions Noted
| Requirement | What It Means |
|-------------|---------------|
| Customizable Reports | Filters by team, person, project, status, date range, type |
| Master Data / Taxonomy | Configurable lists for roles, statuses, types, availability options |
| Multi-tenancy | Multiple organizations can use the same instance, isolated from each other |
---
Naming Ideas
Since your directory is already capacit, here are some options:
| Name | Rationale |
|------|-----------|
| Capacit | Your directory name - simple, relates to capacity |
| TeamPulse | Rhythm of the team, utilization heartbeat |
| ResourceIQ | Smart resource planning |
| CapacityOS | Operating system for capacity |
Or something entirely different? I'm bad at naming - what resonates with you?
==> My pick: Headroom
It's the word managers actually say ("do we have headroom for this?"), it immediately signals capacity planning, and it's memorable without being try-hard. It also captures the over/under allocation anxiety that's central to the whole tool.
Close runner-up would be Margin — because this tool is literally about protecting margin through accurate forecasting.
---
Before We Build
Since you said "before starting the build," let me confirm what's left to debate:
Architectural decisions:
1. Multi-tenancy approach - For MVP, should we build multi-tenant from day 1, or start single-tenant and add later?
- My recommendation: Start single-tenant. Add tenant_id column when needed. Premature multi-tenancy adds complexity. ==> AGREED
2. Tech stack - Any preference? (e.g., Next.js, React + Node, etc.) ==> I would like to go with Laravel based stack. Thoughts?
3. Database - Any preference? (SQLite for local, PostgreSQL for production?) ==> Postgres from the start.
4. Authentication - Do you need login/accounts, or is this something you run locally? ==> Login accounts.
From get go, everything must be containerised. Do not add any proxy manager (NPM, Caddy, or Traefik). My environment already runs an NPM.
Should we discuss about the thumb rules/standing instructions for the project now?
## INTERVIEW 4
Can you give me some examples of what you have in mind? Are you thinking about:
1. Coding standards - PHP/Laravel conventions, naming, code organization ==> AGREED
2. Project structure - How to organize controllers, models, services ==> AGREED
3. API design - REST conventions, response formats, error handling
4. Database conventions - Naming tables/columns, migrations approach
5. Git workflow - Branch naming, commit messages, PR process
6. Testing requirements - Unit tests, feature tests, coverage targets
7. Documentation - Code comments, API docs, README expectations
==> While we can agree on industry standard practices for the above items, once we have everything settled and ready to start, the project level config.yml (OpenSpec) must be updated to have the following:
1. Every change must have unit tests, E2E test, regression tests (with other scope documents) added to it whether I prompt it or not.
2. Changes must end with code review for style, standard, security.
3. Verification (/opsx-verify) must trigger checking of uncovered code (code that is not tested).
4. Commits must be granular. One fix - one commit.
5. Tests run in a progressive loop. Test -> Create issue in repo -> After test is completed -> Fix the issue -> Retest + Regression test. This must be done until all issues are fixed. I know this will be a time taking process. But I believe it will be worth it. Thoughts?
We need to decide on the E2E framework.
I chose Laravel because of my PHP background. Debate me if that is not a good choice. May be Laravel + Svelte? Or Sveltekit itself?
```Switched over to Sonnet 4.5```
## INTERVIEW 5
Part 1: Project-Level Standing Instructions (config.yml)
Your 5 points are solid and disciplined. This is a high-bar, quality-focused workflow. My thoughts:
On point 5 (test → issue → fix → retest loop):
This is rigorous, but I want to make sure we're aligned on scope. You're describing a defect-driven test cycle, which is excellent for catching edge cases. My question:
- Is this for ALL tests, or specifically for E2E/integration tests where bugs surface?
- Unit tests are usually fixed in the same commit (they're fast), but E2E bugs might need a separate issue. Clarify?
==> I agree. Let us go for a kill only in E2E and Integration.
Concerns I'd raise:
- This workflow is thorough but can slow velocity. For an MVP, consider whether you want this rigor from day 1, or if we should start with "every change has tests" and add the issue-loop in phase 2?
- The code coverage check in /opsx-verify is smart, but which threshold? (80%? 90%?)
My recommendation:
Agree to all 5 points, but for MVP we start with "every test must pass before merge" and defer the granular issue-tracking loop to phase 2 when you have more tests to manage. Thoughts? ===>Agreed
---
Part 2: Frontend Stack
You chose Laravel for the backend (good choice for PHP background). Now frontend:
Option 1: Laravel + Blade Templates
- Pros: Everything in one framework, you know Laravel
- Cons: Less interactive UI, harder to build responsive dashboards
Option 2: Laravel + Vue.js
- Pros: Interactive UI, Laravel ecosystem integrates well, good for dashboards
- Cons: Adds JS complexity, Vue has opinions
Option 3: Laravel API + SvelteKit (separate) ==> I will choose this.
- Pros: SvelteKit is modern, reactive, great for dashboards
- Cons: Two separate projects, more deployment complexity, you'd be learning Svelte
Option 4: Laravel API + React
- Pros: React is industry standard, great dashboard libraries
- Cons: You'd be learning React, more opinionated
---
My honest take:
For Headroom (a data-heavy dashboard with charts, filters, real-time updates):
- Laravel + Vue.js = best sweet spot. You get interactivity without leaving the Laravel ecosystem. Vue is approachable.
- SvelteKit separate = tempting but adds deployment complexity for MVP. Save for later if you want to refactor.
What's your instinct? Do you want to stay in the Laravel world (Blade/Vue), or are you open to learning a new frontend framework? ===> Sveltekit it is!
---
Questions Before We Formalize
1. Test threshold - What code coverage % for /opsx-verify? => Let us call it >70%
2. Issue-loop timing - MVP (simple tests only) or from day 1 (rigorous)? =>agreed with you in above section.
3. Frontend - Laravel + Vue, or something else? ==> Laravel + Sveltekit
Is there anything else we need to talk about? the stack/infrastructure/choice of UI framework/something that I dont know?
Once we align here, I'll capture everything in OpenSpec and we can start building.
▣ Plan · claude-haiku-4-5 · 11.0s
## INTERVIEW 6
Remaining Architectural Decisions
1. API Communication
- Laravel API → SvelteKit via REST or GraphQL? ==> It is already heavy. So, I will stick to REST.
- My take: REST is simpler for MVP. GraphQL adds tooling complexity. ==> AGREE
- Should we use Laravel API Resources for consistent JSON responses? ==> YES. Resources.
2. Authentication Architecture
- Session-based (Laravel sessions) or Token-based (JWT)?
- My take: Session-based is easier for same-origin setup. JWT if you ever want mobile apps later. ==> I will go with JWT.
3. Real-time Updates
- You mentioned "monthly updates, weekly increments" on actuals. Do you need live updates (WebSockets), or is polling OK?
- My take: Start with polling (SvelteKit can refetch on interval). Add WebSockets if needed. ==> I dont think we need to sweat on it. Go with a basic implementation. Polling is good enough.
4. Containerization Details
- Single container (Laravel + SvelteKit) or two containers (separate)?
- My take: Two containers (Laravel API on port 3000, SvelteKit on port 5173, both behind your NPM reverse proxy). Cleaner separation. ==> Agreed
- Volume mounts for PostgreSQL? ==> Yes. Mount it to a directory --> Good for portability.
5. Development Environment
- Docker Compose for local dev, or native Laravel/Node setup?
- My take: Docker Compose from the start. Ensures prod parity. ==> 100% agree. If possible, we should have at least the local dev avoid building after every change (may be code mounted)
6. Environment Configuration
- .env files or Docker secrets?
- My take: .env files for local, Docker secrets in prod (when you deploy). ==> .env everywhere
---
What You Might Not Have Considered
State Management (SvelteKit)
- Svelte stores for client-side state? Or fetch-as-needed?
- My recommendation: Start with fetch-as-needed, add stores only if you have complex shared state. ==> Agreed.
Error Handling & Validation
- Laravel's validation → SvelteKit form handling
- Should we use something like Zod for shared validation schemas?
- My recommendation: Laravel validates, SvelteKit shows errors. Simple. ==> I agree. But how about something like Superform or Zod?
Reporting & Export
- You mentioned "customizable reports" - will users need PDF/CSV exports?
- My recommendation: Start with on-screen reports, add exports in phase 2. ==> Good to have at this time.
Search & Filtering
- Database-driven (query filters) or in-memory (load all, filter client)?
- My recommendation: Database queries for large datasets, client-side for small. ==> Agreed.
---
Should we talk about a caching layer?
---
Once these are settled, we're ready to formalize in OpenSpec and start building.
▣ Plan · claude-haiku-4-5 · 9.6s
## INTERVIEW 7
Excellent progress. Let me address the remaining items:
---
Error Handling & Validation
Superforms + Zod is a great choice. Here's why:
Laravel validates API input (first layer)
SvelteKit receives response with errors
Zod schema mirrors Laravel validation (type safety)
Superforms handles form state + errors (UX)
This approach:
- Ensures type safety on the frontend
- Superforms handles loading states, optimistic updates
- Single source of truth for validation logic (Zod)
- Users see errors immediately
Recommendation: Use Zod + Superforms. Define schemas once, use everywhere.
---
Report Exports (PDF/CSV)
You said "Good to have at this time" - I want to clarify:
Should exports be in MVP scope, or phase 2?
Reasons to include in MVP:
- Managers often need to send reports to stakeholders
- Relatively straightforward (HTML → PDF via wkhtmltopdf or similar)
- CSV is trivial
Reasons to defer:
- Adds complexity to reporting UI
- MVP value is the interactive dashboard, not exports
- Can add in 1-2 sprints
My recommendation: Start with on-screen reports only. Add exports in phase 2 (1-2 weeks later). This keeps MVP scope tight.
What's your call?
---
Caching Layer
Yes, good question. In what context?
Option 1: Database Query Caching
- Cache expensive queries (e.g., capacity calculations, forecasts)
- Tools: Redis, or Laravel's built-in cache
- When to invalidate: When allocations/actuals change
Option 2: API Response Caching
- Cache GET endpoints (reports, summaries)
- SvelteKit can cache too (via response headers)
Option 3: Full-page caching
- Cache entire dashboard views
- Overkill for MVP
My recommendation for MVP:
- Start without caching. Queries are likely fast until you have years of data.
- Add Redis in phase 2 if dashboard feels slow, or when you have 1000+ projects.
Does that make sense, or do you anticipate needing caching from day 1?
---
Final Architectural Summary
┌─────────────────────────────────────────────────────────┐
│ HEADROOM ARCHITECTURE │
├─────────────────────────────────────────────────────────┤
│ │
│ BACKEND │
│ ──────── │
│ • Laravel API (port 3000) │
│ • PostgreSQL (mounted volume) │
│ • Laravel Resources for JSON responses │
│ • JWT authentication │
│ • Docker container + .env config │
│ │
│ FRONTEND │
│ ──────── │
│ • SvelteKit (port 5173) │
│ • Zod + Superforms (validation & forms) │
│ • Client-side stores (minimal, as-needed) │
│ • REST API calls (polling for updates) │
│ • Docker container + .env config │
│ │
│ DEPLOYMENT │
│ ────────── │
│ • Docker Compose (local dev, code-mounted) │
│ • NPM reverse proxy (already running) │
│ • .env files (all environments) │
│ │
│ QUALITY │
│ ─────── │
│ • All changes: Unit + E2E + Regression tests │
│ • Code coverage: >70% (checked in /opsx-verify) │
│ • E2E failures: create issue, fix, retest (phase 2) │
│ • Granular commits (one fix = one commit) │
│ • Code review (style, security, standards) │
│ │
└─────────────────────────────────────────────────────────┘
---
Before We Formalize
Just to confirm:
1. Exports - Defer to phase 2? Or include in MVP? ==> Phase 2
2. Caching - Start without, add in phase 2? ==> Query caching and Response caching on Redis from Day 1. No need to sweat on refactoring it everywhere.
3. Anything else that feels unresolved?
Once these are locked, I'll create the OpenSpec change and we start building.
## INTERVIEW 8
Great - Redis caching from day 1 is smart. No technical debt there.
Now, frontend libraries - let me ask some clarifying questions:
---
Frontend Libraries - Key Questions
1. Charts & Visualization
You need dashboards with:
- Monthly capacity/allocation views (tables with conditional formatting)
- Forecast charts (line charts across months)
- Utilization percentages (gauges, progress bars)
- Cost summaries (bar charts, pie charts)
Which do you prefer?
- Recharts - React-style, works well with Svelte, good Svelte integration
- Chart.js - Simpler, lightweight
- Plotly - More advanced
- Apache ECharts - Powerful, steeper learning curve
My recommendation: Recharts. Good balance of power and simplicity. ==> Agreed
---
2. UI Component Library
Do you want a pre-built component system?
- Shadcn/ui - Headless, customizable, works with SvelteKit
- DaisyUI - Tailwind-based, opinionated but fast
- Svelte Material UI - Full-featured
- Build custom with Tailwind - More control, slower initial development
My recommendation: Shadcn/ui (if you want polish) or DaisyUI (if you want speed). I'd lean DaisyUI for MVP - faster to build dashboards. ==> Daisy it is.
---
3. Tables & Data Grid
You need:
- Sortable, filterable tables (allocations, actuals)
- Inline editing (allocations)
- Pagination or virtualization (for large datasets)
Options:
- TanStack Table (React Table) - Headless, works with Svelte, very powerful
- Svelte DataTable - Simpler, less flexible
- Build custom with Svelte - Full control
My recommendation: TanStack Table. It's the industry standard and works great with SvelteKit. ==> I am not familiar with this. but I will go with your recommendation.
---
4. Form Handling
You chose Superforms + Zod (good). Should we add:
- SvelteKit Form Actions - Native SvelteKit approach, works seamlessly with Superforms
- Or direct API calls?
My recommendation: Use SvelteKit Form Actions + Superforms. Native, elegant, built for this. ==> Agreed.
---
5. Styling
- Tailwind CSS - The standard, highly recommended
- Other?
My recommendation: Tailwind + DaisyUI. Fast development, consistent theming. ==> Agreed.
---
6. State Management for Complex Flows
You said fetch-as-needed, but do you want:
- SvelteKit stores for things like: "current month filter", "selected project"?
- Or always fetch from API?
My recommendation: Use Svelte stores for UI state (filters, modals), API queries for data. ==> Agreed.
---
My Recommended Frontend Stack
┌─────────────────────────────────────────────────────────┐
│ FRONTEND TECH STACK │
├─────────────────────────────────────────────────────────┤
│ │
│ Framework: SvelteKit │
│ Styling: Tailwind CSS + DaisyUI │
│ Charts: Recharts │
│ Tables: TanStack Table (React Table) │
│ Forms: Superforms + Zod │
│ Form Actions: SvelteKit native │
│ State: Svelte stores (minimal) │
│ HTTP Client: fetch (native) │
│ Testing: Vitest (unit) + Playwright (E2E) │
│ │
└─────────────────────────────────────────────────────────┘
▣ Plan · claude-haiku-4-5 · 10.8s
## INTERVIEW 9
You're right to do a final review before locking in. Let me run through the complete architecture holistically:
---
Complete Headroom Architecture - Final Review
BACKEND (Laravel)
✓ Framework: Laravel 11
✓ Database: PostgreSQL (Docker volume mount)
✓ API Design: REST with Laravel Resources
✓ Authentication: JWT (token-based)
✓ Caching: Redis (Query + Response caching from day 1)
✓ Testing: PHPUnit (unit) + Pest/PHPUnit (feature)
✓ Containerization: Docker (port 3000)
✓ Environment: .env files (all environments)
✓ Code Standards: PSR-12, Laravel conventions
Potential Gap I'm seeing:
- Background Jobs - Will you need queuing for async tasks? (e.g., report generation, notifications)
- My take for MVP: Start without. Add Laravel Queue (Redis-backed) in phase 2 if needed.
---
FRONTEND (SvelteKit)
✓ Framework: SvelteKit
✓ Styling: Tailwind CSS + DaisyUI
✓ Charts: Recharts
✓ Tables: TanStack Table (React Table)
✓ Forms: Superforms + Zod + SvelteKit Form Actions
✓ State: Svelte stores (minimal, UI state only)
✓ HTTP: fetch (native)
✓ Testing: Vitest (unit) + Playwright (E2E)
✓ Containerization: Docker (port 5173)
✓ Environment: .env files
Potential Gap I'm seeing:
- Notifications/Alerts - When allocation changes, do devs get notified?
- My take for MVP: Skip notifications. Add in phase 2.
---
DEPLOYMENT & INFRASTRUCTURE
✓ Local Dev: Docker Compose (code-mounted, hot reload)
✓ Reverse Proxy: Your existing NPM (no Caddy/Traefik)
✓ Container Ports: Laravel 3000, SvelteKit 5173
✓ Database Volumes: Mounted for portability
✓ Secrets: .env files (no Docker secrets for MVP)
---
QUALITY STANDARDS (OpenSpec config)
✓ Testing: Unit + E2E + Regression on every change
✓ Coverage: >70% (checked in /opsx-verify)
✓ Code Review: Style, security, standards
✓ Commits: Granular (one fix = one commit)
✓ Issue Loop: E2E/integration only (phase 2 for rigor)
✓ No shortcuts: Pre-commit hooks for linting/formatting
---
DATA MODEL (What we're tracking)
✓ Teams/Roles: Name, hourly rate
✓ Team Members: Name, role, availability (1, 0.5, 0)
✓ Holidays/PTO: Calendar per month
✓ Projects: Status, type, approved estimate, forecasted effort
✓ Allocations: Project → Person → Hours (monthly)
✓ Actuals: Project → Person → Hours logged (monthly)
✓ Untracked Resource: Bucket for external team time (no billing)
---
What I Think Might Be Missing
1. Reporting Architecture
You need reports (forecast, utilization, cost). Should we:
- Pre-calculate and cache? (query once, serve multiple times)
- Or calculate on-demand? (fresh, slower)
- My recommendation: On-demand for MVP (cleaner logic). Cache in phase 2 if slow.
2. Data Validation Rules
- Can you allocate more hours than approved estimate? (I assume no - red flag)
- Can you log actuals after project is "Done"? (I assume no)
- Can you delete a team member with active allocations? (I assume no)
- Should we define these business rules in OpenSpec before building?
3. Role Hierarchies
You mentioned 4 personas: Superuser, Managers, Devs, Top Brass
- Do managers see only their team's projects?
- Do devs see only their allocations?
- Do Top Brass see everything (read-only)?
- Should we define these permissions clearly?
4. API Versioning
- Should the Laravel API be versioned (e.g., /api/v1/)?
- My recommendation: Start without versioning, add in phase 2.
5. Audit Logging
- Do you need to track who changed what and when?
- My recommendation: Start without. Add audit logs in phase 2 if compliance matters.
---
Questions Before Locking In
1. Data Validation Rules - Should we document these in OpenSpec? ==> OpenSpec document must have all required data. I believe we need it there for verification and regression tests. Thoughts?
2. Permission Model - Should we define role-based access rules upfront? ==> Of course, RBAC is required.
3. Background Jobs - Will you need async processing for any MVP features? ==> No. Since we have laravel and redis ready, it is just a matter of flipping the switch.
4. Notifications - Should team members get alerts on allocation changes? ==> Wont it become a technical debt? How big the lift will be to at least set up the wiring for notifications (websocket setup and one notification implemented as a proof of concept?)
---
Honestly, I think you're 99% locked in. These last questions are minor and can mostly be decided during implementation. But I want to make sure we're not missing anything critical before you commit to this stack.
What's your feeling? Anything jump out as "we forgot about this"?
## INTERVIEW 10
Excellent questions. Let me address them:
---
1. Data Validation Rules in OpenSpec
Absolutely. In fact, this is critical for your workflow. Here's why:
Validation Rules (in OpenSpec)
Inform API implementation (Laravel validation)
Inform test cases (unit + E2E)
Used in /opsx-verify to check coverage
Examples of rules we should document:
- Can't allocate more hours than approved estimate (per project, per month)
- Can't allocate negative hours
- Can't log actuals after project status is "Done"
- Can't delete team member with active allocations
- All required fields must be populated
- Hourly rate must be > 0
- Availability must be 0, 0.5, or 1.0
My recommendation: Create a validation-rules.md in the OpenSpec change. This becomes your test oracle.
---
2. RBAC (Role-Based Access Control)
Yes, define upfront. Let me clarify the 4 personas:
| Persona | Can Do | Cannot Do |
|---------|--------|-----------|
| Superuser | Everything (setup, config, all projects) | Nothing restricted |
| Manager | Create/edit projects, allocate resources, view team's projects, approve estimates | Edit other managers' data, change team members |
| Developer | View own allocations, log hours, view project details | Allocate resources, change estimates |
| Top Brass | View all reports (read-only), forecast summaries, utilization | Modify anything |
Question for you:
- Can a Manager only see projects they're assigned to, or all projects?
- Can a Manager allocate resources to projects outside their team?
---
3. Background Jobs
Agreed. No async needed for MVP. Redis + Laravel Queue are wired and ready if needed later.
---
4. Notifications - The Real Question
This is interesting. Let me break down the lift:
WebSocket Setup (One-time cost)
- Laravel Broadcasting with Redis adapter: ~2 hours
- SvelteKit WebSocket client: ~1 hour
- Docker networking: ~30 min
- Total: ~3.5 hours
First Notification (Allocation Changed)
- Backend event + listener: ~1 hour
- Frontend listener + toast: ~30 min
- Tests: ~1 hour
- Total: ~2.5 hours
Total for Wiring + PoC: ~6 hours
Is this worth it for MVP?
Your concern about technical debt is valid. Here are the options:
Option A: Include WebSocket + 1 notification PoC
- Pros: Users see allocation changes in real-time, framework is ready for more
- Cons: Adds complexity, 6 hours of dev time
- Timeline impact: Delays other features by ~1 day
Option B: Skip notifications entirely for MVP
- Pros: Keeps scope tight, faster MVP
- Cons: Users don't know about allocation changes until they refresh
- Debt accrual: Low (easy to add later)
Option C: Add polling-based notifications (simpler)
- SvelteKit polls for "new allocations" every 30s
- Pros: No WebSocket complexity, users see changes quickly
- Cons: Not true real-time, more server load
- Lift: ~2 hours
---
My Honest Take
For MVP, I'd recommend Option B (skip notifications). Here's why:
1. Allocations are typically planned once per month - not super time-sensitive
2. Users can refresh the page (or we can auto-refresh every 5 min)
3. The WebSocket setup will be cleaner in phase 2 when you know exactly what needs notifying
4. Saves 6 hours of dev time for more important features (reports, analytics)
BUT: If you want to prove the notification concept early, Option C (polling) is a middle ground at 2 hours.
---
Before We Formalize
Quick clarifications:
1. RBAC - Can a Manager see/allocate to projects outside their assigned team? ==> Can see. But not allocate to other team's members.
2. Notifications - Go with Option B (skip MVP), or Option C (polling PoC)? ==> Ok. Option B.
3. Validation Rules - Should I start documenting these, or wait until OpenSpec change? ==> Perfect. Bake it into the project scope.
One question: How about SwaggerUI documentation for APIs?
Said that, I want to have all the conversation formally documented, outside the scope of OpenSpec. This includes whatever we have deffered, whatever we discussed and decided not to do. All conisderations. Then, for the architectural diagrams, see if Mermaid diagrams can be created. If possible, generate an MD file and a Word Document (for hardcopy for me. This is my magnum opus project as of date.)
Once these are locked, we formalize everything in OpenSpec and you're ready to build.
## CONCLUSION
Perfect! That's a wise decision. You've got comprehensive documentation ready for review, and sleeping on it will give you fresh perspective in the morning.
Here's what you have ready to review:
---
📚 Documentation Ready for Review
Core Documents (docs/)
1. headroom-project-charter.md - Complete requirements, validation rules, success criteria
2. headroom-architecture.md - Technical design with 7 Mermaid diagrams
3. headroom-decision-log.md - Full conversation archive with all decisions & rationale
4. headroom-executive-summary.md - Print-friendly overview
5. README.md - How to convert to Word, reading order, maintenance guide
OpenSpec Artifacts (openspec/changes/headroom-foundation/)
1. proposal.md - WHY we're building Headroom (15 capabilities)
2. design.md - HOW we'll build it (technical decisions + 5 open questions)
3. specs/ - 15 detailed requirement specs with WHEN/THEN/AND scenarios
4. tasks.md - 250+ implementation tasks organized by sprint
---
✨ Everything Updated
- ✅ Laravel 12 (with PHP 8.4)
- ✅ All dependencies using :latest tags
- ✅ Version strategy documented in decision log
---
💭 What to Review
Before implementation, consider:
1. Do all the decisions captured match your vision?
2. Are there any requirements you'd like to adjust or clarify?
3. Do you have thoughts on the 5 open questions in design.md?
4. Does the task breakdown feel reasonable for 6-8 weeks?
5. Any concerns about the RBAC model or validation rules?
---
🛌 When You're Ready
Just say the word when you've reviewed everything, and we can:
- Answer any questions about the design
- 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/<capability>/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/<capability>.spec.ts │ │
│ │ └── Mark as test.skip() or test.fixme() │ │
│ │ │ │
│ │ 3. Write API test (Pest) │ │
│ │ └── backend/tests/Feature/<Capaibility>Test.php │ │
│ │ └── Mark as $this->markTestSkipped('pending implementation') │ │
│ │ │ │
│ │ 4. Write Unit tests (Pest/Vitest) │ │
│ │ └── backend/tests/Unit/<Class>Test.php │ │
│ │ └── frontend/src/lib/<module>.test.ts │ │
│ │ └── Mark as skip/pending │ │
│ │ │ │
│ │ 5. Write Component tests (Vitest + Testing Library) │ │
│ │ └── frontend/src/components/<Component>.test.ts │ │
│ │ └── Mark as skip/pending │ │
│ │ │ │
│ │ 6. Commit: "test(<capability>): 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(<capability>): Implement <scenario>" │ │
│ │ └── "test(<capability>): Enable <scenario> 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(<capability>): <what was improved>" │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 4: DOCUMENT │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. Update API documentation (Scribe) │ │
│ │ └── php artisan scribe:generate │ │
│ │ │ │
│ │ 2. Verify all tests still pass │ │
│ │ │ │
│ │ 3. Commit: "docs(<capability>): 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/<capability>/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(<capability>): Add pending tests for <scenario>
↳ Initial failing tests, marked skip/pending
feat(<capability>): Implement <specific feature>
↳ Enable test + minimal implementation
refactor(<capability>): <description of improvement>
↳ Clean up while tests green
docs(<capability>): <documentation change>
↳ 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!