Files
nick-doc/02 - Data Models/Data Model Overview.md
Siavash Sameni 940ad0c655 Add full system audit reports and Telegram Mini App debug handoff
- Three-stream audit (security / logic / performance) with 35+ findings
  derived from actual source code, each with file:line and remediation
- Audit Index cross-references criticals across streams into prioritized
  fix tiers: immediately / before soft launch / before public launch
- Telegram Mini App debug handoff documenting what was implemented and
  all remaining work items with exact file lists and test commands
- Updated architecture, data model, auth API, and registration flow docs
  to reflect Telegram auth, TON wallet, and email verification additions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:20:08 +04:00

9.1 KiB

title, tags, aliases
title tags aliases
Data Model Overview
data-model
mongoose
overview
Models Index
Schema Overview

Data Model Overview

This section documents every Mongoose model that backs the marketplace. The persistence layer lives in backend/src/models/ and is exported through a single barrel file at backend/src/models/index.ts. All models target MongoDB via Mongoose, lean on timestamps: true for createdAt / updatedAt, and follow a consistent pattern: one schema per file, an exported I<Name> TypeScript interface, and named exports for the compiled model.

[!note] Scope Eighteen models are documented here. The "File" concept exists only at the service layer (backend/src/services/file/) and is not persisted as its own Mongoose collection, so it is not listed below.

[!warning] Implementation gap As of the 2026-05-24 audit, the following documented models do not yet have Mongoose schema files in backend/src/models/:

Index of Models

  • User — Core identity. Stores credentials, profile, preferences, referral data, points, and WebAuthn passkeys. Every other model that records "who did what" points back at a User._id. Buyers, sellers, and admins all live in this collection, differentiated by a role enum.
  • PurchaseRequest — The buyer-side document at the heart of the marketplace. Captures what a buyer wants, the budget, urgency, delivery preferences, and the full lifecycle status (pending_paymentseller_paid). Aggregates SellerOffer references and tracks delivery codes.
  • SellerOffer — A seller's bid against a PurchaseRequest. Holds price, delivery ETA, attachments, and a small status machine (pending / accepted / rejected / withdrawn).
  • Payment — Records every monetary movement: buyer pay-in, seller payout, refund. Integrates with the SHKeeper crypto gateway and tracks escrow state plus on-chain transaction metadata.
  • Chat — Conversation container with embedded messages, participants, unread counters, and reactions. Used for direct buyer-seller chats, group chats, and support tickets. Can be linked to a PurchaseRequest or SellerOffer.
  • Notification — Per-user notification with category, type, and 90-day TTL for automatic cleanup. References any related entity by stringified id.
  • RequestTemplate — A seller-authored, sharable template that pre-fills a PurchaseRequest. Carries a public shareable link, usage counter, and an optional default proposal.
  • Dispute — Buyer-raised complaint tied to a PurchaseRequest. Captures evidence uploads, a timeline of admin actions, deadlines, and a structured resolution.
  • BlogPost — Editorial content: title, slug, rich content, media, SEO metadata, view/like counters, and a draft/published/archived workflow.
  • Address — User shipping address book entry. Enforces a single primary address per user via a pre-save hook.
  • Category — Hierarchical product/service taxonomy referenced by PurchaseRequest and RequestTemplate. Supports parent/child via parentId and bilingual name / nameEn.
  • Review — Polymorphic 1-5 star review against either a seller or a RequestTemplate (subjectType discriminator). One review per reviewer per subject (compound unique index).
  • PointTransaction — Ledger of point grants and spends per user. Sources include purchase, referral, bonus, admin grant, and redemption.
  • LevelConfig — Static configuration of loyalty tiers (level number, point thresholds, benefits, icon, color). Driven by admins; consumed by the User.points.level field.
  • ShopSettings — One-to-one storefront branding for a seller: name, description, avatar, cover image, review toggles, and social links.
  • TempVerification — Short-lived signup record that holds candidate user data and a verification code. Auto-purges via TTL when emailVerificationCodeExpires passes.
  • TelegramLink — Permanent auditable association between a Telegram user ID and an Amanat User. Stores Telegram profile metadata, link source (miniapp / bot / login_widget), status (active / blocked), and last-seen timestamp. One per Telegram user (unique on both userId and telegramUserId).
  • TelegramSession — Short-lived Telegram Mini App session token issued when initData is verified. Carries the initDataFingerprint for replay protection and auto-expires via a MongoDB TTL index on expiresAt.

Relationship Diagram

erDiagram
    USER ||--o{ PURCHASE_REQUEST : "creates as buyer"
    USER ||--o{ SELLER_OFFER : "submits as seller"
    USER ||--o{ ADDRESS : "owns"
    USER ||--o{ NOTIFICATION : "receives"
    USER ||--o{ POINT_TRANSACTION : "earns/spends"
    USER ||--o{ REQUEST_TEMPLATE : "authors as seller"
    USER ||--o| SHOP_SETTINGS : "configures"
    USER ||--o{ BLOG_POST : "publishes"
    USER ||--o{ REVIEW : "writes as reviewer"
    USER ||--o{ DISPUTE : "raises as buyer"
    USER ||--o{ USER : "referred by"

    PURCHASE_REQUEST }o--|| CATEGORY : "belongs to"
    PURCHASE_REQUEST ||--o{ SELLER_OFFER : "receives"
    PURCHASE_REQUEST ||--o{ PAYMENT : "settled by"
    PURCHASE_REQUEST ||--o| CHAT : "discussed in"
    PURCHASE_REQUEST ||--o{ DISPUTE : "may trigger"
    PURCHASE_REQUEST ||--o| REVIEW : "rated by buyer"

    SELLER_OFFER ||--o| PAYMENT : "funds"
    SELLER_OFFER }o--|| PURCHASE_REQUEST : "responds to"

    PAYMENT }o--|| USER : "buyer"
    PAYMENT }o--|| USER : "seller"

    CHAT }o--o{ USER : "participants"
    CHAT ||--o{ DISPUTE : "support channel"

    REQUEST_TEMPLATE }o--|| CATEGORY : "belongs to"
    REQUEST_TEMPLATE ||--o{ REVIEW : "rated as subject"

    CATEGORY ||--o{ CATEGORY : "parent of"

    POINT_TRANSACTION }o--|| USER : "owner"
    LEVEL_CONFIG ||..|| USER : "level lookup"

    TEMP_VERIFICATION ||..|| USER : "promoted to"

    TELEGRAM_LINK }o--|| USER : "links identity"
    TELEGRAM_SESSION }o--o| USER : "session for"
    TELEGRAM_SESSION }o--|| TELEGRAM_LINK : "matches"

Conventions Across All Models

[!note] Shared schema patterns

  • Timestamps: every model declares { timestamps: true }, so createdAt and updatedAt are always present.
  • ObjectId references: foreign keys use Schema.Types.ObjectId with an explicit ref (e.g. ref: 'User'). The two exceptions are Notification and Payment which use string-typed or Mixed identifiers in places to support template-flow payments.
  • Soft delete: deletion is modelled as a status flag (e.g. User.status = 'deleted', BlogPost.status = 'archived') rather than physical removal.
  • TTL indexes: short-lived collections (Notification, TempVerification) use { expireAfterSeconds: ... } so MongoDB does the cleanup.
  • toJSON sanitisation: User overrides toJSON to strip credentials, refresh tokens, and verification codes before serialisation.

[!warning] Index discipline Several schemas leave a comment noting that unique: true already creates an index — adding schema.index({ field: 1 }) on top would produce a duplicate-index warning at startup. When introducing new indexes, search for unique: true first.

Lifecycle View

The dominant happy-path flow exercises five collections in order:

  1. A buyer (User) creates a PurchaseRequest with status: 'pending'.
  2. Sellers (other Users) attach SellerOffer documents; the request transitions through received_offersin_negotiation as the parties chat in a Chat.
  3. The buyer accepts an offer; a Payment is opened against the SHKeeper provider with escrowState: 'funded'.
  4. The seller marks the request deliverydelivered; the buyer confirms with the 6-digit deliveryCode and the request becomes completed.
  5. The escrow Payment flips to released and a payout Payment (direction: 'out') is issued. Optionally the buyer writes a Review and earns a PointTransaction.

If anything goes sideways, the buyer can open a Dispute (planned but not yet implemented), which would freeze the flow until an admin resolves it (refund, replacement, compensation, or no-action).

How to Navigate

Each model has its own note in this folder. Cross-references use [[wikilinks]] so backlinks work in Obsidian's graph view. Schemas are documented at field-level granularity — every field is listed with its type, default, validation, and indexing decisions. Where a model carries a meaningful state machine, a Mermaid stateDiagram-v2 accompanies the schema table.

[!note] Source of truth The information below is mirrored from the TypeScript schema definitions. If a field listed here disagrees with the code, the code wins — please update the note. All source citations use the form backend/src/models/<File>.ts:<line>.