DomiDo's domain layer is what turns a customer's idea, a designer's listing, an interest signal, a verified card, and a shipment into one coherent set of records. This page is the canonical map of those records: the entities the platform reasons about, the relationships between them, the MongoDB Atlas collections that store them, and the read models that the universal app consumes. The intent is that an engineer arriving with no prior context can scan this page, follow the entity-relationship diagram, and understand the shape of the business before opening a single source file. The page is also the boundary between architecture and the canonical REST contract: every entity here corresponds to a resource that the API exposes through the Interface requirements page, and every read model here corresponds to a UI-ready snapshot the universal app can render without joining unrelated resources on the client. Throughout the document, three-aggregate separation between interest reservations, pre-orders, and orders is treated as a structural invariant, not a presentation choice — Phase A demand never collapses into a Phase A.5 commitment and a Phase A.5 commitment never collapses into a Phase B captured order, regardless of how convenient that flattening would be in any given read model.
The single source of truth for the REST surface is the canonical contract under the Interface requirements page; architecture documents reference application-programming-interface concepts but never carry a parallel schema file. Frontend-facing mutations always return either the updated resource or the parent aggregate the screen needs next, so the app does not reassemble state through multiple round trips. The first-class domain concepts the contract reasons about are named, not opaque, and they must not be replaced by generic payloads at the storage or transport layer. Each named concept earns its place because it carries lifecycle state, audit history, or commercial meaning that a generic payload would lose.
| Concept | Purpose |
|---|---|
| Feature phase gate | Delivery-phase control for visible but inactive behaviour. |
| Interest reservation | Phase A non-binding demand signal: no card, no charge, no order or pre-order, with cancellation, listing-owner attribution, and conversion-invite state. |
| Checkout commitment | Checkout confirmation result that can be a Phase A.5 pre-order or a Phase B order. |
| Pre-order | Phase A.5 physical-kit no-capture commitment: invited reservation, fresh buyer consent, verified card, no capture, with cancellation, attribution, and conversion readiness. |
| Order | Phase B captured, fulfilment-active order. |
| Stripe SetupIntent request | Phase A.5 card-verification request for an invited reservation. |
| Payout account | Designer Stripe Connect / Know Your Customer state, payout settings, and payout readiness. |
| Designer sale (attributed interest) | Phase A public demand state before pre-orders exist. |
| Designer sale (attributed pre-order) | Phase A.5 projected entitlement state before captured sales exist. |
| Buyer dashboard | UI-ready buyer aggregate for the home resume cards, dashboard overview, drafts, saved listings, followed designers, notification shortcuts, and account shortcuts. |
| Text assist request | Phase-gated AI assistance context for copy, reply, and help-drafting surfaces. |
| Job | Polling-first long-running work resource for generation, voxelisation and block-kit, AI assistance, translation, publication, notification dispatch, embedding refresh, and future fulfilment work. |
| Localised text | Source user input plus translated variants, context, status, provider metadata, and source-checksum stale protection. |
| Translation configuration | Backend-owned language list, fallback order, translation provider state, glossary, and prompt or configuration version. |
| Translation job result | Async result for translated fields that can update the owning aggregate without replacing changed source text. |
The diagram below shows the major aggregates and how they relate. A user may have a designer profile and may own a stack of drafts, reservations, pre-orders, and orders; a designer publishes listings, connects a single payout account, and accrues designer-sale records; a design produces a deterministic kit of universal blocks and fasteners and may be published as a listing; reservations may convert to pre-orders, pre-orders may convert to orders, and the two payment links — verification via SetupIntent for pre-orders and capture via PaymentIntent for orders — are themselves distinct.
Three invariants are visible directly in the diagram. An interest reservation, a pre-order, and an order are separate aggregates; they may be linked, but they are never collapsed into one ambiguous record. A kit is the bill of materials that a design produces — a deterministic set of universal blocks plus fasteners — and the platform sells only those blocks and fasteners; there are no "hero products" sitting alongside the kits. A payment is associated with a pre-order through SetupIntent for verification and with an order through PaymentIntent for capture, and the two payment states are distinct objects that never share a single record.
The system is organised into named domain modules, each owning a slice of the business and the data behind it. The Identity module owns OAuth identity, the user profile, roles, sessions, and preferences. The Configuration module owns jurisdictions, delivery options, generation costs, payout configuration, feature phase gates, and translation configuration. The Catalogue module owns the public user-owned listings, creator and listing-owner profiles, the gallery and search surface, product-detail variants, and reviews and questions where they are active. The Creation module owns design drafts, projections, model tryouts, model feedback, block kits, the bill of materials, and assembly payloads. The Media module owns uploads, generated assets, the private-and-public media state, and safe download references.
The Localisation module owns supported content languages, source-language handling, localised-field resolution, translation jobs, and the isolation of the language-model provider behind a backend adapter. The Reservations module owns Phase A interest reservations, the non-binding acknowledgement, cancellation, anti-abuse signals, demand analytics, and the Phase A.5 conversion-invite state. The Commerce module owns the Phase A.5 and Phase B cart, saved carts, checkout state, Stripe verification and payment state, and promo codes. The Pre-orders module owns Phase A.5 commitments, card-verification state, the no-capture acknowledgement, cancellation, attribution, and conversion readiness. The Orders module owns Phase B order records, payment capture, fulfilment, shipment, returns, replacements, disputes, and the build companion. The Designer-commerce module owns listings, attributed interest, attributed pre-orders, projected entitlements, payout readiness, statements, payout release, reserves, and disputes. The Help and support module owns Docusaurus publication metadata, help comments, support conversations, and the admin content workflow. The Audit module owns the security-sensitive and business-sensitive event history that the rest of the system writes into.
Phase rules are enforced inside the data model itself, not only at the user interface. Aggregates that expose future-phase behaviour carry phase state, or are reachable through a parent aggregate that does — so a screen cannot accidentally read a record that should be invisible at the active phase. The Phase A interest reservation, the Phase A.5 pre-order, and the Phase B order are three separate aggregate types that may be linked but are never collapsed, and the Phase A.5 designer and listing-owner commerce records can record demand and readiness without ever creating captured money-movement facts. Payout-release records, when they appear, require Phase B captured funds, delivery eligibility, reserve and dispute checks, and a positive payout-readiness state on the owning payout account; nothing else makes a release record valid.
The server is authoritative for everything that matters at money time. Pricing, Value-Added Tax, delivery, generation costs, payout rules, feature gates, translation target languages, interest-reservation state, Phase A.5 checkout totals, pre-order state, order state, and audit state are all recalculated and validated server-side at the moment an action runs; the frontend may cache UI snapshots, but it must revalidate before creating or cancelling an interest reservation, confirming a Phase A.5 checkout, cancelling a pre-order, changing payout readiness, or requesting a payout release. Idempotency is required for reservation create or cancel, checkout confirmation, SetupIntent or session creation, pre-order cancellation, generation-job creation, translation-job creation, job retry and cancel controls, asset publication, payout-readiness changes, payout requests, order actions, help comments, and admin publication actions; replays return the stored response rather than producing duplicate effects. Audit events are written for every state change that affects reservations, payment verification, commitments, orders, designer and listing-owner payout readiness or release, publishing, translation configuration and job state, privacy, support, and admin operations.
Free-form user-generated text that is visible outside a private form uses the localised-text or localised-field-map structure described later on this page. Source text stays authoritative; translated variants are derived, versioned by source checksum and configuration version, and are allowed to be stale or failed without invalidating the source mutation. Long-running work is represented by job aggregates whose public reads expose polling progress, steps, result and artefact references, retry and cancel eligibility, safe errors, and timestamps; internal worker-lease state stays backend-only, and stale job results never overwrite newer draft or source state. Reliability state — health and readiness, dependency degradation, provider outage, job dead-letter and manual repair, webhook durable-store failure, media-object mismatch, audit fail-closed, restore rehearsal, and reconciliation — is first-class domain and API data when it affects users or operators, and it does not exist only in logs. Critical state changes that affect reservations, payment verification, pre-order commitments, payout readiness or release, admin content, privacy, trust, security, or provider webhooks require durable business state, idempotency state where applicable, and audit state to land before success is returned to the caller.
The multilingual user-generated-content pipeline applies to design prompts and briefs, draft publish copy, listing title and description and tags, designer bios and inspirations, reviews, questions, replies, messages, help comments, support conversations, report and dispute notes, and Promo Studio prompts. It explicitly excludes structured enum and configuration values, price and currency, legal acceptance text, payment fields, addresses, OAuth identity data, raw provider payloads, audit actor metadata, and system-authored help article source.
The API exposes UI-ready read models so the universal app does not have to assemble its own data. Public browsing read models are optimised for fast loading of listing cards and listing-detail screens. Dashboard read models combine interest reservations, Phase A.5 pre-orders, future orders, notifications, support actions, and designer and listing-owner commerce summaries without forcing the frontend to join unrelated resources, and designer dashboards keep projected values, captured values, and release-eligible values separate so that a designer never confuses one for another. Help and workshop public pages may be served from a statically published projection while comments, support, and admin workflows remain runtime API data. The traceability contract for the universal app — the cross-walk between every visible element and the backend snapshot that feeds it — is the API traceability audit; if a visible UI element needs data, the backend exposes a UI-ready read model, or the shell hides or gates the element. Read models that expose translatable content resolve display text by trying, in order, an explicit API language parameter, the authenticated user's preferred content language, the Accept-Language header, the configured default language, and finally the source text, and they include translation status and fallback metadata wherever the app needs to explain owner or admin state or avoid pretending fallback text is a completed translation.
The MongoDB Atlas database is organised into the collections below. Collections marked A are part of Phase A; collections marked A.5 or B activate when their phase opens. Storage technology is not prescribed by the domain document itself — selection details live on the Backend page — but the catalogue below is the active implementation map.
| Collection | Phase | Purpose |
|---|---|---|
users |
A | DomiDo user profile, roles, locale and currency, designer and admin refs |
oauth_identities |
A | Provider identity mapping |
sessions |
A | Server-issued sessions and access credentials |
trust_restrictions |
A/B | Anti-abuse restrictions and challenge state |
addresses |
A/B | Saved buyer delivery and billing addresses |
notification_preferences |
A | User notification settings |
notification_items |
A/B | Concrete dashboard and inbox notifications |
feature_phase_gates |
A | Server-side phase gates |
jurisdiction_configs |
A | Supported country, currency, VAT, delivery, and card copy |
generation_cost_configs |
A | AI and processing cost configuration |
payout_configs |
A.5 | Payout thresholds, fees, schedules, and reserve rules |
translation_configs |
A | Supported languages, fallback order, LLM provider state, glossary and context settings |
create_style_presets |
A | Describe-stage style presets |
promo_studio_configs |
A.5 | Promo Studio options and costs |
shell_configs |
A | App shell, footer, and search configuration |
media_assets |
A | Uploads, generated media, model files, artefacts |
upload_sessions |
A | Signed upload lifecycle and validation |
design_drafts |
A | The create-wizard aggregate |
jobs |
A | Long-running work with leases and retries |
model_feedback |
A | User feedback on generated model tryouts |
listings |
A | Public and designer-owned listings |
designer_profiles |
A/A.5 | Public designer identity and owner profile |
designer_profile_history |
A.5 | Optional audit-friendly snapshots of owner profile edits |
listing_questions |
A/A.5 | Listing question and answer |
reviews |
B | Buyer reviews and designer replies when active |
search_documents |
A | Text- and vector-searchable public documents |
interest_reservations |
A | Non-binding demand signals, acknowledgement, cancellation, anti-abuse, conversion-invite state |
carts |
A.5/B | Active cart per user or session where commerce phase is active |
saved_carts |
A.5/B | Saved cart and checkout-draft snapshots |
checkout_states |
A.5/B | The checkout-step aggregate |
payment_references |
A.5/B | Masked Stripe payment-method references |
pre_orders |
A.5 | SetupIntent-backed no-capture commitments |
orders |
B | Captured, fulfilment-active orders |
shipments |
B | Shipment and parcel data |
returns |
B | Return requests and assessments |
disputes |
B | Order, trust, payment, and designer disputes |
support_conversations |
A/B | Support-conversation state |
support_messages |
A/B | Support message bodies, translations, attachments, visibility, and read state |
designer_listings |
A.5 | Owner editor state, moderation, similarity, metrics |
promo_studio_projects |
A.5 | Listing-scoped Promo Studio scene and asset state |
designer_sales |
A/A.5/B | Attributed interest, attributed pre-orders, captured sales, royalty and entitlement lifecycle |
designer_message_threads |
A.5/B | Designer messages, question-and-answer workflow nodes, internal notes, reports |
designer_claim_actions |
B | Designer claim and dispute actions linked to orders and replacements |
payout_accounts |
A.5/B | Stripe Connect, Know Your Customer, tax, and payout settings |
royalty_events |
A.5/B | Projected and captured royalty events |
payout_transfers |
B | Actual or preview payout transfers |
reserve_ledger |
A.5/B | Reserve holds, releases, adjustments |
statements |
A.5/B | Designer statement archives |
help_topics |
A | Help and workshop topics |
help_articles |
A | Admin-authored content source metadata |
help_comments |
A | Runtime article comments and replies |
help_article_feedback |
A | Helpful votes, lightweight feedback, and bookmark state |
help_publication_artifacts |
A | Docusaurus export and build records |
newsletter_signups |
A | Newsletter consent records |
cookie_preferences |
A | Cookie consent by user or session |
privacy_requests |
A | Data export, lifecycle, and delete requests |
audit_events |
A | Security and business audit log |
idempotency_keys |
A | Mutation replay control |
webhook_events |
A/B | Provider webhook safe-event log |
outbox_events |
A/B | Reliable side-effect dispatch |
reliability_events |
A | Dependency outage, readiness transition, restore rehearsal, circuit-breaker, repair, incident, and audit fail-closed evidence |
alert_rules |
A | Alert-rule definitions, owner, state, trigger summary, and linked incidents |
analytics_events |
A | Product funnel event mirror where needed |
product_event_definitions |
A | Controlled product-event dictionary and property schema versions |
beta_feedback |
A | Structured beta-tester and customer feedback with translation and routing state |
admin_exports |
A | Founder and admin beta, feedback, support, and statement export records |
Every collection document carries a small set of universal fields. Each document has an _id, a createdAt and updatedAt pair, a schemaVersion, a deletedAt where soft deletion is needed, createdBy and updatedBy for user-mutated or admin-mutated records where that history is useful, and a requestId on mutation-created records where the audit trail benefits from it. User-facing resources expose id rather than raw _id semantics; public slugs and display references are unique within their domain; the internal identifier is ObjectID unless a public display reference or external provider identifier is explicitly required.
Money subdocuments use integer minor units, and floats are never persisted. The canonical money shape carries amountMinor, currency, a display string, an includesVat flag, and a configVersion so a price snapshot can be reproduced exactly:
{
"amountMinor": 12900,
"currency": "GBP",
"display": "GBP 129.00",
"includesVat": true,
"configVersion": "jurisdiction-2026-05-13"
}
Media references stored inside domain records point to media_assets by id and may include denormalised safe display fields: kind, alt text, width, height, format, thumbnail asset id, public URL only if the asset is public, and signed-action references only when generated for the current user and the current request. Private URLs are not stored inside public records, and the safe display fields are the contract that public reads can rely on.
Translatable user input is stored on the owning aggregate as a localised-text object rather than split into detached translation records by default; this keeps reads simple for the Web and Progressive Web App beta and avoids distributed joins across listing, draft, message, and support surfaces. A localised-text record carries sourceLanguage, sourceText, and sourceChecksum; a context block with resourceType, resourceId, fieldPath, an audience tag drawn from public, buyer, designer, support, admin, or internal, and a tone hint where available; a variants array where each variant carries language, text, status, provider, model, translatedAt, sourceChecksum, qualityFlags, and errorCode; an aggregate translation status for the field; and an updatedAt. A localised-field-map keys many separately translated fields by stable field path — for example title, description, designer.bio, or messages.body — and workers update only the affected field paths and use optimistic source-checksum checks so an old translation result cannot overwrite text the user has since edited.
The users collection carries email, emailNormalized, displayName, avatarMediaId, roles drawn from buyer, designer, admin, support, and finance, locale, preferredContentLanguage, currency, cartId, designerProfileId, adminContentCapability, a status drawn from active, restricted, paused, or deleted, marketingConsent, and first-touch and last-touch UTM attribution. It is indexed uniquely on emailNormalized, with secondary indexes on roles, designerProfileId, and createdAt. The sessions collection records userId, sessionHash, a credentialType of webCookie or bearerToken, device display, the platform tag (web, ios, android, or unknown), created and last-active and expires and revoked timestamps, and a csrfTokenHash for cookie sessions; it is unique on sessionHash and carries a TTL on expiresAt. Feature phase gates carry featureKey, phase, status, userFacingState, disabledReason, activationCriteria, configVersion, effectiveFrom, and updatedBy; Phase A active gates include public discovery, gallery, the two create modes, draft save, listing publish, cart, SetupIntent checkout, pre-orders, support, help comments, and admin beta, while inactive or gated gates include the designer marketplace, Promo Studio, Stripe Connect payout readiness, payment capture, fulfilment, shipment tracking, returns, build companion, payout release, remix economics, and the native iOS and Android targets.
A listing carries slug, title, description, a designer reference, a source draft id, media references, indicative price and royalty fields, visibility, remix flags, a status drawn from draft, published, paused, moderationBlocked, or archived, availability and orderability flags, tags, category, kit and assembly summaries, review and question summaries, product-detail variant references, and phase status. It is indexed by slug (unique), by visibility-and-status-and-createdAt, by designer-and-status-and-updatedAt, by category and by tags, with a text index over title and description for fallback search and a reference to a vector-search document for semantic discovery.
The Phase A demand signal is the interest reservation. It stores a public reference, the buyer (a user or session), the listing and listing-owner ids, a status drawn from active, cancelledByUser, cancelledByDomiDo, blocked, invitedToPreorder, convertedToPreOrder, or expired, the non-binding acknowledgement and its version, an indicative price snapshot, jurisdiction, intended use, source surface, campaign or UTM context, duplicate-policy state, conversion-invite state, the converted pre-order id, a cancellation timestamp and reason, and the audit correlation id. By invariant, no Stripe object is created for an interest reservation, no order or pre-order or receipt or invoice or shipment or payout state is created, cancellation is permitted while status is active unless an administrator abuse block applies, and Phase A.5 conversion requires a separate invite and a fresh buyer action.
The Phase A.5 commitment is the pre-order. It stores a reference, the source reservation id, the conversion-invite id, the user id, the listing-owner id, the checkout state id, items, a status drawn from draft, cardVerified, committed, cancelled, expired, convertedToOrder, or conversionBlocked, a card-verification status drawn from notStarted, setupIntentCreated, requiresAction, verified, failed, or expired, Stripe SetupIntent, Customer, and PaymentMethod ids, the expected price, buyer fresh consent, the no-capture acknowledgement, gate versions, cancellation eligibility, support and dashboard summary fields, attribution, conversion readiness, the downstream order id, configuration versions, and the audit correlation id. The invariant is that a pre-order never contains a receipt, invoice, shipment, delivery promise, fulfilment handoff, payout release, or captured payment reference.
The Phase B captured aggregate is the order. It stores a reference, the source pre-order id, the user id, items, status, payment, fulfilment readiness, delivery status and address, the selected delivery option, shipments, totals, receipt and invoice references, actions, messages, timeline, a trust-restriction reference, and phase status. The designer profile carries a unique handle, display name, banner and avatar references, verified state, availability, bio, location display, social links, portfolio and collection references, follower counts, section visibility, owner analytics, and phase status. Designer sales record attributed demand and the royalty lifecycle: the designer id, listing id, pre-order id, order id, buyer display alias, a status drawn from attributedPreOrder, reserved, sold, disputed, or refunded, the sale value, projected and captured royalty amounts, the Value-Added-Tax-inclusion flag, verification and capture and cleared and paid timestamps, the payout id, lifecycle, dispute, and statement references.
The payout account binds the designer to a Stripe Connect account id, a connect state drawn from notConnected, actionRequired, active, or newDesigner, Know Your Customer state, safe requirement labels, payout options and schedule, an auto-payout pause state, tax region, masked Value-Added-Tax and Unique Taxpayer Reference identifiers, a minimum-payout status, payout readiness status, the payout configuration version, statement archive references, and the last Stripe sync timestamp; raw bank account numbers, raw identity documents, and full tax identifiers are never stored. Royalty events record a sourceType drawn from projectedPreOrder, capturedOrder, returnAdjustment, disputeAdjustment, or manualCorrection, projected and captured amounts, accrual and delivery and earliest-payable dates, payout eligibility state, payout-release eligibility, the statement id, the payout transfer id, the configuration version, and the audit correlation id. Payout transfers carry a status drawn from preview, requested, inTransit, paid, failed, cancelled, or blocked, the amount, a masked method display, an arrival label, a failure reason label, retry availability, the Stripe transfer id and payout id, the included royalty event ids, release eligibility, the requested-by actor, timestamps, and phase status — and actual money movement is blocked unless the Phase B payout-release gates are active. The reserve ledger records holds, releases, and adjustments against designer payout balances with the linked sale, dispute, and order ids.
A single, polled job aggregate covers all long-running work across the platform. Each job carries a job type — one of projection face, projection autofill, model generation, block-kit generation, promo photo, promo video, text assist, text translation, Docusaurus publication, notification dispatch, fulfilment sync, or embedding refresh — an owner id, a resource reference, an internal status, the public status that the OpenAPI surface exposes, progress, the current step, the step list, input, the result reference, artefact references, cost and configuration metadata, safe provider metadata, attempts, max attempts, lease owner and lease-until and heartbeat, retry-after, cancel-requested and by and reason and at, error code and message, provider error class, poll-after-ms, the idempotency-key id, and the audit correlation id. The worker lifecycle begins by finding a queued or retryable job with no active lease whose retry-after has elapsed; it atomically sets the status to leased, sets lease owner and lease-until, and increments the attempt only when transitioning into execution; it then sets the status to running, writes the start timestamp on the first attempt, and publishes a safe first step. Workers update heartbeat, progress, current step, and steps regularly, and on a safe-stop cancellation request they write cancelled, preserve previous successful state, and do not publish partial artefacts. On success, the worker writes result and artefact references, the linked aggregate updates, the outbox and audit events, and a final status of succeeded; on failure, it writes a safe error code, message, and provider class, then either transitions to retrying with a retry-after or to deadLettered once attempts are exhausted. Expired leases are recoverable by another worker after lease-until, and stale results are ignored when the source resource version or checksum no longer matches the job input. Public job responses map the internal succeeded state to complete and never expose leased, worker host names, raw queue names, private storage keys, raw provider payloads, or language-model prompts.
Idempotency keys carry scope, key, actorId, an optional sessionId, operation, a request hash and summary, a response status and body snapshot, resource references, a state drawn from inProgress, completed, failed, or conflict, a lockedUntil, a conflict reason, and an expiresAt. They are unique on the tuple of scope, key, actorId, and operation, indexed by state and locked-until, and carry a TTL on expiresAt. A repeat request with the same key and the same hash returns the stored response or current resource snapshot; a repeat with the same key and a different hash returns an idempotency conflict; a repeat while the first is still in progress returns the current in-progress state or a retryable conflict, but never starts duplicate provider or worker work.
Audit events are append-only and corrections are themselves new audit events. Each event carries actor and role, resource type and id, action, result, source surface, request id, correlation id, hashes of IP and user-agent, a safe summary, and the creation timestamp. Webhook events store the provider, the provider event id (unique), the event type, the API version, the received-at timestamp, the signature-verified flag, the signature timestamp, the request-body hash, a processing status drawn from received, processed, ignoredDuplicate, failed, or deadLettered, related resource references, and a safe payload summary; raw provider payloads are never exposed through application APIs. Outbox events drive reliable provider side effects after MongoDB transactions commit — email dispatch, analytics dispatch, Docusaurus publication start, fulfilment provider calls, designer notifications, and Stripe reconciliation — and they carry the standard lease, retry, idempotency-key, and dead-letter fields. Reliability events provide small operational records that capture beta reliability evidence and repair history — dependency outage, readiness change, circuit opened or closed, worker drain, restore rehearsal, media repair, webhook-store failure, audit fail-closed, and reconciliation — without exposing secrets or raw provider payloads.
The backend ships an idempotent index-creation command that creates ordinary indexes, TTL indexes, unique indexes, Atlas Search indexes, and Atlas Vector Search indexes from configuration. Production startup verifies that required indexes exist, but it does not silently apply destructive index changes. Each document carries a schemaVersion, and the backend supports read-time tolerance for the previous production schema version during rolling deploys; migrations are idempotent, resumable, logged, safe to run in staging first, and reversible whenever the change is metadata-only. Phase A launch migrations avoid long collection locks.
Embeddings live on search_documents.embedding together with provider, model, dimensions, version, source-updated-at, indexed-at, and embedding-input-hash metadata. The Atlas Vector Search index uses cosine similarity over the embedding vector and filters by scope, visibility, phase status, resource type, category, and tags; the embedding dimension is read from configuration rather than hard-coded, and if the model or dimensions change a new vector index is created and backfilled before the active configuration switches over. The search endpoint loads the search configuration, validates the query and the enabled scopes, generates the query embedding when vector search is enabled, runs the vector query with configured filters, optionally combines vector results with text-search results, applies authorisation and phase filters, and returns a UI-ready response. Search results never leak private drafts, private Promo Studio assets, private media, private support records, or inactive future-phase resources.
Multi-collection state transitions run inside a shared transaction runner with majority write concern, and the runner classifies MongoDB errors before returning to domain code. Transient transaction errors and write conflicts are retried within the request deadline; duplicate-key races on idempotency, webhook, payment-reference, pre-order, and job uniqueness are treated as reconciliation cases rather than 500 errors; unknown commit results are resolved by reading the expected resource, idempotency, or webhook record before retrying any external side effect; timeout, pool exhaustion, and retry exhaustion are mapped to typed service-unavailable errors; and a provider call is never retried merely because the surrounding database transaction was retried.
Required transaction boundaries span the platform. OAuth account creation runs across users, oauth_identities, sessions, and audit_events. Interest reservation create and cancel run across interest_reservations, the listing demand summary where it is denormalised, notification_items, audit_events, and idempotency_keys. Phase A.5 SetupIntent creation runs across checkout_states, interest_reservations, idempotency_keys, audit_events, and optionally outbox_events. Checkout confirmation to pre-order runs across checkout_states, interest_reservations, pre_orders, payment_references, designer_sales, notification_items, audit_events, and idempotency_keys. Pre-order cancellation runs across pre_orders, designer_sales, notification_items, audit_events, and idempotency_keys. Translation job success runs across jobs, the owning aggregate's localised field paths, search_documents when searchable text changed, and audit_events. Draft publish runs across design_drafts, listings, search_documents, jobs, audit_events, and idempotency_keys. Stripe webhook processing runs across webhook_events, the affected payment or pre-order or order or payout records, audit_events, and outbox_events. Phase B pre-order conversion runs across pre_orders, orders, payment_references, designer_sales, royalty_events, audit_events, and idempotency_keys. Payout readiness updates and payout release requests run across the relevant payout, royalty, reserve, audit, and idempotency records. Provider side effects that cannot participate in MongoDB transactions are dispatched through the outbox pattern.