# Phase 17 — Performance, security and data hardening

Phase 17 adds no operational module. It hardens the existing modular monolith across HTTP handling, tenant isolation, persistence, concurrency, caching, exports, logs, and database access.

## Security controls

- Application redirects reject CR/LF injection, protocol-relative targets, relative paths, and external origins.
- Database-backed sessions are regenerated on authentication and revoked when the user agent changes. Cookies remain secure, HTTP-only, SameSite, strict-mode, cookie-only sessions.
- Content Security Policy no longer needs inline styles. HSTS, COOP, CORP, clickjacking, MIME-sniffing, referrer, permissions, and cross-domain-policy headers are emitted.
- Upload paths accept only controlled directory segments. Empty files, unsupported MIME types, and malformed images are rejected; stored files receive mode `0640`.
- The rate limiter fails closed when its protected storage or lock is unavailable.
- Logger context and messages recursively redact passwords, tokens, secrets, authorization/cookie/session values, database credentials, private keys, and sensitive document bodies. Bearer credentials and database URLs embedded in messages are masked.
- Audit events no longer persist raw session identifiers. Audit search uses tenant-scoped, server-side pagination.
- No PHP object serialization is used by the background-job abstraction.

## Data integrity and concurrency

Migration `2026_07_19_000018_harden_integrity_and_performance` adds tenant/date/status/reference/soft-delete indexes for authentication, audits, flights, fleet, maintenance, finance, inventory, documents, and alerts. It adds the missing maintenance-work-order defect foreign key.

Generated-column unique constraints enforce one current aircraft assignment per flight and one current aircraft installation per serialized component.

Transactions and row locks protect expense approvals, vendor and customer payment posting, flight/aircraft assignment, availability approvals, component movements, maintenance completion, stock balances, purchase receipts, and number generation. Existing inventory and numbering locks remain in force.

All schema money and exchange-rate fields were scanned; they remain fixed-scale `DECIMAL`, with no `FLOAT`, `DOUBLE`, or `REAL` columns.

## Performance infrastructure

- Audit search is counted and paginated on the server at 50 records per page.
- A tenant-keyed, lock-safe JSON query cache supports short-lived dashboard summaries and explicit namespace rotation.
- Reusable batch processing and background-job contracts are available without silently dropping work.
- Old application logs can be compressed, checksum-verified, and archived with `php cli logs:archive [days]`. A minimum seven-day age is enforced.
- Existing executive snapshots and utilization summary tables remain the source of cached analytical results.

## Verification

- Full PHP lint: passed.
- Tailwind and Alpine asset build: passed.
- Full application suite: 62 passed, 0 failed.
- Static migration scan: no floating-point database columns.
- Static serialization scan: no PHP serialization calls.
- Static inline-style scan: no inline `style` attributes in server-rendered views.

The Phase 17 migration could not be applied in the development workspace because no reachable MySQL connection was configured. Apply it with `php cli migrate` against the deployment MySQL 8 database after a backup and preflight review of existing active assignment/installation duplicates.
