ReferenceUpdated 2026-03-26 MyClaude uses 13 Firestore collections with camelCase naming, server-side order creation via Stripe webhooks, atomic username uniqueness, and XP deduplication logs.
Property Value Database Cloud Firestore Project claude-code-vaultRegion us-central1Naming convention camelCase Schema version 1.1.0 Total collections 13 (8 root + 5 subcollection groups)
All timestamps use Firestore server timestamps. All counters use FieldValue.increment() for atomic updates. Document IDs follow the convention noted per collection.
User profiles for creators, buyers, and admins. Document ID is the Firebase Auth UID.
Field Type Required Default Description uidstring yes — Firebase Auth UID emailstring yes — Account email (never exposed to client) usernamestring yes — Unique, lowercase, 3-30 chars. Pattern: ^[a-z0-9_-]{3,30}$ displayNamestring yes — Public display name (max 100 chars) biostring no — Profile bio (max 500 chars) avatarUrlstring no — Firebase Storage URL countrystring no — Two-letter country code localestring no "en"Preferred language (en, pt-BR, es)
Field Type Required Default Description rolestring no "user"One of: user, creator, verified_creator, admin rankstring no — Current gamification rank ID verifiedboolean no falseManually verified by admin bannedboolean no falseAccount is banned bannedBystring no — UID of admin who issued ban bannedAttimestamp no — When ban was issued statusstring no — Set to "deleted" on account deletion
Field Type Required Default Description stripeAccountIdstring no nullStripe Connect Express account ID stripeOnboardedboolean no falseOnboarding completed
Field Type Required Default Description xpnumber yes 0Total experience points levelnumber yes 0Current level
Denormalized counters updated server-side via increment().
Field Type Default Description stats.followersnumber 0Follower count stats.followingnumber 0Following count stats.productsnumber 0Published products stats.downloadsnumber 0Total downloads received stats.likesnumber 0Total likes received stats.totalRevenuenumber 0Lifetime revenue in cents (USD) stats.totalSalesnumber 0Total products sold stats.reviewsReceivednumber 0Reviews received across all products stats.avgRatingnumber 0Weighted average rating stats.messagesSentnumber 0Messages sent in conversations stats.productsBoughtnumber 0Products purchased stats.achievementCountnumber 0Achievements unlocked stats.categoryCountmap {}Per-category product count, e.g. {skills: 3, agents: 1}
Field Type Required Description createdAttimestamp yes Server timestamp at creation updatedAttimestamp yes Server timestamp at last update
Operation Rule Read Public Create auth.uid == userIdUpdate auth.uid == userId (cannot modify stripeAccountId, stripeOnboarded)Delete Never (soft delete via account deletion endpoint)
Tracks who this user follows. Document ID is the target user's UID.
Field Type Description createdAttimestamp When the follow occurred
Tracks who follows this user. Document ID is the follower's UID.
Field Type Description createdAttimestamp When the follow occurred
Unlocked achievements for the user.
Field Type Description titlestring Achievement name descriptionstring What the user did to earn it iconstring Icon identifier tierstring One of: bronze, silver, gold, diamond unlockedAttimestamp When unlocked
In-app notifications. Auto-generated document ID.
Field Type Required Default Description typestring yes — One of: purchase, download, follow, review, achievement, message, refund, system titlestring yes — Notification headline bodystring no — Notification detail text linkstring no — Internal route to navigate to readboolean yes falseHas user seen this actorUidstring no — UID of user who triggered this actorUsernamestring no — Username of triggering user createdAttimestamp yes — Server timestamp
Published artifacts (skills, squads, agents, etc.). Document ID is auto-generated by Firestore.
Field Type Required Default Description titlestring yes — Product name (max 120 chars) slugstring yes — URL-safe identifier, immutable after creation descriptionstring yes — Short description (max 5,000 chars) readmestring no — Markdown content for product page (max 50,000 chars)
Field Type Required Default Description categorystring yes — One of: skills, squads, agents, workflows, design-systems, claude-md, prompts, applications, systems tagsarray<string> no — Up to 10 tags
Field Type Required Default Description pricenumber yes 0Price in USD (0 = free). Stored as float, converted to cents for Stripe currencystring no "usd"Currency code
Field Type Required Description fileUrlstring yes R2 storage key or legacy Firebase Storage path. Never exposed to client for paid products. fileNamestring yes Original filename fileSizenumber yes File size in bytes thumbnailUrlstring no Product thumbnail URL
Field Type Required Description authorUidstring yes Author's Firebase UID authorUsernamestring yes Author's username authorDisplayNamestring yes Author's display name authorAvatarstring no Author's avatar URL
Field Type Required Default Description statusstring yes "pending_review"One of: draft, pending_review, published, archived, removed approvedBystring no — Admin UID who approved approvedAttimestamp no — Approval timestamp removedBystring no — Admin UID who removed removedAttimestamp no — Removal timestamp
Status lifecycle: Client creates always set pending_review (enforced by Firestore rules). Only Admin SDK can set published or removed.
Field Type Required Default Description versionstring no "1.0.0"Semantic version changelogstring no — Changelog text (max 2,000 chars) licensestring no "MIT"One of: MIT, Apache-2.0, GPL-3.0, BSD-3-Clause, ISC, CC-BY-4.0, CC-BY-SA-4.0, CC0-1.0, Proprietary, Custom
Present on CLI-published products that have been processed by the CONDUIT content pipeline.
Field Type Required Description mcsLevelnumber no MCS certification level (1-5) languagestring no Primary language of the product longDescriptionstring no Extended description from CONDUIT enrichment installTargetstring no Install target path compatibilitymap no Compatibility info, e.g. {claudeCode: ">=1.0"} dependenciesmap no Dependency info, e.g. {myclaude: ["other-skill"]}
Denormalized counters. Updated server-side only — Firestore rules block client writes to stats.
Field Type Default Description stats.downloadsnumber 0Download count stats.likesnumber 0Like count stats.ratingnumber 0Average rating (1-5) stats.reviewsCountnumber 0Number of reviews stats.purchaseCountnumber 0Number of purchases
Field Type Required Description createdAttimestamp yes Server timestamp at creation updatedAttimestamp yes Server timestamp at last update
Operation Rule Read Public Create Authenticated + authorUid == auth.uid + status must be pending_review Update authorUid == auth.uid (cannot change status, authorUid, or stats)Delete authorUid == auth.uid
One document per user per product. Document ID is the user's UID.
Field Type Description createdAttimestamp When the like occurred
Version history. Each file upload creates a version record.
Field Type Description versionstring Semantic version string fileUrlstring R2 storage key for this version fileNamestring Filename fileSizenumber Bytes changelogstring What changed createdAttimestamp Upload timestamp
Product reviews. Created server-side after purchase/download verification.
Field Type Required Description authorUidstring yes Reviewer's UID authorUsernamestring yes Reviewer's username authorDisplayNamestring no Reviewer's display name authorAvatarstring no Reviewer's avatar URL ratingnumber yes 1-5 stars commentstring yes Review text (max 1,000 chars) createdAttimestamp yes Server timestamp
Per-user download tracking. Used for review eligibility. Server-side only.
Field Type Description uidstring User's UID downloadedAttimestamp Server timestamp
Purchase records. Created exclusively by the Stripe webhook — never from client-side code. Document ID is the Stripe session ID (ensures idempotency).
Field Type Required Description buyerUidstring yes Buyer's Firebase UID sellerUidstring yes Seller's Firebase UID
Field Type Required Description productIdstring yes Product document ID productTitlestring yes Product name at time of purchase productCategorystring yes Product category at time of purchase
Field Type Required Description amountnumber yes Total charged platformFeenumber yes Platform cut sellerAmountnumber yes Seller receives currencystring yes Currency code (default "usd")
Field Type Required Description stripeSessionIdstring yes Checkout session ID stripePaymentIntentIdstring no Payment intent ID
Field Type Required Description statusstring yes One of: completed, refunded, disputed refundedAttimestamp no When refund was processed
Field Type Required Description createdAttimestamp yes Server timestamp updatedAttimestamp yes Server timestamp
Operation Rule Read buyerUid == auth.uid OR sellerUid == auth.uidCreate Never from client (webhook transaction only) Update Never from client (webhook transaction only) Delete Never
Buyer-seller messaging threads. Document ID format: {productId}_{buyerUid}.
Field Type Required Default Description productIdstring yes — Related product productTitlestring yes — Product name productSlugstring yes — Product slug for linking buyerUidstring yes — Buyer's UID buyerUsernamestring yes — Buyer's username buyerDisplayNamestring yes — Buyer's display name buyerAvatarstring no — Buyer's avatar URL sellerUidstring yes — Seller's UID sellerUsernamestring yes — Seller's username sellerDisplayNamestring yes — Seller's display name sellerAvatarstring no — Seller's avatar URL participantsarray<string> yes — [buyerUid, sellerUid] for array-contains querieslastMessagestring no — Preview text (max 100 chars) lastMessageAttimestamp yes — Timestamp of most recent message lastMessageSenderUidstring no — UID of last message sender unreadBySellernumber — 0Unread count for seller unreadByBuyernumber — 0Unread count for buyer createdAttimestamp yes — Server timestamp
Operation Rule Read auth.uid in participants arrayCreate Server-side only Update Server-side only Delete Never
Individual messages within a conversation.
Field Type Required Description senderUidstring yes Sender's UID senderUsernamestring yes Sender's username senderDisplayNamestring yes Sender's display name senderAvatarstring no Sender's avatar URL textstring yes Message body (max 1,000 chars) createdAttimestamp yes Server timestamp
Atomic username uniqueness registry. Document ID is the lowercase username string. Admin SDK only — no client reads or writes.
Field Type Required Description uidstring yes UID of the username owner claimedAttimestamp yes Server timestamp
All operations: Admin SDK only. Client reads and writes are denied.
Content reports for moderation. Auto-generated document ID.
Field Type Required Default Description reporterUidstring yes — UID of reporter targetTypestring yes — One of: product, review, user targetIdstring yes — ID of reported entity reasonstring yes — One of: malicious_content, spam, inappropriate, copyright, other descriptionstring no — Details (max 1,000 chars) statusstring yes "pending"One of: pending, resolved, dismissed resolvedBystring no — Admin UID who resolved resolvedAttimestamp no — Resolution timestamp createdAttimestamp yes — Server timestamp
Operation Rule Read Admin only (Admin SDK) Create Authenticated + reporterUid == auth.uid Update Admin only (Admin SDK) Delete Never
XP award deduplication. Document ID format: {uid}_{action}_{dedupKey}. Prevents double-awarding XP for the same action.
Field Type Required Description actionstring yes XP action type amountnumber yes XP awarded uidstring yes User UID createdAttimestamp yes When XP was awarded
Operation Rule Read Owner only (logId prefix matches auth.uid) Create Owner only (logId prefix matches auth.uid) Update Never Delete Never
Security-relevant action log. Admin SDK only , fire-and-forget. Auto-generated document ID.
Field Type Required Description actionstring yes Action performed uidstring yes UID of actor detailsmap no Additional context timestamptimestamp yes Server timestamp
All operations: Admin SDK only. No client access.
Firestore-backed rate limiting for serverless API routes. Document ID format: {ip}__{path}. Admin SDK only .
Field Type Required Description countnumber yes Request count in current window resetAtnumber yes Unix timestamp (ms) when window resets ipstring yes Client IP address pathstring yes API route path
All operations: Admin SDK only. No client access.
Fields Purpose status ASC, createdAt DESCExplore page — newest first status ASC, stats.likes DESCExplore page — most liked status ASC, stats.downloads DESCExplore page — most downloaded status ASC, stats.rating DESCExplore page — highest rated status ASC, category ASC, createdAt DESCCategory filter — newest status ASC, category ASC, stats.likes DESCCategory filter — most liked status ASC, category ASC, stats.downloads DESCCategory filter — most downloaded authorUid ASC, createdAt DESCAuthor dashboard authorUsername ASC, status ASC, createdAt DESCPublic profile page authorUid ASC, status ASC, createdAt DESCAuthor page (UID variant)
Fields Purpose sellerUid ASC, createdAt DESCSeller sales dashboard buyerUid ASC, createdAt DESCBuyer purchase history productId ASC, buyerUid ASC, status ASCPurchase verification (download auth) buyerUid ASC, status ASC, createdAt DESCFiltered purchase history
Fields Purpose participants ARRAY_CONTAINS, lastMessageAt DESCUser's conversation list productId ASC, sellerUid ASC, lastMessageAt DESCProduct-specific threads
Fields Purpose status ASC, createdAt DESCAdmin moderation queue reporterUid ASC, targetType ASC, targetId ASCDuplicate report check reporterUid ASC, createdAt ASCReporter history
Product files and user assets are stored across two systems:
System Content Access Cloudflare R2 Product files (products/{key}/{fileName}) Presigned URLs only (5-30 min expiry) Firebase Storage Avatars (users/{uid}/**), thumbnails (products/{id}/thumbnails/) Public read for images Firebase Storage (legacy) Old product files (products/{id}/files/) allow read: if false (signed URLs only)
Max file size: 50MB for product files, 5MB for images. Images restricted to image/* content type.
Buyer clicks "Buy"
→ POST /api/stripe/checkout (Bearer token)
→ Server verifies auth token
→ Server creates Stripe Checkout Session
→ Buyer redirected to Stripe payment page
→ Buyer completes payment
→ Stripe fires webhook
→ POST /api/stripe/webhooks
→ Server creates order document (Firestore transaction)
→ Server increments product stats.purchaseCount
→ Server increments seller stats.totalSales + totalRevenue
→ Server increments buyer stats.productsBought
→ Buyer returns to product page
→ Client checks order exists for user+product
→ Download button becomes available
User clicks "Download"
→ POST /api/products/download (Bearer token)
→ Server verifies auth token
→ If paid: server checks order exists (buyerUid + productId)
→ If free: server allows
→ Server generates presigned R2 URL (5 min expiry)
→ Server records download in products/{id}/downloads/{uid}
→ Server increments product stats.downloads
→ Server increments author stats.downloads
→ Returns signed URL
→ Client opens URL in new tab
Creator submits product form
→ Client uploads file to R2 via presigned upload URL
→ Client uploads thumbnail to Firebase Storage
→ Client creates product document (status: "pending_review")
→ Firestore rules enforce status == "pending_review"
→ Admin reviews product (Admin SDK)
→ Admin sets status to "published"
→ Product appears in explore page
User clicks "Write Review"
→ POST /api/products/reviews (Bearer token)
→ Server verifies auth token
→ Server checks download record exists (review eligibility)
→ Server creates review in products/{id}/reviews/{reviewId}
→ Server recalculates product stats.rating + stats.reviewsCount
→ Server increments author stats.reviewsReceived
→ Server recalculates author stats.avgRating
Two safe types strip sensitive fields before passing data to client components:
Type Omits Purpose SafeProductfileUrlPrevents client from accessing paid product files directly SafeUserProfileemail, stripeAccountId, stats.totalSales, stats.totalRevenueProtects PII and financial data
Server components fetch full documents, strip fields, then pass SafeProduct or SafeUserProfile to client islands.