Files
headroom/docs/headroom-decision-log.md
Santhosh Janardhanan 3e36ea8888 docs(ui): Add UI layout refactor plan and OpenSpec changes
- Update decision-log with UI layout decisions (Feb 18, 2026)
- Update architecture with frontend layout patterns
- Update config.yaml with TDD, documentation, UI standards rules
- Create p00-api-documentation change (Scribe annotations)
- Create p01-ui-foundation change (types, stores, Lucide)
- Create p02-app-layout change (AppLayout, Sidebar, TopBar)
- Create p03-dashboard-enhancement change (PageHeader, StatCard)
- Create p04-content-patterns change (DataTable, FilterBar)
- Create p05-page-migrations change (page migrations)
- Fix E2E auth tests (11/11 passing)
- Add JWT expiry validation to dashboard guard
2026-02-18 13:03:08 -05:00

955 lines
34 KiB
Markdown
Raw 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.
# Headroom - Complete Decision Log & Conversation Archive
**Version:** 1.0
**Date:** February 17, 2026
**Participants:** Santhosh J (Project Owner), AI Assistant (Design Partner)
**Purpose:** Comprehensive record of all discussions, decisions, considerations, and deferrals
---
## Table of Contents
1. [Project Genesis](#project-genesis)
2. [Requirements Discovery](#requirements-discovery)
3. [Technical Stack Decisions](#technical-stack-decisions)
4. [Architecture Decisions](#architecture-decisions)
5. [Quality & Testing Decisions](#quality--testing-decisions)
6. [Deferred Features](#deferred-features)
7. [Rejected Options](#rejected-options)
8. [Open Questions](#open-questions)
9. [Timeline](#timeline)
---
## Project Genesis
### The Problem
**Context:**
- Managing team of 10-15 developers
- Handling 10-12 concurrent projects in various phases
- Currently using spreadsheets → "a nightmare"
**Pain Points Identified:**
1. **Capacity calculation chaos**: Manual calculations across holidays, PTO, weekends
2. **No validation**: Easy to over-allocate people or projects
3. **Visibility gap**: Hard to answer "Who has headroom for new work?"
4. **Billing errors**:
- Over-allocation → Overcharge clients → Escalations
- Under-allocation → Undercharge → Revenue loss
5. **No audit trail**: Changes are invisible
6. **Actual vs Planned tracking**: Difficult to compare what was planned vs what actually happened
### The Vision
**Product Name:** Headroom
- **Why this name?** It's the word managers actually say ("do we have headroom for this?"), immediately signals capacity planning, and captures the over/under allocation anxiety central to the tool.
- **Close runner-up:** Margin (protecting margin through accurate forecasting)
**Core Value:**
> Know exactly who has headroom for new work, prevent billing errors, forecast revenue, track planned vs actual hours.
### Personas
Four distinct user types identified:
| Persona | Primary Need |
|---------|--------------|
| **Superuser** | System setup, configuration, admin controls |
| **Managers** | Resource planning, allocation, team oversight |
| **Developers** | View allocations, log hours, understand workload |
| **Top Brass** | Executive reports, forecasts, budget visibility |
---
## Requirements Discovery
### The Monthly Cycle
**Key Insight:** The workflow is organized around monthly capacity planning cycles, not continuous allocation.
```
Monthly Cycle:
1. Capacity Planning → Who's available, how much?
2. Project Setup → What work needs to be done?
3. Resource Allocation → Who does what?
4. Actuals Tracking → What actually happened?
```
### Capacity Planning Requirements
**Inputs:**
- Team member list (name, role, hourly rate)
- Calendar data (holidays, weekends)
- Individual PTO requests
- Daily availability: **0** (unavailable), **0.5** (half day), **1.0** (full day)
**Critical Clarification:**
- Initial assumption: "10 hrs for Dev" meant role-based allocation
- **Actual requirement:** Person-specific allocation ("10 hrs for Santhosh")
- Availability is per-person, per-day, not role-based
**Outputs Needed:**
1. Individual capacity (person-days per month)
2. Team capacity summary (total available person-days)
3. Possible revenue (if fully utilized)
### Project Management Requirements
**Project Lifecycle:**
```
NA/Support → Initial → Gathering Estimates → Estimate Pending Approval
Estimate Rework ←───────┘
Estimate Approved → Funded → Scheduled → In-Progress
Ready for Prod → Done
[Optional: On-Hold, Cancelled]
```
**Key Attributes:**
- **Approved Estimate**: Total billable hours approved by client
- **Forecasted Effort**: How those hours split across months
- **Project Type**: Project (billable) vs Support (ongoing ops)
**Validation Requirement:**
- **Over-forecast**: Allocated hours > Approved estimate → RED FLAG (will overcharge)
- **Under-forecast**: Allocated hours < Approved estimate → YELLOW FLAG (will undercharge)
- **Clarification:** "Under-forecast is NOT OK. This money is my salary! Always try to be 100%."
### Resource Allocation Requirements
**The "Matrix" Concept:**
```
For month M:
┌────────────────────────────────────────┐
│ Project │ Dev A │ Dev B │ Dev C │ Ext │
├──────────┼───────┼───────┼───────┼─────┤
│ Proj X │ 40h │ 20h │ 0 │ 10h │
│ Proj Y │ 20h │ 40h │ 30h │ 0 │
└────────────────────────────────────────┘
```
**"Untracked Resource" Requirement:**
- Purpose: Accommodate hours for external team members (e.g., DevOps from another team)
- Billing: NOT tracked for revenue (like a joker in a deck of cards)
- Use case: "We might bill another team, but not track their specific person"
**Validation Rules:**
- Sum of project allocations should equal approved estimate (tolerance: ±5%)
- Cannot allocate more than person's monthly capacity (warning, not hard block)
- Visual indicators: GREEN (100%), YELLOW (<100%), RED (>100%)
### Actuals Tracking Requirements
**Data Entry:**
- **Frequency**: Monthly aggregate, but can be updated incrementally (weekly)
- **Method**: Manual entry (no time-tracking tool integration for MVP)
**Calculations:**
- **Running utilization**: (Allocated hours YTD) / (Capacity YTD) × 100%
- **Overall utilization**: (Allocated hours this month) / (Capacity this month) × 100%
**Display Requirement:**
- Show utilization % alongside capacity view
### Reporting Requirements
**Core Reports:**
1. **Forecast Summary** (multi-period)
2. **Utilization Summary**
3. **Cost Summary**
**Critical Requirement:**
> All reports must be highly customizable with filters (team, person, project, status, date range, type)
**Additional Requirements:**
- Master data / taxonomy for configurable items (roles, statuses, types)
- Support for multi-tenancy (deferred to post-MVP)
---
## Technical Stack Decisions
### Backend: Why Laravel?
**Question Raised:** "I chose Laravel because of my PHP background. Debate me if that is not a good choice."
**Consideration:**
- Alternative: SvelteKit full-stack (single framework)
- Alternative: Next.js + Node.js
**Decision:** Laravel
- **Rationale**:
- You have PHP background (lower learning curve)
- Laravel is mature, robust for API development
- Rich ecosystem (Scribe for API docs, Pest for testing, Pint for linting)
- PostgreSQL support is excellent
- Redis integration is first-class
**No pushback from AI:** Laravel is a solid choice for this use case.
### Frontend: The Great Debate
**Initial Question:** "May be Laravel + Svelte? Or Sveltekit itself?"
**Options Presented:**
1. Laravel + Blade Templates (rejected: less interactive)
2. Laravel + Vue.js (recommended by AI: stay in Laravel ecosystem)
3. **Laravel API + SvelteKit (separate)** ← CHOSEN
4. Laravel API + React (rejected: more learning curve)
**Decision:** Laravel API + SvelteKit (separate projects)
- **Your choice:** "Sveltekit it is!"
- **AI concern:** "Adds deployment complexity for MVP"
- **Your response:** "I will choose this."
- **Outcome:** Two separate containers, clean separation
**Why SvelteKit?**
- Modern, reactive
- Great for data-heavy dashboards
- Smaller bundle sizes than React/Vue
- You're willing to learn it
### Database: PostgreSQL from Day 1
**Question:** "SQLite for local, PostgreSQL for production?"
**Decision:** PostgreSQL from the start
- **Rationale**:
- Avoid migration pain later
- Production-grade features (JSON operators, full-text search)
- Better for reporting queries
- Volume-mounted in Docker (portability maintained)
### Caching: Redis from Day 1
**Initial Recommendation:** "Start without caching, add in Phase 2 if slow"
**Your Response:** "Query caching and Response caching on Redis from Day 1. No need to sweat on refactoring it everywhere."
**Decision:** Redis caching from day 1
- **Rationale**: Prevents technical debt
- **Scope**: Query caching + Response caching
- **Implementation**: Laravel cache facade, automatic invalidation
### Authentication: JWT
**Question:** "Session-based or Token-based (JWT)?"
**AI Recommendation:** "Session-based is easier for same-origin setup"
**Your Choice:** "I will go with JWT."
**Rationale:**
- Token-based authentication
- Suitable for SPA frontend
- Easier to add mobile app later (if needed)
### UI Component Library
**Options Presented:**
- Shadcn/ui (headless, customizable)
- **DaisyUI** (Tailwind-based, fast) ← CHOSEN
- Svelte Material UI (full-featured)
- Build custom with Tailwind
**Decision:** DaisyUI
- **Rationale**: Faster to build dashboards, opinionated but fast
- **Your response:** "Daisy it is."
### Charts & Visualization
**Options Presented:**
- **Recharts** ← CHOSEN (AI recommendation)
- Chart.js
- Plotly
- Apache ECharts
**Decision:** Recharts
- **Rationale**: Good balance of power and simplicity
- **Your response:** "Agreed"
### Tables & Data Grid
**Options Presented:**
- **TanStack Table (React Table)** ← CHOSEN
- Svelte DataTable
- Build custom
**Decision:** TanStack Table
- **AI note:** "I am not familiar with this, but I will go with your recommendation."
- **Rationale**: Industry standard, powerful filtering/sorting, works with Svelte
### Forms & Validation
**Options Presented:**
- SvelteKit Form Actions + Superforms
- Direct API calls
**Additional Question:** "How about something like Superform or Zod?"
**Decision:** Superforms + Zod + SvelteKit Form Actions
- **Rationale**:
- Type-safe validation (Zod)
- Form state management (Superforms)
- Server-side handling (SvelteKit native)
- Single source of truth for validation
### API Documentation
**Question Raised:** "How about SwaggerUI documentation for APIs?"
**Decision:** Laravel Scribe (auto-generates SwaggerUI)
- **Implementation**: `composer require knuckleswtf/scribe`
- **Output**: `/api/documentation` endpoint with OpenAPI spec
- **Lift**: ~1 hour setup
- **Inclusion**: From day 1
### Testing Stack
**Backend:**
- PHPUnit (unit tests)
- Pest (feature tests)
**Frontend:**
- Vitest (unit tests)
- Playwright (E2E tests)
**Decision:** Include all from day 1
### Version Strategy
**Question:** Which versions to use?
**Decision:** Use latest versions across the stack
- **Laravel 12** (latest major version)
- **PHP 8.4** (compatible with Laravel 12)
- **All other dependencies:** Use `:latest` tags (PostgreSQL, Redis, Node, npm packages)
**Rationale:**
- Stay current with latest features and security patches
- Avoid version lock-in from the start
- Docker `:latest` tags ensure fresh installs get newest versions
---
## Architecture Decisions
### Containerization
**Requirement:** "From get go, everything must be containerised."
**Additional Constraint:** "Do not add any proxy manager (NPM, Caddy, or Traefik). My environment already runs an NPM."
**Decision:** Docker Compose with 4 containers
1. **Frontend**: SvelteKit (port 5173)
2. **Backend**: Laravel (port 3000)
3. **Database**: PostgreSQL (port 5432)
4. **Cache**: Redis (port 6379)
**Reverse Proxy:**
- Use existing Nginx Proxy Manager
- NPM routes `/api/*` → Laravel
- NPM routes `/*` → SvelteKit
### Multi-Tenancy
**Question:** "Should we build multi-tenant from day 1?"
**AI Recommendation:** "Start single-tenant. Add tenant_id column when needed."
**Your Response:** "AGREED"
**Rationale:** Reduces complexity, easy to add later
### Environment Configuration
**Question:** ".env files or Docker secrets?"
**AI Recommendation:** ".env files for local, Docker secrets in prod"
**Your Response:** ".env everywhere"
**Decision:** .env files in all environments
- Simpler configuration management
- Consistent across local/prod
### Development Environment
**Question:** "Docker Compose for local dev, or native setup?"
**AI Recommendation:** "Docker Compose from the start. Ensures prod parity."
**Your Response:** "100% agree. If possible, we should have at least the local dev avoid building after every change (may be code mounted)"
**Decision:** Docker Compose with code-mounted volumes
- Hot reload for both frontend and backend
- Avoid rebuilding containers on every change
- Volume mounts: `./frontend:/app`, `./backend:/var/www`
### Real-Time Updates
**Question:** "Do you need live updates (WebSockets), or is polling OK?"
**AI Recommendation:** "Start with polling. Add WebSockets if needed."
**Your Response:** "I dont think we need to sweat on it. Go with a basic implementation. Polling is good enough."
**Decision:** Polling (defer WebSockets to Phase 2)
### State Management (Frontend)
**Question:** "Svelte stores for UI state, or always fetch from API?"
**AI Recommendation:** "Use Svelte stores for UI state (filters, modals), API queries for data."
**Your Response:** "Agreed."
**Decision:** Minimal Svelte stores (UI state only)
### Report Exports
**Question:** "Will users need PDF/CSV exports?"
**AI Recommendation:** "Start with on-screen reports, add exports in phase 2."
**Your Initial Response:** "Good to have at this time."
**AI Clarification:** "Should exports be in MVP scope, or phase 2?"
**Final Decision:** Phase 2
- **Rationale**: Keeps MVP scope tight, adds 4 hours of work
- Interactive dashboard is primary value
### Caching Strategy
**Question Raised by You:** "Should we talk about a caching layer?"
**Options Discussed:**
1. Database Query Caching
2. API Response Caching
3. Full-page caching
**AI Recommendation:** "Start without caching, add Redis in Phase 2 if slow"
**Your Response:** "Query caching and Response caching on Redis from Day 1. No need to sweat on refactoring it everywhere."
**Decision:** Redis caching from day 1
- Query caching (expensive calculations)
- Response caching (GET endpoints)
- Automatic cache invalidation on mutations
- TTL: 1 hour (allocations), 15 min (reports), 24 hours (master data)
---
## Quality & Testing Decisions
### Project-Level Standing Instructions
**Your 5 Points (to be encoded in OpenSpec config.yml):**
1. **Every change must have unit tests, E2E test, regression tests** (whether prompted or not)
2. **Changes must end with code review** for style, standard, security
3. **Verification (`/opsx-verify`) must trigger checking of uncovered code** (code not tested)
4. **Commits must be granular** (one fix = one commit)
5. **Tests run in a progressive loop**:
- Test → Create issue in repo → Fix → Retest + Regression test
- Loop until all issues fixed
**AI Question:** "Is this for ALL tests, or specifically for E2E/integration tests?"
**Your Clarification:** "I agree. Let us go for a kill only in E2E and Integration."
**AI Concern:** "This workflow can slow velocity. For MVP, start with 'every test must pass before merge' and defer granular issue-loop to phase 2?"
**Your Response:** "Agreed"
**Final Decision:**
- **MVP**: All tests must pass, granular commits, code review
- **Phase 2**: Issue-driven test loop for E2E/integration failures
### Code Coverage Threshold
**AI Question:** "What code coverage % for /opsx-verify?"
**Your Response:** "Let us call it >70%"
**Decision:** >70% code coverage required
- Checked in `/opsx-verify`
- Blocks merge if below threshold
### Data Validation Rules
**AI Question:** "Should we document validation rules in OpenSpec?"
**Your Response:** "OpenSpec document must have all required data. I believe we need it there for verification and regression tests. Thoughts?"
**AI Agreement:** "Absolutely. Rules inform API implementation, test cases, and verification."
**Decision:** Create `validation-rules.md` in OpenSpec changes
- These rules drive Laravel validation
- Inform test case generation
- Used in `/opsx-verify`
### RBAC (Role-Based Access Control)
**AI Question:** "Can a Manager see only their projects, or all projects?"
**Your Clarification:** "Can see all projects. But not allocate to other team's members."
**Decision:** RBAC Matrix defined
| Persona | Can See | Can Modify |
|---------|---------|------------|
| Superuser | All | All |
| Manager | All projects (read-only for others') | Own projects, own team allocations |
| Developer | Own allocations, assigned projects | Own actuals only |
| Top Brass | All reports | Nothing (read-only) |
---
## Deferred Features
### Phase 2 Deferrals
| Feature | Reason for Deferral | Estimated Lift |
|---------|---------------------|----------------|
| **Notifications (WebSocket)** | Allocations are monthly, not time-critical | ~6 hours |
| **PDF/CSV Exports** | On-screen reports sufficient for MVP | ~4 hours |
| **Background Jobs** | No heavy processing in MVP, Laravel Queue ready | ~2 hours |
| **Audit Logging** | No compliance requirement for MVP | ~3 hours |
| **Advanced Caching (pre-calculated reports)** | Start with on-demand queries | ~4 hours |
| **API Versioning (`/api/v1/`)** | Not needed until breaking changes | ~2 hours |
| **Issue-driven test loop** | Slower velocity for MVP | ~8 hours |
### Notifications Deep-Dive
**AI Presented 3 Options:**
**Option A:** Include WebSocket + 1 notification PoC (~6 hours)
- Pros: Real-time updates, framework ready
- Cons: Adds complexity, delays other features by ~1 day
**Option B:** Skip notifications entirely for MVP
- Pros: Keeps scope tight, faster MVP
- Cons: Users must refresh to see changes
- **Debt accrual:** Low (easy to add later)
**Option C:** Polling-based notifications (~2 hours)
- SvelteKit polls every 30s
- Pros: Simple, users see changes quickly
- Cons: Not true real-time, more server load
**AI Recommendation:** Option B (skip for MVP)
**Your Question:** "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?)"
**AI Response:** "6 hours total lift. Not worth it for MVP - allocations are monthly, not time-critical."
**Your Decision:** "Ok. Option B."
---
## Rejected Options
### Options Considered but Not Chosen
| Option | Why Rejected |
|--------|--------------|
| **Laravel + Blade Templates** | Less interactive UI, harder to build dashboards |
| **Laravel + Vue.js** | You preferred learning Svelte over Vue |
| **Next.js + Node.js** | You have PHP background, prefer Laravel |
| **SQLite for local dev** | Avoid migration pain, PostgreSQL from start |
| **Session-based auth** | JWT chosen for future mobile support |
| **Multi-tenancy from day 1** | Adds complexity, defer to post-MVP |
| **WebSocket notifications in MVP** | Not time-critical, 6 hours of work |
| **PDF/CSV exports in MVP** | On-screen reports sufficient initially |
| **GraphQL** | REST is simpler for MVP |
| **Chart.js / Plotly / ECharts** | Recharts chosen (good balance) |
| **Shadcn/ui / Svelte Material UI** | DaisyUI chosen (faster development) |
| **Custom-built table component** | TanStack Table chosen (industry standard) |
---
## Open Questions (Resolved)
### 1. Over/Under Forecast Context
**Initial Confusion:** "Is over/under forecast about allocation vs approved estimate, or allocation vs capacity?"
**Your Clarification:** "In the project's context, yes. it is allocation vs approved. (For the future phases, there will be over/under forecast for resources - that will be based on individual's allocation vs their capacity. May be we can keep that aside for now.)"
**Example Correction:**
- **AI Example:** "Month 1 allocation: 80hrs → Under-forecast (OK)"
- **Your Correction:** "Not OK. Because this money is my salary! We always try to be on par - 100%. If it is under-forecast, call that out."
**Resolution:** Both over and under-forecast are flagged. Under is YELLOW, Over is RED.
### 2. Availability Model
**Initial Confusion:** "Is availability 1.0 = 8 hours/day, or is it a percentage?"
**Your Clarification:** "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."
**Resolution:** Availability is 0, 0.5, or 1.0 (not percentage). 0 = unavailable or PTO.
### 3. Untracked Resource Purpose
**Initial Confusion:** "Is this for contractors, or overhead?"
**Your Clarification:** "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."
**Resolution:** Untracked resource is for external team time (not billed in this system).
### 4. Team Structure
**Initial Confusion:** "Does 'Team' mean sub-teams?"
**Your Clarification:** "Yes. Read that as 'Role'."
**Resolution:** Team = Role (e.g., Frontend, Backend, QA, PM, Architect).
### 5. Manager Permissions
**Initial Confusion:** "Can a Manager allocate to projects outside their team?"
**Your Clarification:** "Can see. But not allocate to other team's members."
**Resolution:** Managers see all projects (read-only for others'), but can only allocate their own team members.
---
## Timeline
### Conversation Flow
**February 17, 2026:**
1. **Initial Problem Statement** (09:00-09:30)
- You described the spreadsheet nightmare
- Identified 4 personas
- Outlined capacity planning → allocation → actuals flow
2. **Requirements Deep-Dive** (09:30-11:00)
- Clarified capacity planning details (availability model)
- Defined project lifecycle states
- Detailed allocation matrix requirements
- Discussed reporting needs
3. **Technical Stack Discussion** (11:00-12:00)
- Debated Laravel vs alternatives → Laravel chosen
- Frontend: Vue vs Svelte → SvelteKit chosen
- Database: SQLite vs PostgreSQL → PostgreSQL chosen
- Authentication: Session vs JWT → JWT chosen
4. **Architecture Decisions** (12:00-13:00)
- Containerization approach (Docker Compose)
- Multi-tenancy deferral
- Caching strategy (Redis from day 1)
- Real-time updates (polling, defer WebSockets)
5. **Quality Standards** (13:00-13:30)
- Testing requirements (>70% coverage)
- Code review process
- Commit standards (granular)
- Issue-driven test loop (defer to Phase 2)
6. **Frontend Libraries** (13:30-14:00)
- UI components: DaisyUI chosen
- Charts: Recharts chosen
- Tables: TanStack Table chosen
- Forms: Superforms + Zod chosen
7. **Final Verification** (14:00-14:30)
- Reviewed complete architecture
- Confirmed no missing pieces
- Decided on API documentation (Scribe)
- Named the project: **Headroom**
8. **Documentation Request** (14:30-15:00)
- Request for comprehensive documentation
- Mermaid diagrams
- Word document for hardcopy
### Key Turning Points
**Moment 1: Naming the Project**
- You chose "Headroom" over "Margin"
- This crystallized the product's identity
**Moment 2: SvelteKit Decision**
- Despite AI recommending Laravel + Vue (easier)
- You chose SvelteKit (more learning, cleaner separation)
- This showed willingness to learn for better architecture
**Moment 3: Redis from Day 1**
- AI recommended deferring caching
- You insisted on Redis from day 1 (avoid refactoring debt)
- This showed pragmatic technical judgment
**Moment 4: "This money is my salary!"**
- Clarified that under-forecast is NOT acceptable
- Both over and under-forecast must be flagged
- This revealed the business criticality of accurate allocation
**Moment 5: "One last check before we lock in"**
- You paused before committing to the stack
- Requested comprehensive review
- This showed careful, deliberate decision-making
---
## Considerations & Trade-offs
### Decision Matrix
| Decision | Benefit | Cost | Rationale |
|----------|---------|------|-----------|
| **SvelteKit (separate)** | Clean separation, modern framework | Deployment complexity, learning curve | Better long-term architecture |
| **Redis from day 1** | No refactoring debt later | Slightly more upfront setup | Prevents future pain |
| **JWT over sessions** | Mobile-ready, stateless | More complex than sessions | Future-proofing |
| **PostgreSQL from day 1** | No migration later | Heavier than SQLite | Production-grade from start |
| **Defer notifications** | Faster MVP | Users must refresh | Not time-critical for monthly planning |
| **Defer exports** | Tighter scope | No PDF/CSV initially | On-screen reports are primary value |
| **TanStack Table** | Powerful, standard | Learning curve (you're unfamiliar) | Industry best practice |
| **DaisyUI** | Fast development | Opinionated | Speed > customization for MVP |
### Risk Assessment
**Low Risk:**
- Laravel choice (you have PHP background)
- PostgreSQL choice (mature, well-supported)
- Redis choice (simple, well-integrated with Laravel)
**Medium Risk:**
- SvelteKit choice (learning curve, but modern and well-documented)
- TanStack Table (unfamiliar to you, but powerful)
- Two-container deployment (more moving parts, but cleaner)
**Mitigated Risks:**
- **Over-complexity:** Deferred features to Phase 2 (notifications, exports, multi-tenancy)
- **Performance:** Redis caching from day 1
- **Testing debt:** >70% coverage enforced from day 1
---
## Success Metrics (Defined)
### MVP Success Criteria
**Functional Completeness:**
- ✅ Users can define team capacity
- ✅ Users can create projects with approved estimates
- ✅ Users can allocate resources month-by-month
- ✅ Users can log actual hours
- ✅ System validates allocations (over/under warnings)
- ✅ Users can view 5 core reports
- ✅ RBAC enforced (4 personas)
**Quality Metrics:**
- ✅ All tests passing (unit + E2E)
- ✅ Code coverage >70%
- ✅ Zero linting errors
- ✅ API documentation auto-generated
**Usability Metrics (Post-Launch):**
- Manager can complete monthly allocation in <30 minutes (vs 2+ hours in spreadsheet)
- Zero billing errors in first 3 months (over/under caught before invoicing)
- 90% of team members log actuals weekly
**AI Rationale:** "Fair but not too lenient. Manager time savings is measurable. Billing error prevention is critical. Adoption (90%) is achievable but requires discipline."
---
## Appendix: Conversation Highlights
### Most Insightful Moments
**On Under-Forecasting:**
> "Not OK. Because this money is my salary! We always try to be on par - 100%. If it is under-forecast, call that out."
**On Naming:**
> "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."
**On Caching:**
> "Query caching and Response caching on Redis from Day 1. No need to sweat on refactoring it everywhere."
**On Quality:**
> "I know this will be a time taking process. But I believe it will be worth it."
**On Final Review:**
> "Now this is the part I am most scared about. If I say yes, we need to stick to this rule book. Did I forget anything?"
### Your Leadership Style
**Observations from conversation:**
- **Pragmatic:** Willing to defer features to keep scope tight
- **Quality-focused:** Insisted on testing, code review, coverage from day 1
- **Deliberate:** Paused multiple times to verify decisions before committing
- **Learning-oriented:** Chose SvelteKit despite unfamiliarity, trusted AI recommendations on unfamiliar tools (TanStack Table)
- **Business-minded:** Constantly connected technical decisions to business impact (billing accuracy, manager time savings)
---
## UI Layout Decisions
**Date:** February 18, 2026
**Context:** After initial authentication implementation, reviewed login page UI and decided to establish a comprehensive layout system.
### Problem Statement
The initial UI implementation used a simple top-navbar pattern without a standardized layout system. For a data-dense resource planning application, this approach would not scale well.
### Design Direction
**Aesthetic Spectrum Decision:**
- Target: **70% Data-Dense | 30% Utilitarian**
- Reference Apps: **Obsidian** (minimal chrome, content-first) + **Jira** (hierarchical sidebar, dense tables)
### Core Layout Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| **Sidebar** | Collapsible (full ↔ icons-only ↔ hidden) | Preserves screen real estate for low-resolution displays; sidebar should not eat productive space |
| **Month Selector** | Global (in top bar) | Allocation and actuals views are month-centric; affects all views |
| **Default Theme** | Light mode | Starting simple; dark mode available as toggle |
| **Icon Library** | **Lucide Svelte** | Modern, more icon variety, consistent with Svelte ecosystem |
| **UI Framework** | **DaisyUI-first** (no shadcn-svelte) | Already have it, excellent for business apps, use ~80% of its potential |
| **Navigation Pattern** | Persistent sidebar + top bar | Obsidian/Jira style; sectioned navigation (Planning, Reports, Admin) |
### Sidebar Specifications
```
EXPANDED (240px) COLLAPSED (64px) HIDDEN (0px)
┌────────────────┐ ┌────────┐ ┌──────────────────┐
│ ◀ ▶ │ │ ▶ │ │ │
│ ────────────── │ │ ────── │ │ Full width │
│ PLANNING │ │ │ │ content │
│ 📊 Dashboard │ │ 📊 │ │ │
│ 👥 Team Mem │ │ 👥 │ │ (toggle via │
│ 📁 Projects │ │ 📁 │ │ Cmd/Ctrl+\) │
│ 📅 Allocations │ │ 📅 │ │ │
│ ✅ Actuals │ │ ✅ │ │ │
│ ────────────── │ │ ────── │ │ │
│ REPORTS │ │ │ │ │
│ 📈 Forecast │ │ 📈 │ │ │
│ 📉 Utilization │ │ 📉 │ │ │
│ 💰 Costs │ │ 💰 │ │ │
│ 📋 Variance │ │ 📋 │ │ │
│ ────────────── │ │ ────── │ │ │
│ ADMIN* │ │ │ │ │
│ ⚙️ Settings │ │ ⚙️ │ │ │
│ ────────────── │ │ ────── │ │ │
│ 🌙 Dark [tgl] │ │ 🌙 │ │ │
└────────────────┘ └────────┘ └──────────────────┘
* Admin section visible only to superuser role
```
### Responsive Behavior
| Breakpoint | Sidebar Behavior | Toggle |
|------------|------------------|--------|
| ≥1280px (xl) | Expanded by default | Manual toggle only |
| 1024-1279px (lg) | Collapsed by default | Manual toggle only |
| 768-1023px (md) | Hidden (drawer overlay) | Hamburger menu |
| <768px (sm) | Hidden (drawer overlay) | Hamburger menu |
### Implementation Approach
**Phased Changes:**
1. `p00-api-documentation` — Add Scribe annotations to all controllers
2. `p01-ui-foundation` — Types, stores, Lucide setup, theme system
3. `p02-app-layout` — AppLayout, Sidebar, TopBar, Breadcrumbs
4. `p03-dashboard-enhancement` — Dashboard with stat cards
5. `p04-content-patterns` — DataTable, StatCard, FilterBar, EmptyState, LoadingState
6. `p05-page-migrations` — Migrate remaining pages incrementally
### Files to Create
```
frontend/src/lib/
├── types/layout.ts # SidebarState, NavItem, NavSection
├── stores/
│ ├── layout.ts # sidebarState, theme
│ └── period.ts # selectedMonth (global)
├── config/navigation.ts # Navigation sections config
└── components/layout/
├── AppLayout.svelte # Main layout wrapper
├── Sidebar.svelte # Collapsible navigation
├── TopBar.svelte # Search, month, user menu
├── Breadcrumbs.svelte # Navigation context
└── PageHeader.svelte # Page title + actions
```
### DaisyUI Table Density
| View | Classes |
|------|---------|
| Allocation Matrix | `table-compact table-pin-rows table-pin-cols` |
| Projects List | `table-zebra table-pin-rows` |
| Team Members | `table-zebra` |
| Reports | `table-compact table-pin-rows` |
### Key Quotes from Discussion
> "I like a collapsible sidebar, because some people use very low screen resolution which will limit the real estate to play around with. Sidebar should not eat up the productive space."
> "Make [month selector] global."
> "Light mode for now."
> "I lean more towards data-dense. How about keeping it 30-70 (utilitarian-data-dense)?"
> "Use Lucide."
---
## Next Steps (Post-Documentation)
### Immediate Actions
1. **Review Documentation**
- Read Project Charter
- Review Architecture Document
- Verify Decision Log captures everything
2. **Formalize in OpenSpec**
- Create first change: `/opsx-new headroom-foundation`
- Document proposal, specs, design, tasks
- Begin implementation
3. **Project Setup**
- Initialize Laravel project
- Initialize SvelteKit project
- Create Docker Compose setup
- Configure PostgreSQL + Redis
4. **First Sprint (Week 1)**
- Database schema design
- Docker Compose working
- JWT authentication
- Basic CRUD for team members
---
**Document Control:**
- **Owner:** Santhosh J
- **Type:** Conversation Archive & Decision Log
- **Purpose:** Comprehensive record for future reference
- **Intended Audience:** Santhosh J, Associate
- **Format:** Markdown (for git), Word (for hardcopy)
---
*"This is my magnum opus project as of date."* — Santhosh J, February 17, 2026
---
*End of Decision Log*