Skip to main content

Firestore data model

Firestore is Vessl's single data store. The client reads it through real-time listeners and writes through it directly for authenticated mutations, with security rules in firestore.rules enforcing who can read and write each collection. Composite indexes are declared in firestore.indexes.json.

Collections

The schema is intentionally flat — top-level collections keyed by document id, related by reference fields rather than deep nesting.

CollectionHoldsAccess shape
carsVehicle inventory recordsPublic read; admin write
categoriesInventory categoriesPublic read; admin write
blog_postsBlog articlesPublic read (published); admin write
offersPromotional offersPublic read; admin write
usersUser profiles and preferencesOwner read/write; admin read
consultationsBooked consultationsOwner + admin
inquiriesQuote and contact inquiriesOwner + admin
leadsCRM leadsAdmin
appointmentsScheduled appointmentsAdmin
inventory_eventsStock changes and movementsAdmin
segmentsMarketing audience segmentsAdmin
sequencesMarketing message sequencesAdmin
sequence_runsExecuted sequence stepsAdmin / Worker
teamsOperator teamsAdmin
invitesTeam invitationsAdmin / Worker
tenantsMulti-tenant configurationsAdmin / resolver Worker
settingsApplication and tenant settingsAdmin
activitiesActivity feed entriesScoped
audit_logImmutable record of sensitive actionsAppend-only; admin read

Ownership and security rules

Customer-owned records — consultations, inquiries, favorites, and the user's own profile — are readable and writable only by their owner, identified by request.auth.uid, with admins granted broader read for operations. Public catalog data (cars, categories, published blog posts, offers) is world-readable but write-restricted to roles with the matching permission. The audit_log is append-only so history cannot be rewritten. Writes are run through a stripUndefined sanitizer before they reach Firestore to keep documents clean.

Real-time by default

Reads use onSnapshot so the UI reflects changes immediately — a new lead appears in the pipeline, a status change shows in the customer dashboard — without manual refresh. One-time getDoc/getDocs reads are reserved for exports and server-side code.

Frequently asked questions

Are documents nested or flat? Flat. Collections are top-level and relate through reference fields, which keeps security rules and indexes simple.

How is customer data protected? Security rules scope owner-only collections to request.auth.uid, so a customer can read only their own consultations, inquiries, and profile.

Where are indexes defined? In firestore.indexes.json, deployed with firebase deploy --only firestore:indexes.