TorbatYar/docs/architecture/published-resource-architecture.md
2026-07-28 20:39:10 +03:30

297 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.011.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)