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