TASKS-1823 WebManager module
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# Web Manager
|
||||
|
||||
The CMS behind the public website. Editors assemble localized pages from ready-made blocks in the
|
||||
admin panel; the public Next.js site renders what they publish.
|
||||
|
||||
| Part | Source | Owns |
|
||||
| ---------------------- | ------------------------------------------- | -------------------------------------------------------- |
|
||||
| Backend (`WebManager`) | `apps/backend/app/base_modules/WebManager/` | Data, validation, draft/publish transactions, APIs |
|
||||
| Admin (`Web Studio`) | `apps/admin/src/core/WebStudio/` | Editor UI, drafts, publishing actions, preview, settings |
|
||||
| Public site | `apps/web/web-runtime/`, `apps/web/app/` | Server rendering, layouts, blocks, caching, SEO |
|
||||
|
||||
## Documentation
|
||||
|
||||
| Page | Purpose |
|
||||
| ------------------------------- | ------------------------------------------------------------------ |
|
||||
| [Backend](./backend.md) | Data model, HTTP API, query budget, tuning constants. |
|
||||
| [Admin](./admin.md) | Web Studio: routes, editor, config files, UI conventions. |
|
||||
| [Web](./web.md) | Public site rendering, layouts, hero, SEO, degradation. |
|
||||
| [Integration](./integration.md) | Contracts, cross-app flows, caching, env wiring, extending, tests. |
|
||||
|
||||
## For Editors
|
||||
|
||||
A page is a title, an optional hero, an ordered list of blocks, and SEO fields. Blocks are the
|
||||
prebuilt sections — text columns, FAQ, media, banner, article list — so building a page is picking
|
||||
blocks and filling them in, not writing markup.
|
||||
|
||||
| Term | What it means |
|
||||
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Page** | One address in one language, e.g. `/en/about-us`. |
|
||||
| **Group key** | Ties the same page across languages together (`about-us` links `/en/about-us` and `/uk/pro-nas`) so the site can offer a language switch. |
|
||||
| **Page type** | Landing, Blog, or Blog item. Decides the layout and which blocks are offered. |
|
||||
| **Hero** | The opening section. Four intensities: none, low, middle, high. |
|
||||
| **Draft** | Your working copy. Never visible to visitors. |
|
||||
| **Published** | Live on the site. |
|
||||
| **Unpublished** | Taken down, but kept — content, blocks and address stay reserved, so you can put it back. |
|
||||
| **Preview** | A private, time-limited link that renders the draft exactly as the site would. |
|
||||
| **Site settings** | Header menus, footer, and legal links — shared by every page in one language. |
|
||||
|
||||
Everything you edit is a draft. A live page keeps serving the old version until you press Publish,
|
||||
so an unfinished edit can never reach visitors. Nothing is deleted unless you press Delete.
|
||||
|
||||
## Page Lifecycle
|
||||
|
||||
```txt
|
||||
create publish
|
||||
(none) ────────► draft ───────────► published ◄──────┐
|
||||
│ │ │
|
||||
discard│ │unpublish │publish
|
||||
▼ ▼ │
|
||||
deleted unpublished ───────┘
|
||||
|
||||
published + open draft clone: visitors see the published row, the editor edits the clone
|
||||
```
|
||||
|
||||
Every write happens in one transaction with rows locked `FOR UPDATE`; routes and permissions are in [backend.md](./backend.md), purge behavior in [integration.md](./integration.md#caching-and-revalidation).
|
||||
|
||||
- **Create** — `createDraft` validates the payload, asserts the `locale` + `path` is free across every root row (any status), and inserts the page with `status = draft` plus its components. Nothing public yet.
|
||||
- **Save a draft** — `ensureDraft` edits a `draft` or `unpublished` page in place; for a `published` page it reuses or creates the draft clone. Components are replaced wholesale in the submitted order; a clone inherits its original's address.
|
||||
- **Edit a published page** — the clone is a second row with `draft_of_id` pointing at the original (one clone per page, enforced by a partial unique index). Edit always opens the clone; the original keeps serving until the clone is published.
|
||||
- **Preview** — a signed token (HMAC over `APP_KEY`, TTL 900s clamped to 60–3600s) lets the web app render the draft in an iframe sheet: `force-dynamic`, `noindex`, disallowed in robots. Absent, tampered, or expired tokens render "preview unavailable".
|
||||
- **Publish** — publishes the **last saved** draft (the confirmation dialog says so). A pending clone is always preferred, so publishing can never drop the editor's work: a root draft goes live directly; a clone is folded into its original and deleted. A _structural_ change (first publish, republish, or changed locale/path/title/group key/page type) purges the whole cache tag; anything else purges only the affected page tags.
|
||||
- **Unpublish** — same permission as publish; only valid on a published page (else 409). Sets `status = unpublished`, keeping content, components, and any open clone; the address stays reserved. Full purge — the URL now 404s.
|
||||
- **Republish** — publish again; an unpublished page is edited in place, and republishing counts as structural.
|
||||
- **Discard a draft** — deletes the draft row and its components; a clone's original is untouched. No purge.
|
||||
- **Delete** — the only destructive action, behind a confirmation dialog. Components and any open clone cascade with the row; full purge if it was published.
|
||||
Reference in New Issue
Block a user