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}/faqsif 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.