This page defines how DomiDo keeps the platform safe to use and safe to operate. The model is intentionally practical for a small team: enough rigor on payment, privacy, audit, and recovery to run a public beta and prepare for real fulfilment, without enterprise ceremony. It walks through the request-gating chain that every authenticated mutation passes, then through the resource-level authorization rules that decide who can touch what, then through the payment and payout safety posture across Phase A, Phase A.5, and Phase B, then through the privacy and data-protection rules that keep user data minimal and recoverable, then through audit, observability, backup and recovery, and the lightweight operating model that holds it all together. The aim throughout is that a security-significant event is always observable, that a private record cannot become public by accident, and that a single integration outage can never compromise the integrity of money, payouts, or audit trails.
Every inbound request passes through six gates before any domain mutation: session, CSRF (for cookie-authenticated unsafe methods), rate and payload limits, role, resource authorization, and the feature phase gate. Feature gates never replace authorization — they sit beside it. Webhooks are verified, persisted as durable events, and only then mapped into domain mutations. Audit records and observability signals are emitted alongside every state change.
Every authenticated API request is tied to a server-issued session or access credential, and the only OAuth providers exposed to users are Google, Apple, and Facebook. Authorization is resource-based: role names alone are never sufficient, and the platform always evaluates owner, recipient, participant, support context, and finance or trust context where they apply. Feature phase gates do not replace authorization — they are evaluated in addition to role and resource permissions, so a Phase A reader cannot reach a Phase A.5 record just because a phase gate would otherwise allow it. The frontend never receives raw card data, OAuth secrets, payout-account secrets, full tax identifiers, private provider payloads, or unrestricted private media URLs. Admin help and workshop mutation is separate from public help comments and support conversations, so an admin authoring permission never grants a buyer's comment-thread privileges and vice versa. Translated variants inherit the same authorization, visibility, moderation, deletion, and retention rules as the source user input — a translation endpoint or worker result can never make private text public, and the deletion of a source removes its translations. Public endpoints are explicitly identified in the API contract; all other product endpoints require authentication plus resource authorization, and feature gates do not make private resources public. Web/PWA cookie-authenticated unsafe methods use CSRF or same-site origin protection, while native-compatible bearer credentials remain supported through the same authorization layer.
The phase model is enforced at the security layer, not merely at the product layer. Phase A interest reservations do not collect card details, create Stripe objects, create orders, create invoices, create receipts, or imply a legal pre-order — the public interest beta operates entirely outside Stripe's data path. Phase A.5 card verification uses Stripe-controlled card handling for invited eligible reservation conversion only, and DomiDo stores only safe payment references, SetupIntent identifiers, no-capture acknowledgement, gate versions, and verification state; Phase A.5 no-capture pre-orders do not generate receipt, invoice, shipment, capture, or payout-release records. Phase A.5 payout readiness may store local payout settings, KYC and Connect status labels, projected entitlements, and statement previews, but Phase B payout release requires captured funds, delivery eligibility, configured reserve and dispute checks, and payout readiness — every one of those must hold before money moves. Payment and payout provider webhooks are signature-verified, idempotent, correlated with request ids, and audited; Stripe webhook handling verifies the raw body signature, enforces provider replay tolerance, persists a safe event record before mutation, and treats duplicate provider event ids as successful no-op replays so a redelivery cannot double-apply a charge or a payout.
Private drafts, uploads, generated assets, interest reservations, pre-orders, orders, addresses, payment references, payout and tax data, support conversations, moderation reports, and trust restrictions are all access-controlled. Logs and diagnostics redact secrets, raw payment data, private media URLs where not needed, addresses where not needed, and unnecessary trust-restriction details, so a debugging session does not become an incidental data exposure. Cookie preference, data export, lifecycle, and deletion requests are durable and reviewable: the user can see where their request stands and what has been completed. Backup retention and deletion behavior is documented before production launch, so the deletion-rights contract is clear when the first user invokes it. LLM translation provider requests apply data minimization — the backend may send source field text plus minimal field, resource, and audience context, but never payment data, addresses, OAuth identity details, raw provider payloads, audit actor metadata, or unrelated conversation history. Data export, deletion, moderation, and support review flows include translated variants because they are derived personal or user-generated data. Upload, download, and media-processing paths expose signed actions or safe public URLs only — object keys, private URLs, scan records, and parser diagnostics stay backend-only unless explicitly safe.
Six data classes are kept strictly separate: audit logs, technical logs, product analytics, support content, beta feedback, and aggregated metrics. Each class has its own explicit retention, access roles, redaction rules, export eligibility, and deletion behavior before open beta, and product analytics in particular never contain raw support messages, beta feedback bodies, payment data, addresses, OAuth secrets, private media URLs, raw provider payloads, or full LLM prompts and responses. The platform is designed to comply with GDPR data-subject rights, with PCI-DSS by minimization (no raw card data is ever stored — card handling stays inside Stripe-controlled flows), and with OWASP web-application security guidance.
The backend supports anonymous public browsing, a signed-in buyer account, a designer role, an admin role, a support and trust role when needed, and resource-owner authorization. The server issues its own session or access credential after OAuth completion; the frontend never receives provider secrets or raw provider profiles beyond safe display fields. For Web/PWA, secure HTTP-only cookies carry browser sessions where feasible, while bearer access credentials remain supported for native compatibility when native gates open; cookie-authenticated unsafe requests require CSRF state or an equivalent same-site origin control, and bearer-authenticated native-compatible requests pass through the same resource authorization and rate-limit checks rather than bypassing them. Session records store the session-id hash, user id, created and last-active and expires and revoked timestamps, device or browser display, platform hint, approximate location when available, the current-session flag, and the CSRF state for cookie-authenticated unsafe methods.
| Resource | Access rule |
|---|---|
| Draft | Owner or admin / support with explicit reason. |
| Media | Owner, linked public listing, or authorized signed action. |
| Cart / checkout | Owner session or user. |
| Pre-order | Buyer owner, or admin / support with reason. |
| Order | Buyer owner, the assigned designer in a permitted claim context only, or admin / support with reason. |
| Designer listing | Owner designer or admin. |
| Promo Studio | Listing owner only until the asset is made public. |
| Payout account | Owner designer and finance / admin only. |
| Help comment | Public read when approved; author / admin mutation according to status. |
| Audit | Admin / security only; audit access itself creates an audit event. |
Audit events include actor, role, resource, action, result, source surface, timestamp, request id, and a safe summary — enough to reconstruct what happened without storing the underlying secrets that the action touched. The required audited event classes cover authentication, session, and security changes; media upload and generation; create, publish, and listing changes; translation config changes, translation-job lifecycle, and translated-variant replacement; interest reservation create, cancel, and conversion-invite; Phase A.5 checkout, SetupIntent verification, and pre-order creation, cancellation, and conversion; Phase B payment capture, refunds, receipts, and invoices; designer payout readiness, payout release, reserve and dispute, and statements; support, trust, privacy, and admin content actions; and product-event dictionary and config changes, alert-rule changes, incident changes, beta-feedback triage and status changes, and operational export and download actions. Audit access itself is audited, and audit events are append-only — corrections are new audit events rather than rewrites of old ones.
The system exposes operational signals for user-visible failures, not just infrastructure health. Required signals cover interest reservation creation and cancellation failures; Phase A.5 checkout verification failures; Phase A.5 pre-order creation and cancellation failures; generation job latency and failure; translation job latency and failure, stale-result count, provider failure, and fallback-read count; upload failures; product-event ingestion accepted and rejected counts and provider dispatch backlog; support open count, first-response overdue count, escalation count, and top contact reasons; beta feedback count by type, severity, surface, release version, language, and status; reliability incidents and alert-rule state by severity and owner; designer payout-readiness failures; Phase B capture, payout, and fulfilment failures when active; help, support, and admin publication failures; and rate-limit, CSRF, idempotency-conflict, invalid webhook signature, upload validation, provider circuit-breaker, and job-quota rejection events. Monitoring technology is deferred — the selected implementation supports alerts, dashboards, structured logs, and trace and request correlation where practical, but no specific vendor is mandatory. Rate limits, payload limits, worker quotas, provider timeout and retry budgets, and circuit-breaker state are operational controls and are configurable without mandating a specific gateway, cache, queue, or monitoring vendor.
Operational health separates process liveness, traffic readiness, and sanitized dependency health. Readiness transitions, dependency outage and degradation, worker drain and recovery, webhook durable-store failure, audit fail-closed events, media repair, and restore-rehearsal results are observable without exposing secrets, private URLs, raw provider payloads, internal hostnames, queue names, or raw user-generated text. Alerts define severity, owner, trigger, suppression and deduplication, user-impact summary, first action and runbook, and linked incident behavior. Minimum Phase A alert coverage includes API error spikes, interest-reservation failure, job queue age and dead letters, translation failure spike, database readiness loss, object-storage failure, analytics ingestion rejection spike, and support SLA breach. Phase A.5 adds checkout, pre-order, and webhook durable-store alerts before SetupIntent conversion opens. Correlation and request ids connect app-visible errors, backend requests, job attempts, provider failures, support conversations, incident records, and audit events where applicable, without exposing secrets or private payloads to the client.
Durable business data is restorable from backups. Backup coverage spans user accounts, drafts, localized text variants, translation jobs and configuration, media references, interest reservations, Phase A.5 carts and checkout states and pre-orders, orders, designer commerce records, help and admin content, support records, audit records, and configuration. Media objects and metadata are recoverable together — a restored media reference must not point at a missing or public-by-accident asset. Recovery procedures are tested before real payment capture is enabled in Phase B, so the first money that moves through the platform is moving through a recovery model that has actually been rehearsed. Before Phase A open beta, a staging restore rehearsal verifies users, drafts, localized variants, translation jobs and configuration, listings, media references and object visibility, interest-reservation state, audit, jobs and dead letters, help and admin content, support records, and runtime configuration; the Phase A.5 restore rehearsal adds checkout and pre-order state and webhook events. Phase A recovery targets are: MongoDB business data with a recovery point objective of fifteen minutes or better and a recovery time objective of four hours or better; final and public object-storage assets with a recovery point objective of twenty-four hours or better. Intermediate generated artifacts may be regenerated from source records and configuration when that is safer than restoring stale artifacts.
The operational footprint stays small until real scale proves the need for more infrastructure, and managed or simple services are preferred where they reduce team load — but no vendor is mandatory in architecture. Secrets are encrypted at rest, separated by environment, and rotated on compromise. Every production incident that affects interest reservations, payment verification, commitments, payout readiness or release, translation provider data exposure, privacy, or fulfilment produces a short post-incident note and follow-up action, so the operational record stays honest about what failed and what changed. Critical mutations fail closed when audit persistence, idempotency persistence, or required domain-state persistence is unavailable; analytics and best-effort notification dispatch fail open through outbox and dead-letter behavior so they do not block user workflows. The combination — fail closed where money, audit, and consent live, fail open where signals and notifications live — is what lets a small team run a public beta without sacrificing the integrity of the parts of the system that actually have to be right.