# Legacy Public Website & CMS Retirement Audit (Phase 12)

## Phase 13 controlled removal outcome

Phase 13 retired the legacy Website/CMS runtime without deleting its historical database tables, records, or asset tree. The legacy models, enums, factories, controllers, services, routes, admin pages, public renderer and default seeder are removed. The `operator_websites`, `operator_website_themes`, `website_pages`, `website_sections`, and `website_section_revisions` tables remain historical data until a separately approved data-retention migration.

The Sites platform is now the sole public Website renderer and quotation entry point. Unknown hosts and former `/{operator}` legacy paths return 404 rather than falling back to the retired renderer. Sites-managed assets live under `/assets/sites/takaful-online/`; the old Website CMS asset tree is intentionally retained.

**Date:** 25 August 2026
**Original Phase 12 scope:** Audit and retirement plan only. Phase 13 implementation outcome is recorded above.

## Decision

The legacy operator-centric Website CMS can be retired in a controlled Phase 13. It is still a functioning, parallel public renderer for nine operators, so it must not be deleted as a simple file cleanup. The safe boundary is clear: retire the legacy presentation, CMS management and legacy public URLs only after replacing the few useful public-route and abuse-protection contracts with Sites/Core coverage. Keep the canonical quotation, quality, approval, distribution, attribution and credit pipeline intact.

`TakafulOperator` is **not** legacy CMS. It is the Core operator identity and is used by registration, agents, queues, quotation, Premium Approval and Sites. `Takaful.Online` is a Sites Website (`takaful_online`, `takaful.online`) and is currently **Draft**.

## 1. Legacy graph and runtime inventory

| Legacy model / table | Relationships and active callers | Sites dependency | Phase 13 recommendation |
| --- | --- | --- | --- |
| `OperatorWebsite` / `operator_websites` | One per `TakafulOperator`; owns `theme` and `pages`. Read by `PublicOperatorWebsiteService`, `AdminWebsiteSettingService`, preview and asset services. | None. | Deprecate then remove model/runtime use; retain table initially. |
| `OperatorWebsiteTheme` / `operator_website_themes` | One per legacy website; legacy theme editor and public renderer read it. | None. Sites uses `SitesOperatorTheme` plus `config/sites_operators.php`. | Deprecate then remove. |
| `WebsitePage` / `website_pages` | Legacy page type and enabled state; owns ordered sections. | None. | Deprecate then remove. |
| `WebsiteSection` / `website_sections` | Legacy section schema, draft/publish controls and revisions. | None. `SitesWebsiteSection` is a separate model/table. | Deprecate then remove. |
| `WebsiteSectionRevision` / `website_section_revisions` | Localised CMS draft/published/archived content history. | None. | Preserve temporarily, then future drop with its parent graph. |
| `TakafulOperator` / `takaful_operators` | Core global identity; agent assignment, queue resolution, quotation source, public operator selection and Sites variants. It retains a legacy `operatorWebsite()` relation only. | Required. | **KEEP**; only remove the legacy relation after all legacy callers are gone. |

Related legacy enums are `WebsitePageType`, `WebsiteSectionType` and `WebsiteSectionRevisionStatus`. Related services are `AdminWebsiteSettingService`, `OperatorWebsiteThemeService`, `PublicOperatorWebsiteService`, `WebsiteCmsAssetService`, `WebsiteCmsSchemaService`, `WebsiteDraftPreviewService`, `WebsiteSectionDraftService`, `WebsiteSectionPublishService`, `WebsiteSectionRevisionHistoryService` and `WebsiteSectionRollbackService`.

Legacy controllers are `Admin\\WebsiteSettingController`, `Admin\\OperatorWebsiteThemeController`, `Admin\\WebsiteCmsAssetController`, `Admin\\WebsiteDraftPreviewController`, `Admin\\WebsiteSectionDraftController`, `Admin\\WebsiteSectionPublishController`, `Admin\\WebsiteSectionRevisionHistoryController`, `Admin\\WebsiteSectionRollbackController`, `PublicOperatorWebsiteController`, the legacy `PublicQuotationController`, and `PublicContactController` for the old operator contact form.

There are no legacy CMS jobs or scheduled commands. `routes/console.php` only schedules `leads:process-reminders`.

## 2. Local database inventory and classification

The local database was read on 25 August 2026. It contains 9 legacy websites/themes, 45 pages, 198 sections and 191 section revisions. The nine legacy operator slugs are `aia`, `pru`, `get`, `et`, `ti`, `hlmt`, `zt`, `fwd` and `slt`.

| Table | Local rows | Foreign keys / dependencies | Classification | Data-preservation decision |
| --- | ---: | --- | --- | --- |
| `takaful_operators` | 9 | Referenced by users, lead assignments, queues, approvals, legacy CMS and Sites variants. | **KEEP** | Core authoritative data. |
| `operator_websites` | 9 | FK `takaful_operator_id` (unique, cascade). Parent of theme/pages. | **DEPRECATE** now; **FUTURE DROP** candidate. | Export/backup rows before a later destructive phase. |
| `operator_website_themes` | 9 | FK `operator_website_id` (unique, cascade). | **DEPRECATE** now; **FUTURE DROP** candidate. | Preserve palettes/logo paths for audit only; Sites palettes are already independent. |
| `website_pages` | 45 | FK `operator_website_id` (cascade); unique page type per website. | **DEPRECATE** now; **FUTURE DROP** candidate. | Retain content map until legacy URL/SEO sign-off. |
| `website_sections` | 198 | FK `website_page_id` (cascade); parent of revisions. | **DEPRECATE** now; **FUTURE DROP** candidate. | Retain as historical content/reference. |
| `website_section_revisions` | 191 | FK section (cascade), optional creator user (null-on-delete); revision indexes. | **DEPRECATE** now; **FUTURE DROP** candidate. | Export published revisions before later table drop. |
| `sites_websites` | 1 | New Sites registry. | **KEEP** | `takaful_online` is the intended platform. |
| `sites_website_operators` | 4 | New Website-to-operator variants/main operator. | **KEEP** | New `/aia`, `/ge`, `/pru` mapping. |
| `lead_attributions` | 0 | New immutable Website/landing/UTM snapshot records. | **KEEP** | New Sites/Core attribution; unrelated to legacy CMS. |

No automatic content migration is recommended. The old CMS is operator-centric while Sites allows a Website with multiple operator variants and deliberately different structured content. Preserve/export only for historical recovery, legal/SEO review or a specifically approved copy operation.

## 3. Legacy administration UI to retire in Phase 13

The following authenticated-admin UI is legacy-only and should disappear from TakafulHub Admin after replacement tests exist:

* Desktop legacy navigation in `resources/js/Layouts/AuthenticatedLayout.vue`: **Website Setting**.
* Responsive legacy navigation in the same layout: **Website Setting**.
* Desktop and mobile sidebar **Website → Website Settings** entries in the same layout.
* `resources/js/Components/Navigation/AdminNavigation.vue`: **Website → Website Settings**.
* Pages `resources/js/Pages/Admin/WebsiteSettings/Index.vue`, `EditTheme.vue`, `EditSection.vue` and `Revisions.vue`.

Exact routes (all inside the existing authenticated admin group) are:

* `GET /website-settings`
* `POST /website-settings/assets`
* `GET /website-settings/{operatorWebsite}`
* `GET|PUT /website-settings/{operatorWebsite}/theme[/edit]`
* `GET /website-settings/{operatorWebsite}/{pageType}`
* `GET /website-settings/{operatorWebsite}/{pageType}/preview`
* `GET /website-settings/sections/{websiteSection}/edit`
* `PUT /website-settings/sections/{websiteSection}/draft`
* `POST /website-settings/sections/{websiteSection}/publish`
* `GET /website-settings/sections/{websiteSection}/revisions`
* `POST /website-settings/sections/{websiteSection}/revisions/{revision}/rollback`

The management replacement is `sites.takafulhub.io`: Website Registry, identity, typography, operator variants/themes, marketing, global legal, sections, campaign popups, social proof, Domain Health, Launch Readiness and Reports. These Sites routes/components are not retirement targets.

## 4. Legacy public rendering and route interaction

### Full request trace

The legacy flow is:

```text
unknown/non-Sites host
  -> routes/sites_public.php GET /{operator}
  -> Sites\PublicWebsiteController::showVariant()
  -> no resolved SitesWebsite
  -> PublicOperatorWebsiteController::show()
  -> PublicOperatorWebsiteService
  -> TakafulOperator -> active OperatorWebsite -> legacy theme/pages/sections
     -> published WebsiteSectionRevision for default locale
  -> Inertia Public/OperatorHome|OperatorHibah|OperatorMedicalCard|
     OperatorContact|OperatorCmsPage
```

`routes/public.php` separately owns the longer legacy paths, all under `sites.public.website` middleware:

* `GET|POST /{operator}/quotation`, `GET /{operator}/quotation/thanks`
* `GET /{operator}/privacy-policy`, `/terms-and-conditions`, `/data-deletion`
* `GET /{operator}/hibah`, `/medicalcard`, `/contact`; `POST /{operator}/contact`

The Sites routes are registered first. The legacy home route is therefore the fallback inside `Sites\\PublicWebsiteController::showVariant()` rather than a route in `routes/public.php`. This is a key Phase 13 removal point.

On a registered Sites host, `ResolveSitesPublicWebsite` blocks every controller except the Sites public Website, quotation and legal controllers. This protects a registered domain from being served by the old renderer. On unknown hosts, the portal fallback remains TakafulHub and the old operator routes can still render. Removing the old fallback and legacy wildcard paths will simplify host isolation, but Phase 13 must retain the existing deliberate unknown-host TakafulHub home fallback unless a separately approved policy changes it.

`sites.takafulhub.io` management routes are host-scoped and use `portal.sites`; VastPro routes use their own portal middleware. Neither portal depends on the legacy CMS.

## 5. Quotation, Core and attribution boundary

Legacy quotation **presentation** is `Public/OperatorQuotation` and its GET endpoint requires legacy `quotation` CMS content. Its POST endpoint validates through `QuotationSubmissionRequest`, resolves the source `TakafulOperator`, then calls the canonical `QuotationSubmissionService`. The legacy controller redirects to its legacy thank-you page. The presentation boundary ends immediately before `QuotationSubmissionService::submit()`.

Sites quotation is independent:

```text
Sites/Public/Show + SitesQuotationForm
  -> POST /quotation (Sites\PublicQuotationController)
  -> SitesQuotationContextToken + SitesOperatorContextResolver
  -> SitesLeadAttributionService snapshot
  -> QuotationSubmissionService
  -> quality / quarantine or operational creation
  -> distribution + social proof
```

No replacement distribution engine is needed for Phase 13. The following must survive unchanged:

* `QuotationSubmissionService` and `QuotationSubmissionRequest`
* `OperationalQuotationSubmissionService`
* `App\\Services\\LeadQuality\\LeadQualityService`
* `LeadDistributionService` and `LeadDistributionQueueResolver` (including GETB queue selection)
* `SameDayAssignmentReuseService`
* `CreditWalletService` and Lead Credits behaviour
* `PremiumLeadApprovalService`, `PremiumLeadApprovalApprovalService` and `PremiumLeadApprovalRejectionService`
* `SitesLeadAttributionService`, `LeadAttribution`, immutable approval attribution snapshots and `SitesSocialProofService`

Premium Approval has no legacy CMS dependency. Sites attribution is persisted on normal submissions and on the approval snapshot before an approved lead becomes a quotation; this must remain. Admin attribution visibility remains a new Core/Sites integration. Agent and VastPro agent views must continue to hide Website source information.

The current legacy POST quotation route also carries `throttle:quotation-submission`; validation, quality screening and rate limiting must be retained by equivalent canonical/Sites coverage before the route is removed. The legacy contact form is a separate `PublicContactInquiry` workflow and needs an explicit product decision/redirect or retirement confirmation; it is not a replacement quotation channel.

## 6. Themes, configuration, seeders and assets

### Authority

`OperatorWebsiteTheme` is legacy-only. The authoritative Sites themes are DB-first `SitesOperatorTheme`, with `config/sites_operators.php` as presentation fallback. The config intentionally has no runtime dependency on the legacy CMS, although its initial values were verified from legacy palettes. The new Sites main/operator relationship is `SitesWebsite -> SitesWebsiteOperator`; do not use legacy `operator_websites` to infer a Sites main operator.

`config/website_cms.php`, `WebsiteCmsSchemaService`, `WebsiteCmsDefaults.php` and `WebsiteCmsDefaultSeeder` are legacy-only. `DatabaseSeeder` currently calls the legacy seeder before `TakafulOnlinePilotSeeder`; Phase 13 must remove that call only after legacy route/model/test removal is complete. No environment variable is dedicated to this CMS.

Legacy `/get` uses Core operator slug `get`. New Sites correctly publishes Great Eastern as `/ge` (the pilot has tests rejecting `/get`). A Phase 13 redirect decision must not silently change the new `/ge` contract.

### Asset classification

| Family | Classification | Reason / Phase 13 action |
| --- | --- | --- |
| `public/assets/website-cms/takaful-online/{hero,hibah,medical-card,why-us-default}.(png|webp)` | **MIGRATE / COPY BEFORE RETIREMENT** | Directly configured by `TakafulOnlinePilotSeeder`; `why-us-default.webp` is also referenced by `SitesOperatorBandSection.vue`. Move/copy to a Sites-owned asset namespace, update only the new Sites references, then verify before removing the legacy asset tree. |
| `public/assets/website-cms/takaful-online/why-us.png` | **UNKNOWN** | Present but not found in current runtime references; retain pending asset audit. |
| Generic `public/assets/website-cms/*.jpg` | **DELETE LATER** | Referenced only by legacy default CMS content/seeder/tests. Retain until legacy content archive and final production/SEO review. |
| `storage/app/public/website-cms/{operator-slug}/{context}` uploads exposed as `/storage/website-cms/...` | **UNKNOWN** | Owned by the legacy upload service. Inventory production objects and active published revision references before archival/deletion. Do not delete in Phase 13 initial pass. |
| `public/assets/operators/*-512.png` | **KEEP** | Used by Sites config/default operator presentation and legacy; shared assets survive. |

## 7. Tests and documentation

### Remove or replace in Phase 13

* Remove legacy CMS-only tests: `OperatorWebsiteThemeTest`, `WebsiteCmsAssetTest`, `WebsiteCmsDefaultSeederTest`, `WebsiteCmsFoundationTest`, `WebsiteDraftPreviewTest`, `WebsiteSectionDraftTest`, `WebsiteSectionPublishTest`, `WebsiteSectionRollbackTest`, `PublicOperatorLegalPageTest` and `OperatorLandingParityTest`.
* Replace the legacy-public portions of `FoundationTest`, `ReleaseCandidateAuthorizationAuditTest`, `ReleaseCandidateContentInjectionAuditTest` and `ReleaseCandidatePerformanceAuditTest` with Sites/Core equivalents. Do not discard their security, authorisation, injection or performance intent merely because their fixtures are legacy.
* Migrate quotation route tests that currently post to `public.operators.quotation.store` (`PublicAbuseProtectionTest`, `PremiumLeadApprovalGateEndToEndTest` and any equivalent regression) to canonical service-level and/or Sites `POST /quotation` coverage before deleting the old endpoint.

### Keep

* Sites tests such as `SitesPublicRoutingTest`, `SitesWebsiteRendererTest`, `TakafulOnlinePilotTest`, Sites registry/settings/legal/domain/reporting tests and attribution tests.
* Core quotation, quality, abuse, Premium Approval, same-day reuse, lead distribution, GETB/VastPro and Lead Credit tests once decoupled from legacy route fixtures.

`docs/website-cms-architecture.md` and `docs/operator-landing-parity-audit.md` should receive a deprecation/archive note in Phase 13, not be silently deleted. This document is the Phase 12 retirement record.

## 8. Existing legacy public surface, redirects and SEO

The local CMS has active data for all nine legacy operators. Local database records do not prove production traffic, so treat all nine paths as potentially live until production logs, DNS/host configuration, analytics and advertising landing URLs are reviewed. The only registered local Sites Website is Draft `takaful.online`; it cannot currently be a public replacement for live traffic.

Potential legacy indexed/ad URLs include:

* `/{aia|pru|get|et|ti|hlmt|zt|fwd|slt}`
* the corresponding `/hibah`, `/medicalcard`, `/quotation`, `/quotation/thanks`, `/contact`, `/privacy-policy`, `/terms-and-conditions` and `/data-deletion` paths.

Before retiring each domain/path, decide one of: 301 to an equivalent live Sites URL, retain temporarily, or return an intentional 410/404. Great Eastern requires a specific `/{domain}/get -> /ge` mapping only when the target Website has a published `ge` variant; never make `/get` a new Sites canonical URL. Preserve URL query parameters/UTM values through any approved redirect. Review Google Ads, Meta, inbound links, sitemap/canonical tags and legal links outside the repository before removal.

## 9. Phase 13 controlled removal sequence

1. Freeze legacy CMS feature work and record owners/traffic/SEO decisions for every legacy host/path.
2. Add replacement Sites/Core tests for public quotation validation/throttling, suspicious-lead quarantine, distribution, same-day reuse, attribution, GETB/VastPro and agent-source privacy. Confirm Sites legal, contact-product decision and host isolation.
3. Migrate/copy the four Takaful.Online assets to a Sites-owned namespace and verify public rendering; inventory and archive legacy storage uploads and published content exports.
4. Release and verify any approved redirects while legacy routes still exist; do not redirect a Draft/non-live Sites Website.
5. Remove TakafulHub Admin legacy navigation, pages and the `/website-settings` route/controller/service/upload stack in one isolated change.
6. Remove the legacy public renderer: `PublicOperatorWebsiteService`, `PublicOperatorWebsiteController`, legacy public Vue pages/layout, longer wildcard routes and the `PublicWebsiteController::showVariant()` null-website fallback. Retire the legacy quotation and thank-you route only after replacement contracts are green.
7. Remove legacy models, enums, factories, `WebsiteCmsDefaultSeeder`, default data, config and legacy-specific tests; remove the `TakafulOperator::operatorWebsite()` relation last.
8. Keep legacy tables and uploaded assets intact for a production validation window. Run full route, Core, Sites, security and build regressions.
9. In a separate, later destructive cleanup phase, archive exports/backups, remove old assets/storage only after reference scans, then add a dedicated migration that drops the five legacy tables in dependency order.

## 10. Rollback and destructive-cleanup policy

Phase 13 should be one isolated, reversible commit/deployment. Do not alter or drop legacy tables/migrations/storage assets in that phase. Maintain an export of all five legacy table datasets and an object listing/checksum for `storage/website-cms`. If a hidden production dependency appears, roll back the code deployment and re-enable the retained routes/controllers; no database restore should be needed.

Database drop belongs to a later dedicated cleanup after a measured production validation period, traffic/SEO/Ads cut-over sign-off and a final dependency scan. Use the dependency order `website_section_revisions`, `website_sections`, `website_pages`, `operator_website_themes`, `operator_websites`; retain `takaful_operators`.

## Files reviewed

Important audited files include:

* `routes/public.php`, `routes/sites_public.php`, `routes/sites.php`, `routes/admin.php`, `routes/console.php`
* `app/Http/Middleware/ResolveSitesPublicWebsite.php`, `app/Http/Controllers/Sites/PublicWebsiteController.php`, `app/Http/Controllers/Sites/PublicQuotationController.php`
* `app/Http/Controllers/PublicOperatorWebsiteController.php`, `app/Http/Controllers/PublicQuotationController.php`, `app/Http/Controllers/PublicContactController.php`
* `app/Models/{TakafulOperator,OperatorWebsite,OperatorWebsiteTheme,WebsitePage,WebsiteSection,WebsiteSectionRevision,SitesWebsite,SitesWebsiteSection,SitesWebsiteOperator,SitesOperatorTheme,LeadAttribution}.php`
* legacy and Sites services named in this report, especially `QuotationSubmissionService` and `SitesOperatorContextResolver`
* `database/migrations/2026_08_18_000019_create_website_cms_tables.php`, `database/seeders/{DatabaseSeeder,WebsiteCmsDefaultSeeder,TakafulOnlinePilotSeeder}.php`, `database/seeders/data/WebsiteCmsDefaults.php`
* `config/website_cms.php`, `config/sites_operators.php`, `config/portals.php`
* legacy Admin/Public Vue pages and `resources/js/Components/PublicOperatorLayout.vue`; Sites public components including `SitesOperatorBandSection.vue`
* legacy CMS tests, Sites routing/renderer tests, public abuse tests, Premium Approval end-to-end tests and release-candidate audits.

## Verification

* This Phase 12 audit added this documentation file only; it made no runtime, route, migration, database, storage or public-behaviour change.
* Local database inspection confirms `takaful_online | takaful.online | draft`.
* Run `git diff --check` after staging/review of this documentation file as part of handoff. The surrounding parent worktree has pre-existing unrelated modifications and untracked projects; do not treat those as Phase 12 changes.
