# App-Overlays — freshvibe-cms (the customisation layer)

**Locked 2026-08-04 as part of a452 Phase 6 (App-Overlays).**
**Per FWV v8 §02.1.6 — customisations compose over the base app without modifying it.**

App-Overlays are how freshvibe-cms gets customised per-deployment, per-tenant, or per-environment **without modifying the base package**. An overlay can:

- Add new panels or blocks
- Override existing panel/block behaviour
- Add new content types
- Change the chrome's look/feel via skins
- Inject custom AI prompts or behaviours
- Add per-deployment configuration (API keys, feature flags)

The base package stays untouched. The overlay is a separate folder that the host application can include or exclude per-deploy.

## Why overlays exist

Without overlays, every customisation would either:
- Pollute the base package (drift)
- Require a fork (maintenance burden)

Overlays give us a third option: **compose without forking**. The base package stays at v0.X.0, the overlay is at its own version, and the deployed app is `base + overlay` rendered together.

## The 2 starter overlays (Phase 6 scope)

Phase 6 ships with **2 overlay stubs** as proof-of-concept. Each shows the overlay pattern without committing to a specific customisation.

### 1. `fvcms-watermark-hider/`

**Purpose:** Hides the Oscar watermark in the chrome when not needed (some sites want it visible, some don't).

**Type:** Behaviour override

**Files:**
- `overlay.json` — manifest declaring: name, version, base_version, hooks_used, files
- `fvcms-watermark-hider.js` — the actual override code

**Hook points used:** `chrome.mount:post` (runs after chrome.mount completes)

**How it works:** listens for chrome.mount completion, finds the Oscar watermark element in the DOM, hides it (or shows it, based on configuration).

### 2. `fvcms-extended-blocks/`

**Purpose:** Adds 3 extra blocks (gallery, video-carousel, comparison-table) that aren't in the base 16.

**Type:** Content addition

**Files:**
- `overlay.json` — manifest
- `modules/gallery.js` — the new gallery block
- `modules/video-carousel.js` — the new video carousel block
- `modules/comparison-table.js` — the new comparison table block

**Hook points used:** `modules.register:post` (registers new blocks after the base 16)

**How it works:** the host page can opt-in to these extra blocks by including the overlay's `index.js` after the base package.

## How overlays are structured (per FWV v8 §02.1.6)

Each overlay follows the same shape:

```
app-overlays/<name>/
├── overlay.json     # manifest (name, version, base_version, hooks, files)
├── README.md        # human-readable description
├── index.js         # entry point that registers the overlay
└── <files>          # the actual code (panels, blocks, hooks, etc.)
```

The `overlay.json` is the contract — it declares what hooks the overlay uses, which files it adds, and which base_version it requires.

## The hook system

Overlays communicate with the base via **hooks** — named events the base emits, overlays can subscribe to. Common hooks:

- `chrome.mount:post` — runs after chrome.mount
- `chrome.unmount:pre` — runs before chrome.unmount
- `modules.register:post` — runs after the base modules are registered
- `panels.register:post` — runs after the base panels are registered
- `content-types.register:post` — runs after the base content types are registered
- `store.ready:post` — runs after the store is initialised
- `block.render:pre` — runs before any block renders
- `block.render:post` — runs after any block renders
- `region.add:pre` / `region.add:post` — runs before/after a region is added
- `region.remove:pre` / `region.remove:post` — runs before/after a region is removed

The full hook catalog is in `app-overlays/HOOKS.md` (created in Phase 7 when the App-VP tests need to verify overlay behaviour).

## The deployment model

A freshvibe-cms deployment is `base + N overlays`:

```html
<!-- base -->
<script src="/freshvibe-cms/bootstrap.js"></script>

<!-- overlays (optional) -->
<script src="/overlays/fvcms-watermark-hider/index.js"></script>
<script src="/overlays/fvcms-extended-blocks/index.js"></script>

<!-- host page annotation -->
<script type="application/json" data-fv-annotation>
  { "regions": [...], "content": {...} }
</script>
```

The base package is identical across deployments. The overlays are per-deployment.

## What overlays are NOT

- **Not a fork** — overlays compose with the base, they don't replace it
- **Not a plugin system** — overlays are first-party code, not third-party
- **Not runtime-loaded** — overlays are bundled with the deployment, not downloaded at runtime
- **Not per-user customisation** — overlays are per-deployment, not per-user

For per-user customisation, use the per-site content store (`runtime/content-items/store.js`).

## See also

- `app-pact/vendored/fvw-v8/02-folder-layout.md` §2.1.6 — the FWV v8 doctrine
- `app-pact/dna/app.dna.json` — the package DNA (extension_points lists where overlays attach)
- `app-pact/app-pact.md` — the Constitution (the §3.7 "panels have one owner" rule applies to overlays too)

## History

- 2026-08-04: Created as part of Phase 6 of plan a452 (FWV v8.3 alignment)
- 2 starter overlays: `fvcms-watermark-hider` and `fvcms-extended-blocks`
