# Traceability and Test Plan Seed

Date: 2026-06-15

Use this as a seed matrix. Claude should expand it into a full test plan with IDs, priority, preconditions, data, steps, expected results, automation suitability, owner, and traceability.

## Priority Definitions

- P0: Blocks commercial beta or risks tenant/customer/financial data.
- P1: Blocks core operational workflow.
- P2: Important regression or usability risk.
- P3: Nice-to-have, lower-risk, or future-readiness check.

## Test Layers

- Unit/service: deterministic service, calculator, validator, registry, or utility logic.
- Controller/HTTP: route, permission, CSRF, redirect, status, template wiring.
- Browser E2E: visible navigation, clicks, forms, downloads, responsive UI.
- DB/repository: schema import, SQL behavior, tenant scope, precision, persistence.
- Security: auth/RBAC/CSRF/XSS/secrets/uploads/audit/tenant isolation.
- Contract/mock integration: provider behavior without live credentials.
- Manual QA: exploratory and acceptance checks for local demo.

## Core Traceability Matrix

| Feature area | Business risk | Priority | Unit/service tests | Controller/HTTP tests | Browser E2E tests | Security/negative tests |
| --- | --- | --- | --- | --- | --- | --- |
| App routing/base path | App unusable under XAMPP path | P0 | `Request::path`, `basePath`, renderer prefixing | Every route under `/FieldOps-Cloud/public` | Click all nav links | Unknown route 404; no broken XAMPP links |
| Auth/session | Unauthorised access or session leakage | P0 | `SessionAuth`, password hasher | demo switch, logout | Switch company/platform demo | Production no-auto-login gate |
| RBAC | Tenant users access platform/admin data | P0 | `RbacService` allow/deny | Every protected route by role | Role-switch smoke | Denied routes 403 |
| CSRF | Form tampering | P0 | `CsrfService` | POST missing/invalid token | Submit normal forms | Tampered token rejected |
| Platform admin | SaaS operator misconfiguration | P0 | `PlatformAdminService` actions | platform routes and tenant action posts | nav, tenant detail, action forms | confirmation required, audit written |
| Support login-as | Tenant data access abuse | P0 | `SessionAuth::impersonateTenantAdmin`, audit support history | login/return routes | login as tenant and return | reason required, expiry, platform-only |
| Platform billing | Incorrect tenant invoicing | P0 | ledger, summary, override validation | billing override route | override/pause/resume UI | reason, amount limits, permission |
| Pricing | Wrong trial/discount/currency | P0 | validate settings, currency fallback, discount math | pricing save/reset | pricing form and public pricing | invalid currency/region/tax/price |
| Quotes | Wrong estimates and revenue | P1 | quote validation, totals, draft lock | create/view/edit/update | create, drill-in, edit draft | sent/approved lock; bad money inputs |
| Invoices | Wrong billing/payment follow-up | P1 | invoice validation, totals, unpaid lock | create/view/edit/update | create, drill-in, edit unpaid | paid/overdue lock; bad money inputs |
| Clients | Customer data corruption | P1 | validation, merge, form mapping | create/view/edit/update | create, search, edit | XSS in customer fields |
| Jobs | Field work tracking confusion | P1 | job validation, search, detail helpers | list/view/create | search/filter/detail/create | invalid statuses, unknown id |
| Schedule | Double-booking technicians | P1 | week, validation, conflict | schedule GET/POST | click slot, book appointment | overlapping same technician |
| Team | Role/contact data errors | P1 | validation, merge by email | view/edit/update | drill-in, edit/save | manage_team required |
| Import validation | Bad/malicious data import | P1 | schemas, header normalization, protocol rules | import page/sample route | select type, sample CSV | unknown/missing headers, formula payloads |
| Export CSV | Data leak or unsafe spreadsheet output | P1 | csv-safe cells | export/download route | download datasets | permission, formula injection |
| Accounting settings | False live integration confidence | P1 | provider registry, validation | accounting pages/connect | provider list, sandbox link | unsupported/live mode blocked |
| Calendar settings | Broken/unsafe two-way sync contract | P1 | provider registry, sync validation/conflict | calendar settings | provider list | unsupported provider, conflict states |
| LLM settings | Secret leak or unsafe AI mutation | P1 | provider validation, masking, safety rules | LLM settings | settings UI | HTTPS-only, no raw key output |
| Reports | Misleading business metrics | P2 | report demo data counts | reports route | cards display | permission |
| Demo management | Demo data corruption | P2 | reset service scoping | demo reset route | reset button | explicit reset only, audited |
| System health | False platform readiness | P2 | health snapshot | health route | health page | placeholders labelled clearly |
| Security admin | Compliance blind spots | P2 | security snapshot | security route | page renders | checklist pending items visible |
| Mobile/offline status | App-readiness confusion | P3 | mobile snapshot | mobile route | page renders | placeholders labelled clearly |

## Detailed Test Case Seeds

### Routing and UI Smoke

- TC-ROUTE-001: GET every route with allowed role returns expected 200/302/download status.
- TC-ROUTE-002: GET unknown route returns 404.
- TC-ROUTE-003: All sidebar/nav links resolve under `/FieldOps-Cloud/public`.
- TC-ROUTE-004: Root-relative form actions are prefixed under XAMPP base path.
- TC-ROUTE-005: Every visible button/link on dashboard, clients, jobs, schedule, quotes, invoices, team, reports, settings, platform admin is clickable or intentionally disabled with clear copy.

### RBAC and CSRF

- TC-RBAC-001: Platform admin routes denied to owner, manager, supervisor, team_member, trainee, demo_user.
- TC-RBAC-002: Tenant operational routes denied to platform_admin where platform_admin lacks route-specific permissions.
- TC-RBAC-003: Team edit/update denied to demo_user and supervisor.
- TC-RBAC-004: Quote update denied to demo_user and supervisor.
- TC-RBAC-005: Invoice update denied to demo_user and supervisor.
- TC-CSRF-001: Each POST route rejects missing `_csrf`.
- TC-CSRF-002: Each POST route rejects invalid `_csrf`.
- TC-CSRF-003: Each valid form contains a CSRF hidden field.

### Quotes

- TC-QUOTE-001: Quote list shows seeded and created quotes.
- TC-QUOTE-002: Search/filter by status and text.
- TC-QUOTE-003: New quote button opens create form.
- TC-QUOTE-004: Valid quote with one line item saves and appears in list.
- TC-QUOTE-005: Valid quote with two line items calculates subtotal/tax/total.
- TC-QUOTE-006: Missing customer rejected.
- TC-QUOTE-007: Unsupported status rejected.
- TC-QUOTE-008: Invalid date rejected.
- TC-QUOTE-009: Negative/zero quantity rejected.
- TC-QUOTE-010: Unit price > 1,000,000 rejected.
- TC-QUOTE-011: Draft quote detail has edit action.
- TC-QUOTE-012: Sent/approved quote detail has no edit action or route returns locked response.
- TC-QUOTE-013: Save draft edit merges by quote number without duplicate.

### Invoices

- TC-INVOICE-001: Invoice list shows seeded and created invoices.
- TC-INVOICE-002: New invoice button opens create form.
- TC-INVOICE-003: Valid unpaid invoice saves.
- TC-INVOICE-004: Valid invoice totals calculate correctly.
- TC-INVOICE-005: Missing customer rejected.
- TC-INVOICE-006: Unsupported status rejected.
- TC-INVOICE-007: Invalid due date rejected.
- TC-INVOICE-008: Paid invoice edit denied/locked.
- TC-INVOICE-009: Overdue invoice edit denied/locked unless product owner changes rule.
- TC-INVOICE-010: Save unpaid edit merges by invoice number without duplicate.

### Schedule

- TC-SCHED-001: Calendar starts Monday.
- TC-SCHED-002: Previous/today/next week links work.
- TC-SCHED-003: Time slot click sets form date/time.
- TC-SCHED-004: Existing-client appointment saves.
- TC-SCHED-005: Potential-client appointment saves with client_status potential.
- TC-SCHED-006: Internal meeting uses Internal Team.
- TC-SCHED-007: Same technician overlap rejected.
- TC-SCHED-008: Same technician boundary at end/start accepted.
- TC-SCHED-009: Different technician same time accepted.
- TC-SCHED-010: Invalid email for potential client rejected.
- TC-SCHED-011: Notes over 500 rejected.

### Clients

- TC-CLIENT-001: Client list search works.
- TC-CLIENT-002: Detail page opens for seeded client.
- TC-CLIENT-003: Edit seeded client and save.
- TC-CLIENT-004: New client create with required data.
- TC-CLIENT-005: Missing name rejected.
- TC-CLIENT-006: Invalid email rejected.
- TC-CLIENT-007: Unsupported status rejected.
- TC-CLIENT-008: Edited seeded client does not duplicate.
- TC-CLIENT-009: Malicious HTML in name/address is escaped.

### Jobs

- TC-JOB-001: Jobs list shows demo scale of 20.
- TC-JOB-002: Search HVAC returns expected row.
- TC-JOB-003: Filter by pending returns pending records.
- TC-JOB-004: Detail page opens by id.
- TC-JOB-005: Unknown id returns not found.
- TC-JOB-006: Checklist has expected items.
- TC-JOB-007: Timeline has expected events.
- TC-JOB-008: Financial snapshot displays estimated quote.
- TC-JOB-009: Create job validation accepts valid data.
- TC-JOB-010: Unsupported status/priority rejected.

### Team

- TC-TEAM-001: Team list shows Demo User, Avery Singh, Maya Patel.
- TC-TEAM-002: View member detail opens by email.
- TC-TEAM-003: Edit member opens for owner/manager.
- TC-TEAM-004: Save role/status/phone/email changes.
- TC-TEAM-005: Invalid email rejected.
- TC-TEAM-006: Unsupported role rejected.
- TC-TEAM-007: Unsupported status rejected.
- TC-TEAM-008: View allowed to supervisor/demo_user, edit denied.
- TC-TEAM-009: Edited seeded member does not duplicate.

### Imports and Exports

- TC-IMPORT-001: Default import type is customers.
- TC-IMPORT-002: Each import type shows correct required/recommended/optional fields.
- TC-IMPORT-003: Validation preview accepts complete team headers.
- TC-IMPORT-004: Validation preview reports missing invoice status.
- TC-IMPORT-005: Header aliases normalize correctly.
- TC-IMPORT-006: Unsupported import type fails safely.
- TC-IMPORT-007: Sample CSV downloads for every import type.
- TC-EXPORT-001: Export page shows datasets.
- TC-EXPORT-002: Download clients CSV.
- TC-EXPORT-003: Download jobs CSV.
- TC-EXPORT-004: Download quotes CSV.
- TC-EXPORT-005: Download invoices CSV.
- TC-EXPORT-006: Spreadsheet formula leading characters are neutralised.

### Platform Admin and Billing

- TC-PLAT-001: `/platform-admin` loads only for platform_admin.
- TC-PLAT-002: Navigation includes all 11 sections and no `/admin`.
- TC-PLAT-003: Tenant list opens.
- TC-PLAT-004: Tenant detail tabs render.
- TC-PLAT-005: Suspend requires confirmation and audit.
- TC-PLAT-006: Resume requires confirmation and audit.
- TC-PLAT-007: Extend trial validates 1 to 365 days and audits.
- TC-PLAT-008: Change plan validates plan key and updates MRR.
- TC-PLAT-009: Add grace period validates 1 to 90 days.
- TC-PLAT-010: Mark payment failed sets past_due/high risk.
- TC-PLAT-011: Mark account active sets active/healthy.
- TC-BILL-001: Billing ledger shows contract value, billed-to-date, remaining, next invoice.
- TC-BILL-002: Monthly scheduled invoice is min(monthly price, remaining).
- TC-BILL-003: Annual scheduled invoice is remaining.
- TC-BILL-004: Override next invoice amount validates amount/reason and updates row.
- TC-BILL-005: Pause auto invoice sets next amount zero.
- TC-BILL-006: Resume clears override.
- TC-BILL-007: Platform accounting sandbox links every provider.
- TC-BILL-008: Live platform accounting mode rejected.

### Support Access

- TC-SUPPORT-001: Support login requires platform admin.
- TC-SUPPORT-002: Reason is required.
- TC-SUPPORT-003: Duration must be 15/30/60/120.
- TC-SUPPORT-004: Valid support login switches to tenant owner.
- TC-SUPPORT-005: Banner/history shows reason, tenant, expiry.
- TC-SUPPORT-006: Return restores platform admin.
- TC-SUPPORT-007: Expired session restores platform admin.
- TC-SUPPORT-008: Support login audit event recorded.

### Pricing

- TC-PRICE-001: Basic plan GBP price is zero.
- TC-PRICE-002: Pro plan GBP price is 30 and trial is 30 days.
- TC-PRICE-003: Save valid multi-currency settings.
- TC-PRICE-004: Unsupported default currency rejected.
- TC-PRICE-005: Default currency must be enabled.
- TC-PRICE-006: Empty regions rejected.
- TC-PRICE-007: Discount > 95 rejected.
- TC-PRICE-008: Trial > 365 rejected.
- TC-PRICE-009: Invalid discount date rejected.
- TC-PRICE-010: Public pricing reflects saved settings.
- TC-PRICE-011: Reset restores defaults.

### Integrations and LLM

- TC-ACCT-001: All 10 accounting providers render.
- TC-ACCT-002: QuickBooks supports invoices.
- TC-ACCT-003: SMEPlus does not support payments and requires confirmation.
- TC-CAL-001: Google provider supports push notifications.
- TC-CAL-002: Outlook provider supports change notifications.
- TC-CAL-003: Two-way connection validation accepts valid data.
- TC-CAL-004: Unsupported provider rejected.
- TC-CAL-005: Conflict queued when both FieldOps and provider changed.
- TC-LLM-001: Provider list includes common providers.
- TC-LLM-002: Supported API setup validates.
- TC-LLM-003: Custom endpoint must be HTTPS.
- TC-LLM-004: Secret masking hides middle.
- TC-LLM-005: Import safety rules render.

## Nonfunctional Test Seed

Security:

- XSS in all user-controlled fields.
- CSRF on every POST.
- Tenant isolation when DB persistence is wired.
- Secret masking in LLM/accounting/calendar.
- OAuth/webhook replay/signature when implemented.
- CSV formula injection in imports/exports.

Accessibility:

- Keyboard navigation across sidebar and forms.
- Focus visible on links/buttons/calendar slots.
- Form labels and error messages.
- Icon-only buttons have names/tooltips/aria labels.
- Contrast and status information not color-only.

Responsive:

- 390 x 844 mobile.
- 768 x 1024 tablet.
- 1366 x 768 desktop.
- 1920 x 1080 wide desktop.
- No horizontal overflow and no text overlap.

Performance:

- 10k clients.
- 50k jobs.
- 10k quotes/invoices.
- 50k-row CSV validation preview.
- Dense schedule week with 100+ events.
- Large export memory/time.

