# Phase 15 — Content and Global Settings Report

## Outcome

Phase 15 is complete. The protected web runtime now implements lifecycle-controlled banners, user-targeted announcements, immutable announcement reads, published tutorials, verified public-media delivery, versioned policy-bound settings, managed links, feature rollouts, validated themes, guarded currency metadata, and maintenance-window administration.

## Delivered components

- Migration `020_harden_content_configuration.sql` adds optimistic versions, updater/publisher attribution, lifecycle checks, a single-active-theme guard, JSON-shape checks, exact permissions, and immutable/archive-only triggers.
- Authenticated public APIs expose only active/published content selected by UTC windows, feature gates, and safe targeting.
- Banner and tutorial media references resolve only verified public records; delivery validates path containment and stored size before serving.
- Announcement reads use the existing composite primary key and `INSERT IGNORE`, so retries are harmless while database triggers preserve evidence.
- Admin content services implement create/update/detail/list and explicit publish/pause/expire/archive transitions with row locks and version conflicts.
- Settings retain each successful next value in immutable `setting_versions` with the Admin's reason.
- Managed URLs use deployment allowlisting, feature flags use a closed client set and percentage rollout, and theme tokens use the existing closed CSS-value schema.
- Currency administration cannot change settlement precision, rounding, or activation after ledger setup.
- Maintenance schedules use ordered UTC ranges, explicit transitions, cache invalidation, and existing middleware exemptions.

## Security invariants

- Raw HTML is not accepted as authoritative content; server-generated HTML escapes all Admin text.
- Client payloads cannot select public status, publish timestamps, read counts, internal IDs, media paths, or configuration versions.
- Public content queries require correct lifecycle/time state, and public media requires both verified status and public scope.
- No content delete route exists; database triggers enforce archive-only retention.
- Exact Admin permissions separate reads, edits, publishing, link/flag changes, themes, currencies, settings, and maintenance.
- Admin mutations retain IP allowlisting, authenticated sessions, CSRF, rate limits, strict schemas, optimistic versions, transactions where state is coupled, and audit evidence.
- Redis caches are used only for non-authoritative public projections and are invalidated after relevant Admin writes. Announcement read state remains directly database-backed for freshness.

## Verification

Phase 15 adds **32 focused tests** across unit, integration, and security suites. They cover safe HTML, strict content schemas, targeting, feature short-circuiting, media verification/path containment, server-selected scheduled state, URL policy, setting versions and stored types, free-only invariants, theme validation and activation, settlement currency guards, CSRF, authentication, permission separation, SQL parameterization, and migration protections.

The full suite contains **294 tests** after the Phase 15 additions. The database verifier confirms **20 migrations, 6 seeds, 72 domain tables, 211 named foreign/check constraints, 153 up statements, 141 down statements, and 19 seed statements**.

## Operational boundary

All migration and runtime verification was offline or used test doubles. No deployment `.env`, live MySQL instance, Telegram environment, public domain, or real media store was accessed. Operators must perform the documented staging preflight before applying migration `020`.

## Next phase

Phase 16 will implement Telegram notifications and reminders: templates, transactional outbox delivery, retry-safe jobs, schedules, broadcasts, and delivery reporting.

**Phase 15 status: COMPLETE — focused tests 32/32; full quality gate passed 294/294.**
