297 lines
14 KiB
Markdown
297 lines
14 KiB
Markdown
# Published Resource Architecture
|
||
|
||
> **Platform-wide abstraction** for anything that can be published publicly.
|
||
> Normative decision: [ADR-022](adr/ADR-022.md)
|
||
> Experience ownership: [ADR-016](adr/ADR-016.md) · Roadmap: [experience-roadmap.md](../experience-roadmap.md)
|
||
> Contracts: [published-resource-contracts.md](../reference/published-resource-contracts.md)
|
||
|
||
**Status:** Accepted · **ARCHITECTURE COMPLETE** (documentation freeze — **no implementation in this patch**).
|
||
|
||
> Final freeze adds: **Published Actions**, **Public Access Model**, **Universal Embed Architecture** (additive, backward compatible).
|
||
|
||
## 1. Purpose
|
||
|
||
TorbatYar products publish many public surfaces (sites, pages, forms, menus, cards, events, …). Without a shared abstraction, each vertical and future product invents its own public identity, URL scheme, and cross-service coupling.
|
||
|
||
**Published Resource** is the official platform abstraction for every present and future public surface. All consumers (Payment, Communication, Short Link, QR, Analytics, CRM, verticals, future products) integrate via **`publish_id` only** — never via Experience (or other) internal tables.
|
||
|
||
## 2. Published Resource
|
||
|
||
A **Published Resource** represents anything that can be published publicly for a tenant.
|
||
|
||
| Field | Meaning |
|
||
| --- | --- |
|
||
| `publish_id` | Stable public identity (UUID). Cross-service foreign key substitute. |
|
||
| `tenant_id` | Owning tenant ([ADR-003](adr/ADR-003.md)) |
|
||
| `resource_type` | Extensible type key (string registry — **not** a closed enum in architecture) |
|
||
| `resource_id` | Owning-service aggregate id (opaque to consumers) |
|
||
| `canonical_url` | Canonical public URL path or absolute URL |
|
||
| `publish_status` | Lifecycle: `draft` · `published` · `unpublished` · `archived` (extensible) |
|
||
| `visibility` | e.g. `public` · `unlisted` · `tenant_only` (extensible) |
|
||
| `owner_service` | Service that owns the aggregate (`experience`, `hospitality`, …) |
|
||
|
||
### Resource type registry (open)
|
||
|
||
Architecture **must not hardcode** a finite type list. Types are registered as string keys. Illustrative examples (non-exhaustive):
|
||
|
||
| Example `resource_type` | Typical owner |
|
||
| --- | --- |
|
||
| `site` | experience |
|
||
| `page` | experience |
|
||
| `landing_page` | experience |
|
||
| `form` | experience |
|
||
| `survey` | experience |
|
||
| `appointment` | experience |
|
||
| `restaurant_menu` | hospitality (surface may publish via Experience) |
|
||
| `product_catalog` | marketplace / ecommerce |
|
||
| `campaign` | experience / marketing consumers |
|
||
| `digital_business_card` | experience / future Torbat Card |
|
||
| `event` | experience / future Torbat Event |
|
||
| `booking_page` | experience / future Torbat Booking |
|
||
| *future.*\* | any registered service |
|
||
|
||
Unlimited future types are allowed without ADR revision when they follow this contract.
|
||
|
||
## 3. Publish Target Registry
|
||
|
||
The **Publish Target Registry** is the logical catalog of all Published Resources.
|
||
|
||
Rules:
|
||
|
||
1. Every publicly reachable surface that other services may attach to **MUST** have a registry entry with a `publish_id`.
|
||
2. Registry entries are **tenant-scoped**.
|
||
3. Consumers resolve and attach using `publish_id` (+ `tenant_id` for isolation checks).
|
||
4. Registry ownership for Experience-authored surfaces is Experience (`experience_db`). Other owner services may publish their own surfaces into the same logical contract (API/events), never by writing Experience tables.
|
||
5. **No implementation in this documentation patch** — schema, API, and migrations are deferred to future registered phases.
|
||
|
||
Logical record:
|
||
|
||
```
|
||
PublishTarget {
|
||
publish_id
|
||
tenant_id
|
||
resource_type
|
||
resource_id
|
||
canonical_url
|
||
publish_status
|
||
visibility
|
||
owner_service
|
||
# optional metadata (locale, title_ref, …) — additive only
|
||
}
|
||
```
|
||
|
||
## 4. Independent Resources
|
||
|
||
The following Experience resource kinds **MUST NOT** require a parent Site or Page to exist or publish:
|
||
|
||
| Resource | Standalone publish | Optional Site binding |
|
||
| --- | --- | --- |
|
||
| **Form** | Required | Allowed |
|
||
| **Survey** | Required | Allowed |
|
||
| **Appointment** (appointment page / booking shell) | Required | Allowed |
|
||
|
||
Rules:
|
||
|
||
1. Forms, Surveys, and Appointments are first-class publishable resources.
|
||
2. They **may** optionally belong to a Site (and/or Page) for composition.
|
||
3. They **must** support standalone publishing with their own `publish_id` and canonical URL.
|
||
4. UI and API designs must not force “create Site → create Page → attach Form” as the only path.
|
||
|
||
Sites and Pages remain publishable resources; independence applies to Form / Survey / Appointment aggregates specifically.
|
||
|
||
## 5. Cross-Service Integration Contracts
|
||
|
||
All integrations are **documentation contracts only** until a registered implementation phase.
|
||
|
||
| Consumer | Attachment | Reference key |
|
||
| --- | --- | --- |
|
||
| Payment (Torbat Pay) | Paid form / appointment / booking / registration / event | `publish_id` |
|
||
| Communication | SMS/email/OTP/notify after submit or booking | `publish_id` |
|
||
| Short Link | Resolve short codes to public surfaces | `publish_id` |
|
||
| QR Code | Encode / resolve posters, tables, cards, events | `publish_id` |
|
||
| Analytics | Pageviews, conversions, funnels | `publish_id` |
|
||
| CRM | Lead capture / contact refs from public surfaces | `publish_id` |
|
||
| Booking | Scheduling refs attached to public bookable surfaces | `publish_id` |
|
||
| Marketplace | Catalog embed / campaign surfaces | `publish_id` |
|
||
| Hospitality | Menu / venue public surfaces | `publish_id` |
|
||
| Delivery | Campaign / logistics announcement surfaces | `publish_id` |
|
||
| Loyalty | Offer / card / campaign surfaces | `publish_id` |
|
||
| Sports Center | Membership / event / booking surfaces | `publish_id` |
|
||
| Future services | Any public attachment | `publish_id` |
|
||
|
||
**Forbidden:** consumers must not query Experience (or other) internal tables, import models, or store foreign primary keys as substitutes for `publish_id` when the public surface is the integration target.
|
||
|
||
Detail: [published-resource-contracts.md](../reference/published-resource-contracts.md).
|
||
|
||
## 6. Standard Public URL Patterns (Reserved)
|
||
|
||
Routing is **not implemented** in this patch. The following path prefixes are **reserved** for public resolution:
|
||
|
||
| Prefix | Intended use (illustrative) |
|
||
| --- | --- |
|
||
| `/s/` | Site / published site shell |
|
||
| `/p/` | Page / landing |
|
||
| `/f/` | Form |
|
||
| `/survey/` | Survey |
|
||
| `/book/` | Appointment / booking page |
|
||
| `/menu/` | Restaurant / digital menu surface |
|
||
| `/card/` | Digital business card |
|
||
| `/event/` | Event surface |
|
||
|
||
Additional prefixes may be reserved later without breaking this architecture. Canonical URLs stored on the Publish Target Registry should align with these patterns when applicable.
|
||
|
||
## 7. Future Products
|
||
|
||
The following commercial products are **architecture-reserved**. They consume Published Resources; they **never own** Experience data:
|
||
|
||
| Product | Role |
|
||
| --- | --- |
|
||
| **Torbat Link** | Short / branded link layer over Published Resources |
|
||
| **Torbat QR** | QR issuance and resolution to `publish_id` |
|
||
| **Torbat Card** | Digital business card surfaces |
|
||
| **Torbat Booking** | Booking UX over appointment / bookable resources |
|
||
| **Torbat Ticket** | Ticketing over event / paid registration resources |
|
||
| **Torbat Event** | Event publishing and discovery |
|
||
| **Torbat Learning** | Learning / knowledge page surfaces |
|
||
|
||
These products integrate through API/Events + `publish_id`. Experience remains owner of page/site/theme/form aggregates it already owns ([ADR-016](adr/ADR-016.md)).
|
||
|
||
## 8. Payment Integration
|
||
|
||
Payment ([ADR-020](adr/ADR-020.md), [ADR-021](adr/ADR-021.md)) **may attach** to any Published Resource.
|
||
|
||
Examples: Paid Form · Paid Appointment · Paid Booking · Paid Registration · Paid Event.
|
||
|
||
Contract: Payment request / checkout session stores **`publish_id`** (and `tenant_id`). Payment must not own Experience aggregates or read `experience_db`.
|
||
|
||
## 9. Communication Integration
|
||
|
||
Communication ([ADR-012](adr/ADR-012.md)) triggers may fire on Published Resource lifecycle or submission events.
|
||
|
||
Examples: SMS after submit · Email after booking · OTP · Notifications · Campaign messages.
|
||
|
||
Contract: templates and dispatches reference **`publish_id`** (plus channel/template keys owned by Communication). Providers remain Communication-owned.
|
||
|
||
## 10. Short Link Integration
|
||
|
||
Short Link ownership is **reserved** as a future/adjacent product capability (e.g. Torbat Link).
|
||
|
||
- Short codes resolve to Published Resources via `publish_id`.
|
||
- No direct dependency on Experience internals.
|
||
- Experience must not embed a competing short-link engine as source of truth.
|
||
|
||
## 11. QR Integration
|
||
|
||
QR codes resolve to Published Resources via `publish_id`.
|
||
|
||
Examples: Restaurant Table · Business Card · Poster · Event · Form · Appointment.
|
||
|
||
QR issuance may live in a future Torbat QR product or vertical adapters; payload always targets the Publish Target Registry.
|
||
|
||
## 12. Analytics
|
||
|
||
Analytics (Experience shells and future platform analytics) record **`publish_id`** for public funnel metrics.
|
||
|
||
- No ownership change: Experience analytics shells remain Experience-owned COUNT/local shells where already defined.
|
||
- Cross-service analytics consumers also key off `publish_id`, not internal page/form table ids.
|
||
|
||
## 13. Ownership & Boundaries
|
||
|
||
| Concern | Owner |
|
||
| --- | --- |
|
||
| Publish Target Registry for Experience-authored surfaces | Experience (`experience`) |
|
||
| Page / site / theme / template / form / survey / appointment shells | Experience |
|
||
| Publishing, presentation, rendering metadata, embed metadata | Experience |
|
||
| Published Action *presentation bindings* | Experience (refs `action_key`) |
|
||
| Published Action *business execution* | Owning service of the action |
|
||
| Public Access Policy metadata | Experience |
|
||
| Authentication / SSO | Identity / Core |
|
||
| Payment capture / ledger | Payment |
|
||
| Membership gates | Loyalty |
|
||
| OTP / messaging | Communication |
|
||
| Menu/item catalog source of truth | Hospitality |
|
||
| Product catalog source of truth | Marketplace / Ecommerce |
|
||
| Media binaries | File Storage |
|
||
| Short Link / QR issuance engines | Reserved products |
|
||
| Public URL edge routing | Platform edge / frontend (reserved patterns) |
|
||
| Builder UI | Frontend ([ADR-002](adr/ADR-002.md)) |
|
||
|
||
All cross-service attachments continue to reference **`publish_id` only**.
|
||
|
||
## 14. Published Actions
|
||
|
||
Every Published Resource may expose **zero or more Actions**. Actions are **service-independent** contracts registered in an open **Action Registry**.
|
||
|
||
| Field | Meaning |
|
||
| --- | --- |
|
||
| `action_key` | Open string key |
|
||
| `display_name` | Label |
|
||
| `owning_service` | Executes business logic |
|
||
| `permission` | Invocation permission |
|
||
| `capability` | Discovery key |
|
||
| `feature_toggle` | Optional enablement |
|
||
| `supported_resource_types` | Open type list |
|
||
|
||
Illustrative keys (not closed): View, Submit, Book, Reserve, Pay, Donate, Register, Download, Open Chat, Send Message, Share, Copy Link, Generate QR, Scan QR, Call, Navigate, Add To Calendar, Automation Trigger, Webhook Trigger, …
|
||
|
||
Future services register new actions **without modifying Experience**. Normative contract: [published-action-registry.md](../reference/published-action-registry.md).
|
||
|
||
## 15. Public Access Model
|
||
|
||
A **Public Access Policy** may compose open strategies, including: Public, Private, Authenticated, Tenant Members, Role Based, Password Protected, OTP Protected, Paid Access, Invitation Only, Signed URL, Temporary Link, Expiration, Rate Limited, Geo Restricted (reserved), and future strategies.
|
||
|
||
| Must not live in Experience | Owner |
|
||
| --- | --- |
|
||
| Authentication | Identity / Core |
|
||
| Payment unlock | Payment |
|
||
| Membership evaluation | Loyalty |
|
||
| OTP delivery | Communication |
|
||
|
||
Normative contract: [public-access-contract.md](../reference/public-access-contract.md).
|
||
|
||
## 16. Universal Embed Architecture
|
||
|
||
Published Resources may embed into external sites/apps. Reserved embed types (open): Iframe, JavaScript SDK, Widget, Popup, Inline, Modal, Floating Button, future types.
|
||
|
||
Embed contracts cover: responsive sizing, security/sandbox, origin validation, permission delegation, token passing, theming inheritance, analytics propagation (`publish_id`).
|
||
|
||
Normative contract: [embed-contract.md](../reference/embed-contract.md).
|
||
|
||
## 17. Capability Discovery (additive, docs only)
|
||
|
||
Future `/capabilities` (or equivalent discovery) MAY advertise:
|
||
|
||
- `published_resources: true`
|
||
- `published_actions: true` (registry available)
|
||
- `public_access_policies: true`
|
||
- `universal_embed: true`
|
||
- Open lists of known `action_key` / `embed_type` / access strategy keys
|
||
|
||
No API change in this patch — discovery additions are reserved for implementation phases.
|
||
|
||
## 18. Architecture Complete
|
||
|
||
With Published Resources, Publish Target Registry, Published Actions, Public Access Model, and Universal Embed Architecture documented and accepted under [ADR-022](adr/ADR-022.md), the **Experience Platform architecture is ARCHITECTURE COMPLETE**.
|
||
|
||
Remaining work is implementation (backend registry/APIs, frontend builders/public shells) in **future registered phases** — not architecture redesign.
|
||
|
||
## 19. Non-Goals (Architecture Patches)
|
||
|
||
- No backend schema, migrations, or APIs
|
||
- No frontend UI, embed SDK, or public routers
|
||
- No Short Link / QR / Card / Booking product implementation
|
||
- No changes to completed Experience phases 11.0–11.10 business code
|
||
- No hardcoded closed enums of resource types, actions, access strategies, or embed types
|
||
|
||
## 20. Related Documents
|
||
|
||
- [ADR-022](adr/ADR-022.md)
|
||
- [Published Resource Contracts](../reference/published-resource-contracts.md)
|
||
- [Published Action Registry](../reference/published-action-registry.md)
|
||
- [Public Access Contract](../reference/public-access-contract.md)
|
||
- [Embed Contract](../reference/embed-contract.md)
|
||
- [Module Boundaries](module-boundaries.md)
|
||
- [Integration Architecture](integration-architecture.md)
|
||
- [Experience Roadmap](../experience-roadmap.md)
|
||
- [Payment Contracts](../reference/payment-contracts.md)
|
||
- [Services Contracts](../reference/services-contracts.md) |