PROJECT 07

SaaS Invoicing App

The capstone: all 10 roles, 3 sprints, from architecture to production

โฑ ~120 min ยท 3 Sprints ยท Advanced+

What's New in This Project

This is the capstone. Every command and role you've learned comes together. Multi-tenant SaaS has the highest complexity: tenant isolation, data security, PDF generation, email delivery, payment tracking. You'll use the full framework โ€” security threat modeling upfront, story splitting for complex features, performance tuning, architecture audits, and a complete release pipeline.

โš ๏ธ Why This Matters

Projects 01-06 each introduced a few commands at a time. This project uses nearly every command and ALL 10 roles in a single, realistic build. Multi-tenant means every query must be tenant-scoped, every endpoint must enforce isolation, and every security gap could expose one customer's data to another. This is the complexity level where the framework proves its value.

All 10 Roles in Action

This is the only project where every role makes a meaningful contribution:

RoleWhat they do in this projectWhen
๐Ÿ“‹ @poWrites tenant-scoped stories, validates multi-tenant acceptance criteriaStory creation, sprint reviews, acceptance
๐Ÿ”„ @smManages 3 sprints, tracks velocity trend across sprints, facilitates 3 retrosAll sprint ceremonies
๐Ÿ—๏ธ @archDesigns multi-tenant architecture (shared DB vs separate schemas), records ADRsSprint 0, architecture audit
๐Ÿ‘จโ€๐Ÿ’ป @leadReviews tenant isolation code, ensures no cross-tenant data leaks in PRsEvery code review
โŒจ๏ธ @devImplements with TDD, handles complex PDF generation and payment logicAll implementation
๐Ÿงช @qaTests tenant isolation (can tenant A see tenant B's data?), validates coverageDoD checks, isolation testing
๐Ÿ—„๏ธ @dbaDesigns schema with tenant_id foreign keys, indexes for tenant-scoped queries, migration safetySchema design, Sprint 2 payments
๐Ÿ›ก๏ธ @secSTRIDE threat model upfront, OWASP audit on payment/invoice code, dependency CVE scanSprint 0, Sprint 3
๐ŸŽจ @uxInvoice creation form, PDF preview, responsive dashboard, WCAG AA accessibilitySprint 3 UI work
๐Ÿš€ @devopsCI/CD pipeline, staging + production environments, deployment with rollback planCI, releases, deploy

Phase 1: Project Initialization (Sprint 0) (~15 min)

Step 1: Tell Claude what you want to build

๐Ÿ’ฌ You say

"I want to build a multi-tenant invoicing SaaS. Tenants are businesses that create invoices for their clients. Each tenant's data must be completely isolated. Features: tenant registration, user management within tenants, invoice CRUD with line items, PDF generation, email delivery, and payment tracking."

Step 2: @arch evaluates multi-tenant strategies โ€” /agile-explore-brainstorm

๐Ÿ’ฌ You type

/agile-explore-brainstorm Multi-tenant invoicing SaaS. Key concern: tenant data isolation. Evaluate shared DB with tenant_id column vs separate schemas vs separate databases. Must be cost-effective for MVP with path to scale.

๐Ÿ—๏ธ @arch evaluates multi-tenant isolation strategies:

๐Ÿ—๏ธ @arch responds:

## /agile-explore-brainstorm โ€” Results

### Problem Statement
Multi-tenant data isolation for invoicing SaaS.
Constraints: cost-effective MVP, path to scale, strong isolation.

### Scoring Matrix

| Approach               | Feasibility | Isolation | Cost    | Scale Path | Total |
|------------------------|------------|-----------|---------|------------|-------|
| Shared DB + tenant_id  | 9/10       | 7/10      | 10/10   | 7/10       | 33    |
| Separate schemas       | 7/10       | 9/10      | 7/10    | 8/10       | 31    |
| Separate databases     | 5/10       | 10/10     | 4/10    | 9/10       | 28    |

### Recommendation
Shared DB with tenant_id โ€” highest feasibility, lowest cost.
Isolation enforced at application layer via middleware.

### What Would Change This
- If regulated industry (healthcare, finance) โ†’ separate schemas
- If >1000 tenants with heavy data โ†’ separate databases
- If compliance requires physical isolation โ†’ separate databases
โœ… You decide

"Let's go with shared DB with tenant_id. Simplest for MVP, and we'll enforce isolation in middleware."

Record the decision so the framework remembers it across sprints:

๐Ÿ’ฌ /agile-memory-remember Architecture decision: shared DB with tenant_id column
   for multi-tenant isolation. Enforced via middleware, not DB-level.

๐Ÿ”„ @sm: Saved to .memory/semantic/architecture.md

Step 3: Security threat modeling upfront โ€” /agile-security-threat-model

Multi-tenant systems have a high security bar. Before writing a single line of code, @sec identifies threats that will drive Sprint 3's security stories.

๐Ÿ’ฌ You type

/agile-security-threat-model Analyze the multi-tenant invoicing system for security threats. Key concerns: tenant data isolation, payment data, PII in invoices.

๐Ÿ›ก๏ธ @sec responds with STRIDE analysis:

## /agile-security-threat-model โ€” STRIDE Analysis

### System: Multi-Tenant Invoicing SaaS

| Threat Category    | Threat                                    | Impact | Mitigation                            |
|--------------------|-------------------------------------------|--------|---------------------------------------|
| Spoofing           | Attacker forges tenant context in JWT      | ๐Ÿ”ด High | Sign JWTs server-side, validate       |
|                    |                                           |        | tenant_id claim on every request      |
| Tampering          | User modifies invoice_id in URL to access  | ๐Ÿ”ด High | Scope all queries by tenant_id,       |
|                    | another tenant's invoice (IDOR)           |        | never trust client-supplied IDs alone |
| Repudiation        | Tenant disputes invoice was sent/paid      | ๐ŸŸก Med  | Audit log for all invoice state       |
|                    |                                           |        | changes and email deliveries          |
| Info Disclosure    | Cross-tenant data leak via API response    | ๐Ÿ”ด High | Tenant isolation middleware on ALL    |
|                    | or error messages                         |        | endpoints, sanitize error responses   |
| Denial of Service  | Large PDF generation blocks server         | ๐ŸŸก Med  | Queue PDF generation, set timeouts,   |
|                    |                                           |        | rate limit per tenant                 |
| Elevation of Priv  | Regular user accesses admin endpoints      | ๐Ÿ”ด High | RBAC per tenant, separate admin       |
|                    | or another tenant's admin panel           |        | middleware, validate role + tenant    |

### Key Finding
3 of 6 threat categories are ๐Ÿ”ด High โ€” all related to tenant isolation.
This confirms: tenant isolation middleware is the single most critical component.
๐Ÿšซ Don't Skip This

The STRIDE analysis identified that tenant isolation failures appear in three separate threat categories. This isn't a nice-to-have โ€” it's the architectural foundation. Sprint 3 will address these findings with targeted security stories.

Step 4: Schema design โ€” @dba

๐Ÿ—„๏ธ @dba designs the initial schema with tenant isolation baked into the data model:

๐Ÿ—„๏ธ @dba: Initial Schema Design

### Tables
tenants (id PK, name, slug, created_at)
users (id PK, tenant_id FK โ†’ tenants, email UNIQUE per tenant, role, password_hash)
invoices (id PK, tenant_id FK โ†’ tenants, client_name, client_email,
          status, due_date, created_at, updated_at)
invoice_items (id PK, invoice_id FK โ†’ invoices, tenant_id FK โ†’ tenants,
              description, quantity, unit_price DECIMAL(10,2), line_total DECIMAL(10,2))
payments (id PK, invoice_id FK โ†’ invoices, tenant_id FK โ†’ tenants,
          amount DECIMAL(10,2), payment_date, method)

### Key Constraints
- Every table has tenant_id (except tenants itself)
- Composite unique index on users(tenant_id, email)
- All FK cascades scoped to tenant
- DECIMAL(10,2) for ALL money fields โ€” never FLOAT

### Indexes
- idx_invoices_tenant_status ON invoices(tenant_id, status)
- idx_invoice_items_invoice ON invoice_items(invoice_id)
- idx_payments_invoice ON payments(invoice_id)

Step 5: Scaffold and initialize

๐Ÿ’ฌ "Set up the project with Express, PostgreSQL, and Jest. Then initialize."

โŒจ๏ธ @dev: Scaffolds project structure

/agile-setup-init        โ†’ All memory files populated โœ…
/agile-setup-onboard     โ†’ Coding rules generated โœ…
/agile-setup-health      โ†’ All checks green โœ…

Phase 1 complete. You have a multi-tenant architecture decision, a STRIDE threat model driving future security work, a schema design with tenant isolation at the data level, and a fully initialized project. Zero features built yet โ€” Sprint 0 is about foundations.

Phase 2: Sprint 1 โ€” Foundation (4 stories, ~16 pts) (~25 min)

Step 6: Create stories

๐Ÿ’ฌ You type

/agile-story-create Tenants can register their business and get a unique workspace with a slug URL

๐Ÿ“‹ @po responds:

## /agile-story-create โ€” Story Created

### Story US-001 (3 pts)
**As a** business owner,
**I want** to register my business as a tenant with a unique slug,
**so that** I get an isolated workspace for my invoicing.

### Acceptance Criteria
AC-1: POST /tenants with {name: "Acme Corp"} โ†’ 201, returns tenant with slug "acme-corp"
AC-2: Duplicate slug โ†’ 409 Conflict
AC-3: Missing name โ†’ 400 with error message
๐Ÿ’ฌ You type

/agile-story-create Users within a tenant can register, log in, and only see their tenant's data

๐Ÿ“‹ @po creates US-002 โ€” but @dev estimates it at 13 points. Too large for one story.

Step 7: Split the oversized story โ€” /agile-story-split

๐Ÿ’ฌ You type

/agile-story-split US-002 --strategy business-rules

๐Ÿ“‹ @po splits by business rules:

## /agile-story-split โ€” US-002 Split Into 3 Stories

| Story   | Title                          | Points | Rationale                    |
|---------|--------------------------------|--------|------------------------------|
| US-002a | User registration within tenant | 3      | Signup + tenant_id FK        |
| US-002b | Login + JWT with tenant claim  | 3      | Auth + tenant in token       |
| US-002c | Tenant isolation middleware    | 5      | Core security โ€” scopes ALL   |
|         |                                |        | queries by tenant_id         |

Original 13 pts โ†’ 3 stories totaling 11 pts (reduced uncertainty)

### INVEST Check: All 3 stories pass independently โœ…

Create the final foundation story:

๐Ÿ’ฌ /agile-story-create Create and manage invoices: add line items,
   calculate totals, set due dates

   โ†’ ๐Ÿ“‹ @po creates US-003: Invoice CRUD (5 pts)

Step 8: Sprint planning โ€” /agile-sprint-planning

๐Ÿ”„ @sm facilitates:

## Sprint 1 Planning

### Sprint Goal
"Deliver tenant registration, user auth with isolation, and invoice CRUD"

### Sprint Backlog
| Story   | Title                          | Points | Priority |
|---------|--------------------------------|--------|----------|
| US-001  | Tenant registration            | 3      | P1       |
| US-002a | User registration within tenant | 3      | P1       |
| US-002b | Login + JWT with tenant claim  | 3      | P1       |
| US-002c | Tenant isolation middleware    | 5      | P1       |
| US-003  | Invoice CRUD                   | 5      | P1       |

### Capacity
- Committed: 19 points (aggressive for Sprint 1)
- Risk: No historical velocity โ€” may need to carry US-003 to Sprint 2

Step 9: Build US-001 โ€” Tenant Registration (full loop)

/agile-code-branch feature US-001 tenant-registration
/agile-story-plan US-001
/agile-code-tdd US-001
  ๐Ÿ”ด Test: POST /tenants creates tenant with slug โ†’ โŒ
  ๐ŸŸข Implement tenant creation + slug generation โ†’ โœ…
  ๐Ÿ”ด Test: duplicate slug returns 409 โ†’ โŒ
  ๐ŸŸข Add unique constraint check โ†’ โœ…
  ๐Ÿ”ด Test: missing name returns 400 โ†’ โŒ
  ๐ŸŸข Add validation โ†’ โœ…
/agile-code-ci           โ†’ โœ… All green
/agile-code-commit       โ†’ feat(tenants): add tenant registration with slug
/agile-code-pr           โ†’ PR created
/agile-code-pr-review    โ†’ โœ… Approved (8/10)
/agile-code-merge        โ†’ Squash merged to develop
/agile-story-dod         โ†’ โœ… DONE
/agile-story-accept      โ†’ โœ… ACCEPTED (3 points)

Step 10: Build US-002a, US-002b, US-002c (abbreviated)

US-002a: User registration within tenant (3 pts)

/agile-code-branch feature US-002a user-registration
/agile-story-plan US-002a โ†’ @lead: Create user with tenant_id FK, validate
  email unique within tenant
/agile-code-tdd US-002a
  ๐Ÿ”ด Test: POST /tenants/:tenantId/users creates user โ†’ โŒ
  ๐ŸŸข Implement with tenant_id FK โ†’ โœ…
  ๐Ÿ”ด Test: duplicate email within same tenant โ†’ 409 โ†’ โŒ
  ๐ŸŸข Add composite unique check โ†’ โœ…
  ๐Ÿ”ด Test: same email in different tenant โ†’ 201 (allowed) โ†’ โŒ
  ๐ŸŸข Scope uniqueness to tenant โ†’ โœ…
/agile-code-ci โ†’ commit โ†’ PR โ†’ review โ†’ merge โ†’ DoD โ†’ accept โœ… (3 pts)

US-002b: Login + JWT with tenant claim (3 pts)

/agile-code-branch feature US-002b tenant-jwt
/agile-code-tdd US-002b
  ๐Ÿ”ด Test: POST /login returns JWT with tenant_id in payload โ†’ โŒ
  ๐ŸŸข Add tenant_id claim to JWT โ†’ โœ…
  ๐Ÿ”ด Test: invalid credentials โ†’ 401 โ†’ โŒ
  ๐ŸŸข Add credential validation โ†’ โœ…
/agile-code-ci โ†’ commit โ†’ PR โ†’ review โ†’ merge โ†’ DoD โ†’ accept โœ… (3 pts)

US-002c: Tenant isolation middleware (5 pts)

/agile-code-branch feature US-002c tenant-isolation
/agile-story-plan US-002c โ†’ @lead: Middleware extracts tenant_id from JWT,
  injects into every DB query. No endpoint should work without valid tenant context.
/agile-code-tdd US-002c
  ๐Ÿ”ด Test: request without JWT โ†’ 401 โ†’ โŒ
  ๐ŸŸข Add auth middleware โ†’ โœ…
  ๐Ÿ”ด Test: request with valid JWT โ†’ tenant_id injected into req โ†’ โŒ
  ๐ŸŸข Extract tenant_id from JWT claims โ†’ โœ…
  ๐Ÿ”ด Test: GET /invoices only returns current tenant's data โ†’ โŒ
  ๐ŸŸข Scope all queries with WHERE tenant_id = ? โ†’ โœ…
  ๐Ÿ”ด Test: GET /invoices/:id for another tenant's invoice โ†’ 404 (not 403!) โ†’ โŒ
  ๐ŸŸข Tenant-scoped lookup returns null โ†’ 404 โ†’ โœ…
/agile-code-ci โ†’ โœ… All green

๐Ÿ—„๏ธ @dba reviews the migration for the users table:

๐Ÿ—„๏ธ @dba: Migration Review
  โœ… tenant_id FK with ON DELETE CASCADE โ€” correct
  โœ… Composite unique index (tenant_id, email) โ€” correct
  โš ๏ธ Missing index on users(tenant_id) for tenant-scoped lookups โ€” add it
  โ†’ @dev adds index, tests still pass โœ…

๐Ÿงช @qa runs the critical isolation test:

๐Ÿงช @qa: Tenant Isolation Verification

Test: Can tenant A see tenant B's invoices?
  1. Create tenant A, create invoice for tenant A
  2. Create tenant B, authenticate as tenant B
  3. GET /invoices โ†’ returns [] (not tenant A's invoice) โœ…
  4. GET /invoices/:tenantA-invoiceId โ†’ 404 (not 200) โœ…
  5. Direct DB query confirms data exists but middleware blocks it โœ…

Verdict: โœ… Isolation verified โ€” no cross-tenant data leakage
/agile-code-commit โ†’ feat(auth): add tenant isolation middleware
/agile-code-pr โ†’ PR created
/agile-code-pr-review
  ๐Ÿ‘จโ€๐Ÿ’ป @lead: PR Review โ€” US-002c (CRITICAL component)

  | # | Severity | Finding                                    | Fix                          |
  |---|----------|--------------------------------------------|------------------------------|
  | 1 | ๐ŸŸก S2   | Middleware doesn't handle expired JWTs      | Add expiry check             |
  |   |          | differently from missing JWTs               | with distinct error message  |
  | 2 | ๐Ÿ”ต S3   | Magic string "tenant_id" repeated           | Extract to constant          |

  Score: 8/10
  Verdict: โœ… APPROVED โ€” isolation logic is solid
/agile-code-merge โ†’ Squash merged to develop
/agile-story-dod โ†’ โœ… DONE
/agile-story-accept โ†’ โœ… ACCEPTED (5 pts)

Step 11: Build US-003 โ€” Invoice CRUD (5 pts, abbreviated)

/agile-code-branch feature US-003 invoice-crud
/agile-code-tdd US-003
  ๐Ÿ”ด Test: POST /invoices creates invoice with line items โ†’ โŒ
  ๐ŸŸข Implement with tenant-scoped insert โ†’ โœ…
  ๐Ÿ”ด Test: GET /invoices returns only current tenant's invoices โ†’ โŒ
  ๐ŸŸข Query scoped by tenant_id from middleware โ†’ โœ…
  ๐Ÿ”ด Test: line item totals auto-calculated โ†’ โŒ
  ๐ŸŸข Calculate line_total = quantity * unit_price, sum for invoice total โ†’ โœ…
  ๐Ÿ”ด Test: invoice with zero items โ†’ 400 โ†’ โŒ
  ๐ŸŸข Validate at least one line item required โ†’ โœ…
/agile-code-ci โ†’ commit โ†’ PR โ†’ review โ†’ merge โ†’ DoD โ†’ accept โœ… (5 pts)

Step 12: Sprint 1 ceremonies

/agile-sprint-review
  Sprint Goal Met: โœ… Yes
  Completed: 19/19 points (100%)
  Velocity baseline: 19 points

/agile-sprint-retro
  What went well: Story splitting reduced US-002 risk significantly
  What went well: Tenant isolation tested thoroughly โ€” high confidence
  To improve: Sprint was aggressive โ€” 19 pts may not be sustainable
  Action items:
    | Action                              | Owner | Due      |
    |-------------------------------------|-------|----------|
    | Target 15-16 pts next sprint        | @sm   | Sprint 2 |
    | Add tenant isolation to test template| @qa   | Sprint 2 |

/agile-memory-learn โ†’ Sprint 1 velocity: 19 pts, story splitting effective

Phase 3: Sprint 2 โ€” Business Logic (3 stories, ~13 pts) (~25 min)

Step 13: Refine the backlog โ€” /agile-sprint-refine

/agile-sprint-refine

๐Ÿ“‹ @po: Backlog refined
  US-004: Generate PDF invoices โ€” Ready โœ… (ACs updated with logo, line items, totals)
  US-005: Send invoice by email โ€” Ready โœ… (ACs include retry on failure)
  US-006: Track payments โ€” Ready โœ… (ACs include partial payment, overdue status)

Step 14: Create Sprint 2 stories

๐Ÿ’ฌ /agile-story-create Generate PDF invoices from invoice data.
   The PDF should include company logo, line items, totals, payment terms.
   โ†’ ๐Ÿ“‹ @po creates US-004 (5 pts)

๐Ÿ’ฌ /agile-story-create Send invoice by email to the client
   with the PDF attached
   โ†’ ๐Ÿ“‹ @po creates US-005 (3 pts)

๐Ÿ’ฌ /agile-story-create Track payments against invoices:
   mark as paid, partially paid, or overdue
   โ†’ ๐Ÿ“‹ @po creates US-006 (5 pts)
/agile-sprint-planning
  Sprint Goal: "Add PDF generation, email delivery, and payment tracking"
  Committed: 13 points (down from 19 โ€” learning from retro โœ…)

Step 15: Spike for PDF library โ€” /agile-explore-spike

PDF generation has unknowns. Before committing to an implementation, @dev runs a time-boxed spike:

๐Ÿ’ฌ You type

/agile-explore-spike Evaluate PDF generation libraries for Node.js. Need: company logo, styled table of line items, totals, payment terms. Time-box: 2 hours.

โŒจ๏ธ @dev runs a time-boxed spike:

## /agile-explore-spike โ€” PDF Library Evaluation (2h time-box)

### Libraries Tested
| Library     | Logo Support | Table Layout | File Size | Render Speed | Verdict    |
|-------------|-------------|--------------|-----------|-------------|------------|
| PDFKit      | โœ… Images   | Manual layout| 180KB     | 120ms       | โœ… Winner  |
| Puppeteer   | โœ… HTML/CSS | Full CSS     | 850KB     | 2.1s        | Too heavy  |

### Recommendation
PDFKit โ€” fast rendering, small output, manual layout is acceptable
for structured invoice format.

### What We Learned
Puppeteer renders HTML to PDF (flexible) but requires a headless browser
(heavy dependency, slow). PDFKit is code-driven (less flexible) but
10x faster and no external dependencies.

### Decision
Use PDFKit for MVP. If layout needs become complex, revisit Puppeteer.

> ๐Ÿ’ฌ /agile-memory-remember PDF generation: PDFKit chosen over Puppeteer.
>    Reason: 10x faster, no headless browser dependency.
>    Revisit if layout complexity increases.

Step 16: Build US-004 โ€” PDF Generation (5 pts)

/agile-code-branch feature US-004 pdf-generation
/agile-story-plan US-004
/agile-code-tdd US-004
  ๐Ÿ”ด Test: POST /invoices/:id/pdf returns a PDF buffer โ†’ โŒ
  ๐ŸŸข Implement PDFKit rendering โ†’ โœ…
  ๐Ÿ”ด Test: PDF contains company name, line items, totals โ†’ โŒ
  ๐ŸŸข Add structured layout: header, items table, total โ†’ โœ…
  ๐Ÿ”ด Test: PDF for another tenant's invoice โ†’ 404 โ†’ โŒ
  ๐ŸŸข Tenant-scoped lookup (middleware handles it) โ†’ โœ…
/agile-code-ci โ†’ commit โ†’ PR โ†’ review โ†’ merge โ†’ DoD โ†’ accept โœ… (5 pts)

Step 17: Performance profiling โ€” /agile-code-perf

After implementation, PDF generation is slow for large invoices. Time to profile:

๐Ÿ’ฌ You type

/agile-code-perf Profile PDF generation. It takes 3 seconds for a 50-line invoice. Target: under 500ms.

โŒจ๏ธ @dev profiles and optimizes:

## /agile-code-perf โ€” PDF Generation Profiling

### Bottleneck Analysis
| Operation           | Time    | % of Total |
|---------------------|---------|------------|
| DB query (invoice)  | 45ms    | 1.5%       |
| DB query (items)    | 62ms    | 2.1%       |
| Font loading        | 2,400ms | 80.0% โ† ๐Ÿ”ด |
| PDF rendering       | 320ms   | 10.7%      |
| Buffer finalization | 173ms   | 5.8%       |

### Root Cause
Font files loaded from disk on EVERY PDF generation.
PDFKit re-reads and re-parses .ttf files per request.

### Fix
Cache font objects at module load time โ€” load once, reuse forever.

### Results
| Metric         | Before  | After  | Improvement |
|----------------|---------|--------|-------------|
| 50-line invoice | 3,000ms | 380ms  | 87% faster  |
| Memory per PDF | 12MB    | 4MB    | 67% less    |

โœ… Target met: 380ms < 500ms

Step 18: Build US-005 โ€” Email Delivery (3 pts)

/agile-code-branch feature US-005 email-delivery
/agile-code-tdd US-005
  ๐Ÿ”ด Test: POST /invoices/:id/send triggers email with PDF attachment โ†’ โŒ
  ๐ŸŸข Implement email sending via nodemailer โ†’ โœ…
  ๐Ÿ”ด Test: email failure returns 502 with retry guidance โ†’ โŒ
  ๐ŸŸข Add error handling with status tracking โ†’ โœ…
  ๐Ÿ”ด Test: resending already-sent invoice updates sent_at โ†’ โŒ
  ๐ŸŸข Track email delivery attempts โ†’ โœ…
/agile-code-ci โ†’ commit โ†’ PR

๐Ÿ‘จโ€๐Ÿ’ป @lead catches an important issue in review:

๐Ÿ‘จโ€๐Ÿ’ป @lead: PR Review โ€” US-005

| # | Severity | Finding                                    | Fix                         |
|---|----------|--------------------------------------------|-----------------------------|
| 1 | ๐ŸŸก S2   | Email failure silently swallowed โ€” caller   | Return 502 with error,      |
|   |          | gets 200 even when email fails             | log failure, mark invoice   |
|   |          |                                            | send_status as "failed"     |

โ†’ @dev fixes, re-runs CI โœ…
/agile-code-merge โ†’ DoD โ†’ accept โœ… (3 pts)

Step 19: Build US-006 โ€” Payment Tracking (5 pts)

๐Ÿ—„๏ธ @dba designs the payment tracking schema before implementation:

๐Ÿ—„๏ธ @dba: Payment Schema Design

payments (
  id          SERIAL PRIMARY KEY,
  invoice_id  INTEGER REFERENCES invoices(id),
  tenant_id   INTEGER REFERENCES tenants(id),
  amount      DECIMAL(10,2) NOT NULL,  -- โš ๏ธ DECIMAL, not FLOAT!
  payment_date TIMESTAMP DEFAULT NOW(),
  method      VARCHAR(20) CHECK (method IN ('bank_transfer','card','cash'))
)

### Why DECIMAL, not FLOAT?
FLOAT: 0.1 + 0.2 = 0.30000000000000004 โ†’ rounding errors in financial totals
DECIMAL: 0.1 + 0.2 = 0.3 โ†’ exact arithmetic, required for money

### Invoice Status Logic
- paid: SUM(payments.amount) >= invoice.total
- partially_paid: SUM(payments.amount) > 0 AND < invoice.total
- overdue: due_date < NOW() AND status != 'paid'
/agile-code-branch feature US-006 payment-tracking
/agile-code-tdd US-006
  ๐Ÿ”ด Test: POST /invoices/:id/payments records payment โ†’ โŒ
  ๐ŸŸข Implement payment creation with DECIMAL arithmetic โ†’ โœ…
  ๐Ÿ”ด Test: payment exceeding remaining balance โ†’ 400 โ†’ โŒ
  ๐ŸŸข Add overpayment validation โ†’ โœ…
  ๐Ÿ”ด Test: partial payment updates status to "partially_paid" โ†’ โŒ
  ๐ŸŸข Recalculate invoice status after each payment โ†’ โœ…
  ๐Ÿ”ด Test: full payment updates status to "paid" โ†’ โŒ
  ๐ŸŸข SUM check against invoice total โ†’ โœ…
/agile-code-ci โ†’ commit โ†’ PR โ†’ review โ†’ merge โ†’ DoD โ†’ accept โœ… (5 pts)

Step 20: Mid-sprint health check โ€” /agile-sprint-status

/agile-sprint-status

๐Ÿ”„ @sm: Sprint 2 Status
  | Story  | Status     | Points |
  |--------|------------|--------|
  | US-004 | โœ… Done     | 5      |
  | US-005 | โœ… Done     | 3      |
  | US-006 | โœ… Done     | 5      |

  Progress: 13/13 points (100%)
  Sprint Goal: โœ… On track
  Velocity trend: Sprint 1 = 19, Sprint 2 = 13 (stabilizing)

Step 21: Sprint 2 ceremonies

/agile-sprint-review
  Sprint Goal Met: โœ… Yes
  Velocity: 13/13 points (100%)
  Cumulative: Sprint 1 (19) + Sprint 2 (13) = 32 points

/agile-sprint-retro
  What went well: Spike prevented wrong PDF library choice
  What went well: @lead caught silent email failure โ€” would have been a production bug
  What went well: DECIMAL for money โ€” correct from day one
  To improve: Should profile performance earlier, not after implementation
  Action items:
    | Action                               | Owner | Due      |
    |--------------------------------------|-------|----------|
    | Add perf benchmarks to CI            | @dev  | Sprint 3 |
    | Run OWASP audit before release       | @sec  | Sprint 3 |

/agile-memory-learn โ†’ Sprint 2 velocity: 13 pts, spike ROI validated

Phase 4: Sprint 3 โ€” Security & Production Readiness (~20 min)

Sprint 3 addresses the STRIDE findings from Sprint 0 and prepares for production release.

Step 22: Security audit โ€” /agile-security-audit

๐Ÿ’ฌ You type

/agile-security-audit Scan invoice and payment code against OWASP Top 10

๐Ÿ›ก๏ธ @sec responds:

## /agile-security-audit โ€” OWASP Top 10 Scan

### Findings

| # | Severity | Category              | Finding                               | Location              |
|---|----------|-----------------------|---------------------------------------|-----------------------|
| 1 | ๐Ÿ”ด S0   | A01: Broken Access    | Tenant isolation bypass via IDOR โ€”    | GET /invoices/:id     |
|   |          | Control               | direct ID guessing bypasses middleware | (missing tenant check |
|   |          |                       | on direct-ID lookups                  | in findById query)    |
| 2 | ๐ŸŸ  S1   | A03: Injection        | Invoice amounts accepted from client  | POST /invoices        |
|   |          |                       | without server-side validation โ€”      | (line item prices)    |
|   |          |                       | negative prices allowed               |                       |
| 3 | ๐ŸŸก S2   | A03: Injection        | PDF generation doesn't sanitize HTML  | PDF template          |
|   |          |                       | in client_name field โ€” XSS in PDF     | rendering             |

### Required Actions
Fix #1 (S0) and #2 (S1) โ€” mandatory before release.
Fix #3 (S2) โ€” recommended before release.
๐Ÿšซ S0: Tenant Isolation Bypass

The findById query fetches invoices by ID without scoping to the current tenant. An attacker who guesses an invoice ID from another tenant can access it directly. This is exactly the IDOR threat identified in the STRIDE analysis during Sprint 0.

Step 23: Fix security findings with TDD

Fix S0: IDOR โ€” Tenant isolation bypass

/agile-code-tdd Fix S0: scope findById queries by tenant_id

๐Ÿ”ด RED:
test('GET /invoices/:id from another tenant returns 404', async () => {
  // Create invoice as tenant A
  const invoice = await createInvoice(tenantA);
  // Request as tenant B
  const res = await request(app)
    .get(`/invoices/${invoice.id}`)
    .set('Authorization', `Bearer ${tenantBToken}`);
  expect(res.status).toBe(404);  // NOT 200!
});
// โŒ FAIL โ€” returns 200 with tenant A's invoice data

๐ŸŸข GREEN:
// Fix: Add tenant_id to ALL findById queries
findById(id, tenantId) {
  return db.query(
    'SELECT * FROM invoices WHERE id = $1 AND tenant_id = $2',
    [id, tenantId]
  );
}
// โœ… PASS โ€” returns 404 for cross-tenant access

Fix S1: Server-side amount validation

/agile-code-tdd Fix S1: validate invoice amounts server-side

๐Ÿ”ด RED:
test('negative unit_price rejected with 400', async () => {
  const res = await request(app)
    .post('/invoices')
    .set('Authorization', `Bearer ${token}`)
    .send({ items: [{ description: 'Item', quantity: 1,
      unit_price: -50.00 }] });
  expect(res.status).toBe(400);
});
// โŒ FAIL โ€” returns 201 with negative amount

๐ŸŸข GREEN:
// Add validation: quantity > 0, unit_price >= 0
if (item.unit_price < 0 || item.quantity <= 0) {
  return res.status(400).json({
    error: 'unit_price must be >= 0, quantity must be > 0'
  });
}
// โœ… PASS
๐Ÿ’ฌ /agile-security-audit --recheck
  ๐Ÿ›ก๏ธ @sec: Re-audit results
    #1 IDOR: โœ… Fixed โ€” all findById queries now tenant-scoped
    #2 Amounts: โœ… Fixed โ€” server-side validation on all numeric fields
    #3 PDF XSS: โœ… Fixed โ€” HTML entities escaped in PDF text fields

Step 24: Dependency scan โ€” /agile-security-scan

/agile-security-scan

๐Ÿ›ก๏ธ @sec: Dependency CVE Scan
  Packages scanned: 147
  Vulnerabilities found: 1
    ๐ŸŸก CVE-2025-XXXX in nodemailer < 6.9.8 (ReDoS in email parsing)
    Fix: npm update nodemailer โ†’ 6.9.9 โœ…

  Post-fix scan: โœ… 0 vulnerabilities

Step 25: Security review โ€” /agile-security-review

/agile-security-review Review auth middleware, tenant isolation, and payment handling

๐Ÿ›ก๏ธ @sec: Security Review
  Auth middleware: โœ… JWT validated, expiry checked, tenant_id extracted
  Tenant isolation: โœ… All queries scoped (verified after S0 fix)
  Payment handling: โœ… DECIMAL arithmetic, overpayment prevented
  Password storage: โœ… bcrypt with cost factor 12

  Overall: โœ… PASS โ€” ready for production

Step 26: UX and accessibility โ€” @ux

๐ŸŽจ @ux builds the invoice creation form and verifies accessibility:

๐ŸŽจ @ux: Invoice Form + Dashboard

### WCAG AA Accessibility Checklist
| Criterion                        | Status |
|----------------------------------|--------|
| Color contrast ratio โ‰ฅ 4.5:1    | โœ…     |
| All form inputs have labels      | โœ…     |
| Keyboard navigation works        | โœ…     |
| Screen reader announces errors   | โœ…     |
| Focus management on add/remove   | โœ…     |
| Responsive: mobile invoice form  | โœ…     |

### Responsive Verification
- Desktop (1200px+): full table layout โœ…
- Tablet (768px): stacked cards โœ…
- Mobile (375px): single-column, touch-friendly โœ…

Step 27: Refactor 3 sprints of code โ€” /agile-code-refactor

๐Ÿ’ฌ You type

/agile-code-refactor Analyze the codebase after 3 sprints. Focus on duplication, complexity, and consistency.

## /agile-code-refactor โ€” Analysis + Refactoring

### Before
| Metric              | Value    |
|---------------------|----------|
| Code duplication    | 14%      |
| Avg cyclomatic complexity | 8.2 |
| Inconsistent error handling | 6 locations |

### Changes Made
1. Extracted tenant-scoped query builder (eliminated 8 duplicate WHERE clauses)
2. Unified error response format across all endpoints
3. Extracted validation middleware (DRY)

### After
| Metric              | Before | After  | Change |
|---------------------|--------|--------|--------|
| Code duplication    | 14%    | 3%     | -79%   |
| Avg cyclomatic complexity | 8.2 | 4.1  | -50%   |
| Inconsistent errors | 6      | 0      | -100%  |

Tests: โœ… All 47 tests still pass

Step 28: Architecture health โ€” /agile-explore-audit

/agile-explore-audit

๐Ÿ—๏ธ @arch: Architecture Health After 3 Sprints

### Health Score: 8.5/10

| Dimension         | Score | Notes                                     |
|--------------------|-------|------------------------------------------|
| Separation of concerns | 9/10 | Clean layers: routes โ†’ services โ†’ repos |
| Dependency management  | 8/10 | No circular deps, clean imports          |
| Testability           | 9/10 | All services injectable, 94% coverage   |
| Security posture      | 8/10 | STRIDE mitigations implemented           |
| Scalability path      | 8/10 | Tenant isolation ready for schema split  |

### Recommendation
Architecture is healthy. When tenant count exceeds ~500,
consider migrating to separate schemas (the #2 option from Sprint 0).
The tenant_id abstraction makes this migration straightforward.

Step 29: Sprint 3 ceremonies

/agile-sprint-review
  Sprint Goal Met: โœ… Yes โ€” security hardened, UI accessible, code refactored
  Velocity: 7 points (security + refactoring stories)
  Cumulative: 19 + 13 + 7 = 39 points across 3 sprints

/agile-sprint-retro
  What went well: STRIDE analysis in Sprint 0 predicted exact security findings
  What went well: Refactoring after 3 sprints brought duplication from 14% to 3%
  What went well: All 10 roles contributed meaningfully
  To improve: Should run /agile-security-audit after each sprint, not just Sprint 3
  Action items:
    | Action                                    | Owner | Due     |
    |-------------------------------------------|-------|---------|
    | Add security audit to sprint checklist    | @sm   | Future  |
    | Monitor tenant count for schema migration | @arch | Ongoing |

/agile-memory-learn โ†’ Final sprint learnings saved
  โ†’ Velocity trend: 19 โ†’ 13 โ†’ 7 (stabilized, security sprints are lower velocity)
  โ†’ STRIDE ROI: 100% of predicted threats were found and fixed

Phase 5: Release (~5 min)

Step 30: Changelog โ€” /agile-ship-changelog

## Changelog: v1.0.0 โ€” Multi-Tenant Invoicing SaaS

### Sprint 1 โ€” Foundation
- Tenant registration with unique slugs (US-001)
- User registration scoped to tenant (US-002a)
- JWT authentication with tenant claims (US-002b)
- Tenant isolation middleware โ€” all queries tenant-scoped (US-002c)
- Invoice CRUD with line items and auto-calculated totals (US-003)

### Sprint 2 โ€” Business Logic
- PDF invoice generation via PDFKit (US-004)
- Email delivery with PDF attachment and retry tracking (US-005)
- Payment tracking: paid, partially paid, overdue statuses (US-006)

### Sprint 3 โ€” Security & Quality
- Fixed IDOR vulnerability in invoice lookup (S0)
- Added server-side validation for invoice amounts (S1)
- Sanitized HTML in PDF generation (S2)
- Updated nodemailer to patch CVE
- WCAG AA accessible invoice form and dashboard
- Codebase refactored: duplication 14% โ†’ 3%

Step 31: Cut release โ€” /agile-ship-release

/agile-ship-release v1.0.0

๐Ÿš€ @devops: Release v1.0.0
  Branch: release/v1.0.0 from develop
  CI: โœ… Green (47 tests, 0 vulnerabilities)
  Merged to main โœ…
  Tagged: v1.0.0 โœ…
  Back-merged to develop โœ…

Step 32: Deploy โ€” /agile-ship-deploy

/agile-ship-deploy v1.0.0 --env production

๐Ÿš€ @devops: Deployed v1.0.0 to production
  Smoke tests:
    โœ… Tenant registration
    โœ… User login + JWT
    โœ… Invoice CRUD (tenant-scoped)
    โœ… PDF generation (380ms avg)
    โœ… Payment recording
  Health check: โœ…
  Monitoring: 30-minute observation window started

  Rollback plan: /agile-ship-rollback v0.0.0 (empty state)
  โ†’ Safety net ready if issues emerge during observation

What You Built

MetricValue
Sprints completed3
Stories completed10 (including split stories)
Story points delivered39 (19 + 13 + 7)
Sprint goals metโœ… All 3
Security findings fixed3 (1 S0, 1 S1, 1 S2)
Release versionv1.0.0
Test coverage94% (47 tests)
Roles involvedAll 10: @po, @sm, @arch, @lead, @dev, @qa, @dba, @sec, @ux, @devops

Commands Used

This project used nearly every command in the framework. Here's the full checklist:

CategoryCommandUsed?Where
Setup/agile-setup-initโœ…Sprint 0 โ€” project initialization
/agile-setup-onboardโœ…Sprint 0 โ€” coding rules
/agile-setup-healthโœ…Sprint 0 โ€” verify setup
/agile-setup-doctorโž–Not needed (no config issues)
Story/agile-story-createโœ…All sprints โ€” 6 stories created
/agile-story-estimateโœ…Sprint planning
/agile-story-planโœ…Every story implementation
/agile-story-implementโœ…Execution of implementation plans
/agile-story-splitโœ…US-002 split into 3 stories
/agile-story-dodโœ…Every story completion
/agile-story-acceptโœ…Every story acceptance
/agile-story-rejectโž–Not needed (all stories passed)
Sprint/agile-sprint-planningโœ…All 3 sprint starts
/agile-sprint-statusโœ…Sprint 2 mid-sprint check
/agile-sprint-refineโœ…Before Sprint 2 planning
/agile-sprint-reviewโœ…All 3 sprint ends
/agile-sprint-retroโœ…All 3 sprint ends
/agile-sprint-cancelโž–Not needed (no cancelled sprints)
Code/agile-code-branchโœ…Every story branch
/agile-code-tddโœ…Every story + security fixes
/agile-code-ciโœ…Every story CI check
/agile-code-commitโœ…Every story commit
/agile-code-prโœ…Every story PR
/agile-code-pr-reviewโœ…Every story review
/agile-code-mergeโœ…Every story merge
/agile-code-refactorโœ…Sprint 3 โ€” codebase cleanup
Code (cont.)/agile-code-perfโœ…Sprint 2 โ€” PDF optimization
/agile-code-debugโž–Not needed (no runtime bugs)
Explore/agile-explore-brainstormโœ…Sprint 0 โ€” multi-tenant strategy
/agile-explore-spikeโœ…Sprint 2 โ€” PDF library evaluation
/agile-explore-pocโž–Not needed (spike was sufficient)
/agile-explore-auditโœ…Sprint 3 โ€” architecture health
Security/agile-security-threat-modelโœ…Sprint 0 โ€” STRIDE analysis
/agile-security-auditโœ…Sprint 3 โ€” OWASP Top 10 scan
/agile-security-scanโœ…Sprint 3 โ€” dependency CVE check
/agile-security-reviewโœ…Sprint 3 โ€” auth + payment review
Ship/agile-ship-changelogโœ…Release โ€” 3-sprint changelog
/agile-ship-releaseโœ…Release โ€” v1.0.0
/agile-ship-deployโœ…Release โ€” production deploy
/agile-ship-hotfixโž–Not needed (no production incidents)
/agile-ship-rollbackโž–Mentioned as safety net
Memory/agile-memory-rememberโœ…Sprint 0 โ€” architecture decision, Sprint 2 โ€” PDF choice
/agile-memory-recallโœ…Referenced across sprints
/agile-memory-learnโœ…All 3 sprint retros

All 10 Roles โ€” What They Contributed

RoleKey Contribution
๐Ÿ“‹ @poCreated 6 stories with tenant-scoped acceptance criteria, split US-002, accepted all stories
๐Ÿ”„ @smManaged 3 sprints, tracked velocity trend (19 โ†’ 13 โ†’ 7), facilitated 3 retros with actionable items
๐Ÿ—๏ธ @archEvaluated multi-tenant strategies, recorded ADR, validated architecture health after 3 sprints
๐Ÿ‘จโ€๐Ÿ’ป @leadCaught silent email failure, reviewed tenant isolation code for cross-tenant leaks
โŒจ๏ธ @devTDD on all stories, PDF performance optimization (3s โ†’ 380ms), security fixes
๐Ÿงช @qaVerified tenant isolation ("can tenant A see tenant B's data?"), 94% coverage
๐Ÿ—„๏ธ @dbaDesigned schema with tenant_id FKs, DECIMAL for money, composite indexes, migration review
๐Ÿ›ก๏ธ @secSTRIDE analysis predicted exact vulnerabilities, OWASP audit found IDOR, CVE scan cleared deps
๐ŸŽจ @uxAccessible invoice form (WCAG AA), responsive dashboard, mobile-friendly layout
๐Ÿš€ @devopsCI pipeline on every story, production deploy with smoke tests + 30-min monitoring window
โœ… Key Takeaway

You've delivered a production SaaS using the complete framework. From STRIDE threat modeling to PDF performance tuning, from tenant isolation testing to accessible invoice forms โ€” every role contributed. This is how professional teams ship complex software: structured process, specialized roles, relentless quality gates.

The framework scales from a simple todo API (Project 01) to a multi-tenant SaaS (this project). The core loop never changes โ€” create stories โ†’ plan sprint โ†’ branch โ†’ TDD โ†’ CI โ†’ PR โ†’ review โ†’ merge โ†’ accept โ†’ release โ€” but the roles and commands you activate grow with the complexity of what you're building.

๐Ÿง  Knowledge Check

Why do STRIDE analysis before Sprint 1, not after?

๐Ÿง  Knowledge Check

Why use DECIMAL and not FLOAT for money in the database?

๐Ÿง  Knowledge Check

What does the tenant isolation middleware do?