Schema

Suggested Firestore schema based on Categories and Products pages and docs/openapi.json.

This page is only to help during development — not for production use.

Overview

Collections are scoped by userId (or organizationId for multi-tenant). Use Firestore security rules to restrict read/write by auth uid.

Collections:

  • categories — list + detail (Main, metadata, FAQs embedded)
  • products — list + detail (Main, metadata, FAQs embedded)

categories

Supports GET list, GET detail, PATCH Main/Metadata, PUT FAQs. Main + metadata + FAQs embedded (keeps reads simple; doc limit ~1MB is plenty for typical FAQs).

{
  // ——— List fields (from GET /api/categories) ———
  id: string,
  userId: string,
  organizationId?: string,
  name: string,
  createdAt: Timestamp,
  updatedAt: Timestamp,
  visibility?: number,      // 0–100
  position?: number,
  promptsCount?: number,
  trend?: "up" | "stable" | "down",

  // ——— Main tab (PATCH /api/categories/{id}) ———
  locales?: {
    en: {
      name?: string,
      description?: string,
      keyPhrases?: string,
      uniqueValue?: string,
      useCase?: string
    },
    ar: { ... }
  },

  // ——— Meta tab (PATCH /api/categories/{id}/metadata) ———
  metadata?: {
    title?: { en?: string, ar?: string },
    description?: { en?: string, ar?: string },
    canonical?: string,
    schemaType?: string,
    robots?: string,
    hreflang?: Array<{ lang: string, url: string }>
  },

  // ——— FAQs (PUT /api/categories/{id}/faqs) ———
  faqsEn?: Array<{ id: string, question: string, answer: string }>,
  faqsAr?: Array<{ id: string, question: string, answer: string }>
}

products

Same shape as categories, plus categoryId and shortDesc in Main.

{
  // ——— List fields ———
  id: string,
  userId: string,
  organizationId?: string,
  categoryId: string,
  name: string,
  description?: string,
  createdAt: Timestamp,
  updatedAt: Timestamp,
  visibility?: number,
  position?: number,
  promptsCount?: number,
  trend?: "up" | "stable" | "down",

  // ——— Main (products add shortDesc in locales) ———
  locales?: {
    en: {
      name?: string,
      shortDesc?: string,
      description?: string,
      keyPhrases?: string,
      uniqueValue?: string,
      useCase?: string
    },
    ar: { ... }
  },

  metadata?: { ... },
  faqsEn?: Array<{ id: string, question: string, answer: string }>,
  faqsAr?: Array<{ id: string, question: string, answer: string }>
}

Indexes & queries

  • categories — Composite: (userId, createdAt) or (userId, position) for list; single doc read for detail by id.
  • products — Composite: (userId, categoryId), (userId, createdAt); filter by categoryId for list.

Alternatives

  • FAQs as subcollection — Use categories/{id}/faqs if you expect many FAQs per entity (>50) or need per-FAQ audit. Then PUT would write/delete docs in the subcollection.
  • Metadata separate — Usually unnecessary; metadata is small. Embedding avoids extra reads.

API contract: docs/openapi.json in repo.