diff --git a/docs/backend/PHASE-10-CONTENT-MODULES-CONTRACT.md b/docs/backend/PHASE-10-CONTENT-MODULES-CONTRACT.md new file mode 100644 index 0000000..8526ec9 --- /dev/null +++ b/docs/backend/PHASE-10-CONTENT-MODULES-CONTRACT.md @@ -0,0 +1,118 @@ +# Phase 10 Backend Contract — Tenant Content Modules (Gorbushka-class tenants) + +Companion to [PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md](../PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md) Phase 10 (Sprints 10.1–10.2). Covers plan §11. + +**Status: ready to build, lowest priority.** Only after Commerce Core (Phases 1–7) is real — the plan is explicit that this tenant type does not define the platform architecture; it is one configuration of the shared runtime, not a separate build. + +--- + +## 1. Entities + +```ts +interface Shop { + id: string; + marketplaceId: string; + shopCategoryId: string; + name: string; + floorId?: string; + status: 'draft' | 'published'; +} + +interface ShopCategory { + id: string; + marketplaceId: string; + title: string; +} + +interface Service { + id: string; + marketplaceId: string; + title: string; + description: string; + status: 'draft' | 'published'; +} + +interface Floor { + id: string; + marketplaceId: string; + order: number; + label: string; +} + +interface SchemePin { + id: string; + marketplaceId: string; + floorId: string; + shopId?: string; + x: number; + y: number; +} + +interface RentListing { + id: string; + marketplaceId: string; + title: string; + areaSqm: number; + floorId?: string; + status: 'available' | 'leased'; +} + +interface Lead { + id: string; + marketplaceId: string; + rentListingId?: string; + contactName: string; + contactPhone: string; + message?: string; + createdAt: string; +} + +interface NewsPromo { + id: string; + marketplaceId: string; + title: string; + body: string; + publishedAt?: string; +} + +interface MallSettings { + marketplaceId: string; + openingHours: Record; + contactInfo: Record; +} +``` + +Every entity above carries `marketplaceId`, an audit trail, and the same draft/preview/publish flow as [Phase 9's revision model](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) §5 — not a separate content pipeline. + +## 2. Endpoints + +``` +GET/POST/PATCH/DELETE /api/admin/v2/content/shops +GET/POST/PATCH/DELETE /api/admin/v2/content/shop-categories +GET/POST/PATCH/DELETE /api/admin/v2/content/services +GET/POST/PATCH/DELETE /api/admin/v2/content/floors +GET/POST/PATCH/DELETE /api/admin/v2/content/scheme-pins +GET/POST/PATCH/DELETE /api/admin/v2/content/rent-listings +POST /api/admin/v2/content/rent-listings/{id}/leads +GET/POST/PATCH/DELETE /api/admin/v2/content/news +PATCH /api/admin/v2/content/mall-settings +``` + +## 3. Tenant feature configuration (Gorbushka's v1 default, per plan §11.1) + +```json +{ + "cms": true, "shops": true, "services": true, "mallScheme": true, + "rentListings": true, "news": true, "seoMedia": true, + "catalog": false, "sellerPortal": false, + "cart": false, "checkout": false, "payments": false, "orders": false +} +``` + +Commerce modules are **platform-ready but off** — the point of Phase 10 is proving this tenant can flip `catalog`/`cart`/`checkout`/etc. to `true` later via [Phase 9's `MarketplaceFeatureSet`](PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md) with zero backend or storefront code changes, since the commerce core is already generic by the time Phase 10 starts. + +## 4. What the frontend will start doing once this ships + +- Mall scheme / floor / pin editor UI. +- Rent listing + lead capture forms. +- Confirm the existing Gorbushka frontend/archive is used as UX reference only — production data and auth route through the shared platform per ADR-0001. diff --git a/docs/backend/PHASE-8-IDENTITY-MESSAGING-CONTRACT.md b/docs/backend/PHASE-8-IDENTITY-MESSAGING-CONTRACT.md new file mode 100644 index 0000000..2de690d --- /dev/null +++ b/docs/backend/PHASE-8-IDENTITY-MESSAGING-CONTRACT.md @@ -0,0 +1,151 @@ +# Phase 8 Backend Contract — Customer Identity, VK ID, MAX/Telegram Messaging + +Companion to [PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md](../PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md) Phase 8 (Sprints 8.1–8.5). Covers plan §2.9, §3.4, and all of §14 (the v3.1-only addition). + +**Status: ready to build. Sprint order fixed by Sprint 0.1 decision: VK ID first, then everything else** ("do all after vk"). Sequence below follows that: identity core → VK ID → email/phone OTP → MAX/Telegram → Notification Orchestrator. + +--- + +## 1. Entities + +```ts +interface Customer { + id: string; + marketplaceId: string; // or global identity strategy, tenant-configurable + name?: string; + email?: string; + phone?: string; + status: 'active' | 'suspended'; + createdAt: string; +} + +interface ExternalIdentity { + customerId: string; + provider: 'vk_id' | 'telegram' | 'max'; + providerUserId: string; + verifiedAt: string; + metadata: Record; + lastUsedAt: string; +} + +interface ContactMethod { + customerId: string; + type: 'email' | 'phone'; + value: string; + verifiedAt?: string; +} + +interface ContactChannel { + customerId: string; + provider: 'telegram' | 'vk' | 'max'; + chatId: string; + verified: boolean; + notificationsEnabled: boolean; + deliveryEnabled: boolean; +} + +interface MessagingConsent { + customerId: string; + channel: string; + purpose: 'marketing' | 'order_service_messages'; + grantedAt?: string; + revokedAt?: string; +} +``` + +Telegram is demoted from sole identity to one `ExternalIdentity` provider among several — it must remain fully functional, just no longer the only path. + +## 2. Sprint 8.2 — VK ID (build first) + +``` +GET /api/identity/v1/vk/authorize -> redirects into VK's OAuth 2.1/PKCE flow +POST /api/identity/v1/vk/callback { code, codeVerifier } -> completes OAuth **backend-side**, + links ExternalIdentity, returns session +``` + +Invariants: +- OAuth completion happens entirely backend-side; the VK client secret never reaches the frontend. +- A repeat login for the same `providerUserId` must resolve to the same `Customer`, never create a duplicate. +- If `providerUserId` is already linked to a *different* `Customer` than the one currently authenticated (or none), this is an identity conflict — route to controlled resolution, never silently overwrite the existing binding (plan §14.3). + +## 3. Sprint 8.3 — Email/phone OTP (after VK ID) + +Implements the already-approved [email/phone login spec](../superpowers/specs/2026-08-15-email-phone-login-design.md). Per v3.1 §14, position this as **recovery/fallback** when a messenger channel is unavailable — not the primary login path. No new contract beyond that spec; this section exists only to fix its place in the build order relative to VK ID. + +## 4. Sprint 8.4 — MAX + Telegram bot channels + +```ts +interface BotConversationBinding { + customerId: string; + marketplaceId: string; + provider: 'telegram' | 'max'; + chatId: string; + state: string; // see §5 state machine + orderId?: string; + lastMessageAt: string; +} +``` + +MAX linking flow (bot-assisted, one-time code): +``` +POST /api/identity/v1/max/link-code -> { code, expiresAt } (TTL, single-use, bound to marketplace + browser session) +``` +User opens the MAX bot, sends the code; a confirmed bot update on the backend calls: +``` +POST /api/providers/v1/max/bot-webhook -- idempotent; a repeated update must not create a duplicate binding +``` +which links the pending `Customer` session to the MAX `chatId`. + +All three providers' incoming bot updates (VK, MAX, Telegram) normalize into one shape: + +```ts +interface MessagingEvent { + provider: 'telegram' | 'vk' | 'max'; + chatId: string; + orderId?: string; + text?: string; + receivedAt: string; +} +``` + +Provider bot tokens/secrets never reach the frontend, ever — only the backend calls each provider's Bot API. + +## 5. Sprint 8.5 — Notification Orchestrator + Delivery Conversation State Machine + +On `order.paid` (Phase 2 event bus), the orchestrator picks the customer's chosen channel (captured at checkout, see [Phase 6](PHASE-6-CART-CHECKOUT-CONTRACT.md) and `OrderContactSnapshot` in [Phase 2](PHASE-2-ORDERS-NOTIFICATIONS-CONTRACT.md)) and drives: + +``` +not_started -> awaiting_customer -> details_received -> manager_assigned/auto_confirmed -> shipment_planned -> completed +``` + +```ts +interface DeliveryDetailsSnapshot { + orderId: string; + city?: string; + address?: string; + recipientName?: string; + phone?: string; + timeWindow?: string; + comment?: string; + receivedAt: string; +} +``` + +Hard rules: +- **The bot never changes financial statuses.** It can only write `DeliveryDetailsSnapshot` fields via a dedicated Delivery Service — no bot code path touches `Order.paymentStatus`/`orderStatus`. +- The backoffice `Notification` (Phase 2 §6) fires unconditionally on `order.paid`, independent of whether the customer's messenger channel is reachable. +- If the chosen channel is unavailable, log a `DeliveryAttempt` error (Phase 2 §6) and fall back per tenant-configured policy (e.g. email/SMS) — never block the order itself. +- Follow-up messages are rate-limited per tenant policy; after the configured attempt limit, hand off to a human manager instead of continuing to message. + +``` +POST /api/providers/v1/{provider}/bot-webhook -- generic entrypoint for all three providers +GET /api/admin/v2/orders/{orderId}/conversation -- message history + current state, for manager handoff +POST /api/admin/v2/orders/{orderId}/conversation/handoff +``` + +## 6. What the frontend will start doing once this ships + +- VK ID login button + OAuth redirect flow on storefront (primary social login). +- MAX/Telegram linking UI (one-time code flow). +- Checkout channel-choice step ("where should we send confirmation?") — VK / MAX / Telegram / email/SMS fallback. +- Manager-facing conversation view (message history, current delivery state, accept handoff). diff --git a/docs/backend/PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md b/docs/backend/PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md new file mode 100644 index 0000000..3d131bc --- /dev/null +++ b/docs/backend/PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md @@ -0,0 +1,130 @@ +# Phase 9 Backend Contract — Tenant Registry, Domain Automation, Publish Model + +Companion to [PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md](../PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md) Phase 9 (Sprints 9.1–9.3). Covers plan §4.3, §8. + +**Status: ready to build.** Zero `hostinger` references exist in the codebase today. + +--- + +## 1. Entities + +```ts +interface Marketplace { + id: string; + name: string; + code: string; + type: 'commerce' | 'mall_directory' | 'hybrid' | 'single_brand'; + ownerId: string; + countries: string[]; + locales: string[]; + currencies: string[]; + timezone: string; + lifecycleState: MarketplaceLifecycleState; +} + +type MarketplaceLifecycleState = + | 'draft' | 'configured' | 'content_ready' | 'domains_planned' + | 'staging_live' | 'qa_passed' | 'production_ready' | 'live' | 'paused' | 'archived'; + +interface MarketplaceDomain { + marketplaceId: string; + domain: string; + type: 'production' | 'www' | 'staging' | 'preview' | 'api' | 'seller'; + status: 'planned' | 'dns_pending' | 'ssl_pending' | 'active' | 'failed'; +} + +interface MarketplaceFeatureSet { + marketplaceId: string; + features: Record; // e.g. { catalog: true, sellers: true, cart: true, checkout: true, payments: true, orders: true, refunds: true, directory: false, ... } +} + +interface MarketplaceRevision { + id: string; + marketplaceId: string; + status: 'draft' | 'validated' | 'preview' | 'published'; + publishedAt?: string; + supersedesRevisionId?: string; // rollback creates a NEW revision, never mutates the old one +} +``` + +**Hard invariant:** `Order`, `Payment`, `InventoryRecord`, and every financial ledger row are **not part of a `MarketplaceRevision`**. Rolling back a storefront design revision must never touch commerce data. + +## 2. Lifecycle state machine + +``` +draft -> configured -> content_ready -> domains_planned -> staging_live -> qa_passed -> production_ready -> live -> paused/archived +``` + +Every state transition endpoint must return the specific blocker preventing the next transition — not just "not ready." + +``` +GET /api/admin/v2/marketplaces/{id}/lifecycle -> { currentState, nextState, blockers: string[] } +POST /api/admin/v2/marketplaces/{id}/lifecycle/advance +``` + +## 3. Onboarding wizard (8 steps, plan §4.3) + +``` +POST /api/admin/v2/marketplaces -- step 1: name/code/type/owner/countries/locales/currencies/timezone +PATCH /api/admin/v2/marketplaces/{id}/feature-set -- step 2 +POST /api/admin/v2/marketplaces/{id}/domains -- step 3 +PATCH /api/admin/v2/marketplaces/{id}/design -- step 4 +POST /api/admin/v2/marketplaces/{id}/roles -- step 5 +PATCH /api/admin/v2/marketplaces/{id}/integrations -- step 6 +POST /api/admin/v2/marketplaces/{id}/staging-launch -- step 7, runs smoke tests +POST /api/admin/v2/marketplaces/{id}/production-launch -- step 8, requires all P0 blockers closed + explicit approval +``` + +## 4. Domain automation (Hostinger API, per plan §8.2) + +``` +GET /api/dns/v1/zones/{domain} +POST /api/dns/v1/zones/{domain}/validate +PUT /api/dns/v1/zones/{domain} +DELETE /api/dns/v1/zones/{domain} +GET /api/dns/v1/snapshots/{domain} +GET /api/dns/v1/snapshots/{domain}/{snapshotId} +POST /api/dns/v1/snapshots/{domain}/{snapshotId}/restore +``` + +Process, strictly in this order: +``` +1. Read current DNS zone. +2. Save a snapshot (rollback payload) BEFORE any change. +3. Build and validate a DNS plan. +4. NEVER touch MX/SPF/DKIM/DMARC/CAA records without a separate, explicitly scoped task. +5. Apply records only after production approval. +6. Verify propagation, SSL issuance, and health checks. +7. Mark the domain 'active' only after all checks in step 6 pass. +``` + +## 5. Publish model + +``` +draft -> validation -> preview -> publish +``` + +``` +POST /api/admin/v2/marketplaces/{id}/revisions -- create draft +POST /api/admin/v2/marketplaces/{id}/revisions/{revId}/validate +POST /api/admin/v2/marketplaces/{id}/revisions/{revId}/publish -- becomes immutable +POST /api/admin/v2/marketplaces/{id}/revisions/{revId}/rollback -- creates a NEW revision pointing at the prior published content +``` + +Replaces the current builder's `localStorage`-only draft persistence and the empty `apiEndpoints.builder: {}` placeholder in bootstrap. CMS/static-page content (currently in-memory bootstrap only) gets a real write path through this same revision model. + +## 6. Tenant resolution hardening + +``` +GET /api/v2/storefront/bootstrap -- resolved server-side from verified Host header +``` + +- Host is normalized and matched against `MarketplaceDomain` server-side — the marketplace ID from the browser is never a trust boundary. +- Unknown Host → `404`, with **no fallback to any other tenant**. + +## 7. What the frontend will start doing once this ships + +- Build the backoffice **Marketplaces** section (missing from admin nav today): registry, type, status, domains, currencies, feature set, responsible manager. +- Build the **Domains & Releases** section: DNS/SSL status, staging/production, health checks, rollback. +- Wire the project editor/builder to real revision persistence instead of `localStorage`. +- Marketplace dashboard: GMV, paid orders, conversion, payment failure rate, moderation queue, low stock, unmatched events, integration health, domain/SSL/release status (plan §4.2).