Modèle de données
Postgres 16 + pgvector (embeddings 1024-d) + PostGIS (geography(Point, 4326)), via Drizzle ORM. Le schéma fait foi : apps/api/src/db/schema.ts. Les
migrations vivent dans apps/api/drizzle/ (la migration initiale installe
l'extension vector).
Il n'y a pas de table users — l'identité vit dans Auth0. Les FK logiques
vers les utilisateurs sont des user_id = sub Auth0 (texte), non contraints.
Enums Postgres
| Enum | Valeurs |
|---|---|
tracking_status | contacted, doing, done, refused |
notification_status | queued, sent, no_contact, failed |
service_source | user, google_scrape |
import_status | pending, running, done, failed |
tracking_status ≠ statut dashboardL'enum bas niveau tracking_status (contacted/doing/done/refused) est
l'état backend. Côté dashboard web, les pills de demandes
(a-valider/en-cours/terminee) sont une projection UI ; ne pas confondre les
deux. Voir apps/web.
Invariants notables
- Slugs immuables :
services.slugetuser_profiles.slugsont écrits une fois et jamais régénérés (stabilité des URLs = invariant SEO). Cf.apps/api/src/lib/slug.ts. - Images ≤ 3 : check
cardinality(images_url) <= 3surtasksetservices. - Une review par (task, author) : index unique
reviews_task_author_uidx;ratingcontraint entre 1 et 5. - Un tracking par (task, service) : index unique
trackings_task_service_uidx. - Snapshots de review :
author_name/author_picturesont figés à la création (pas de relookup Auth0 par ligne).