The reference table for compliance filing. Every control below predates v2 and was carried through it unchanged; the only v2-adjacent movement is the role model, which expanded within the existing RBAC framework (noted in 5.2).
| Domain | Control | Implementation |
|---|---|---|
| Authentication | Passwordless OTP (primary) + password (alternative) | Cryptographically random 6-digit OTP, 5-minute TTL, 3-attempt lockout with 60s cooldown, response shaped to prevent account enumeration; passwords hashed with bcrypt (cost 10). |
| Session management | Short-lived signed tokens, no refresh | JWT (HS256, server-side secret), 12-hour TTL, stored in per-tab sessionStorage; users re-authenticate on expiry; token carries user, role, franchise and environment context. |
| Authorization | Role-based access control + route guards | Role model enforced by middleware guards on every route; role normalization on input; v1 shipped four roles, v2 six (see 5.2). |
| Data-level access | Franchise-scoped filtering | Store visibility filtered by the user’s franchise assignments (MSF-code matching) as parameterized SQL WHERE clauses — applied to every data query, independent of UI. |
| Injection defense | 100% parameterized SQL | Every database query is fully parameterized — zero string-built SQL — and independently audited against injection; comprehensive input sanitization on all request payloads. |
| Web hardening | Security headers + controlled CORS | Enforced security headers on every response; CORS origins controlled per environment via configuration, never wildcarded in production. |
| Upload security | Whitelist + verification + hard limits | Strict file-type whitelisting with MIME verification (extension alone is not trusted); hard limits of 300 MB and 1M rows per upload. |
| Encryption in transit | TLS 1.2+ everywhere | HTTPS for browser→app and browser→API; TLS to database, SMTP, and S3. |
| Encryption at rest | AWS-managed encryption | Aurora automatic encryption (AWS KMS); uploads/exports in S3 with SSE-S3. |
| Secrets management | Environment configuration, never code | Secrets injected via environment at deployment; deployment checklist mandates strong per-environment JWT_SECRET; committed env files hold template values only. |
| Data residency | Single AWS region | All compute and data in one AWS region (single AZ); no cross-region replication by design. |
| PII handling | Minimal by design + full log masking | The system processes business planning data, not consumer PII; user records hold business contact fields (name, work email, phone). Logs automatically mask sensitive data: passwords, tokens, and OTPs fully redacted; PII partially masked to remain traceable without exposure; error responses and diagnostics sanitized against information leakage. |
| Audit & logging | Structured logs with correlation IDs | Application/error/access logs retained 30 days with automated archival to S3 under lifecycle policies, supporting audit and compliance needs; cell-level audit metadata (who changed what and when) kept indefinitely inline in the database across all planning data; database-level audit logs not enabled (see 5.3). |
| Backups | Platform-managed | Aurora automated backups with configurable retention; recovery relies on AWS-managed features per the NFR baseline. |
| Environment isolation | Schema-per-environment | Seasonal environments isolated at the database-schema level; connection search-path is set per request and reset on release to prevent cross-environment access. |
v2 changed the data model, the UI, and the role model — the three places where a release of this shape could regress security. The bundled test log records 150+ security and privacy test cases passing post-v2 (itemized by category in Section 4.2 of the Code Quality page); the rows below map them to the specific questions v2 raises:
| Question v2 raises | Status | Evidence |
|---|---|---|
| Does the new 4th hierarchy level open an access-control gap? | VERIFIED BY DESIGN + TESTS | Authorization is franchise/store-scoped, not hierarchy-level-scoped — the Platform level inherits the same route guards and SQL filters as existing levels. The passing suite (log) exercises this directly: store access allowed within the user’s franchise, denied outside it with a 404 (anti-enumeration), 403 when no franchise is configured, explicit admin/superadmin bypass tests, and access grants/denials logged — plus platform-level planning integration tests. |
| Was the role-model expansion (4 → 6 roles) done safely? | TESTED | Roles remain enforced by the same guard framework: the log shows per-endpoint role checks on the new v2 admin endpoints (dashboard summary, franchisee list, and store drill-down each require ADMIN/SUPERADMIN; FRANCHISE_MANAGER, LEVIS_MANAGER, and VIEWER explicitly rejected), invalid role names (SUPERUSER, ROOT, GUEST…) rejected with case normalization, and privilege escalation via token manipulation blocked. The expansion also fixed two v1 auth gaps: standard-user login and the non-functional change-password flow. |
| Any new code-level security findings after the v2 changes? | CLEAN | Post-v2 SonarQube analysis: 0 security issues, 0 security hotspots, rating A (dashboard). |
| Does the security test baseline still hold? | TESTED | Security testing aligned to the OWASP Top 10 — 0 critical/high findings (internal assessment; independent penetration test was out of scope): all 10 categories pass, including broken access control (5 tests), injection (6), and auth failures (5); plus targeted suites — OTP rate limiting (11), SQL parameterization (7), CORS/headers (11), upload security (30+). |
| Dependency CVE status? | CLEAN | npm audit records 0 critical / 0 high vulnerabilities (OWASP A06 record). |
| Secrets exposure? | NO FINDINGS | Deployment checklist enforces environment-based secrets; committed env files are template-only; no credentials in source. |
| Does the new UI or logging expose personal data? | TESTED | The new admin dashboard and user directory display business contact data (work email, login recency) and are role-gated to admin routes. Passing tests verify: password hashes never appear in API responses; the user bulk-upload CSV excludes password columns and values; onboarding passwords are shown once and excluded from result DTOs; error messages sanitize credential patterns; audit logs record failures without passwords and with obfuscated emails (t***t@e***e.c***m). The new exports table stores job metadata (storage key, status, expiry), not file contents. |