ViteComm is a multi-vendor marketplace: clients order, vendors sell, drivers deliver, admins oversee. Four roles, one login. The cleanest way I found to model that in Prisma with MySQL is a single user table with one-to-one role extensions.
One table per role, linked 1:1
Every account is a Utilisateur. Each role is its
own model sharing the user's primary key:
model Utilisateur {
id_user Int @id @default(autoincrement())
nom String
prenom String
email String @unique
statut_compte String @default("Actif")
est_admin Boolean @default(false)
client Client?
vendeur Vendeur?
livreur Livreur?
}
model Client {
id_user Int @id
utilisateur Utilisateur @relation(fields: [id_user], references: [id_user], onDelete: Cascade)
adresse_livraison String
}
A user can wear several hats over time — a client who becomes a vendor keeps one identity, one password, one notification inbox. Roles become data, not accounts.
Reports need both sides
Marketplaces need moderation, and moderation needs context. A report always has an author and a target, so the relation is declared twice:
signalementsAuteur Signalement[] @relation("SignalementsAuteur")
signalementsCible Signalement[] @relation("SignalementsCible")
Naming both sides explicitly keeps queries readable: reports filed by a user versus reports against them. Prisma requires the disambiguation anyway — lean into it and make the names tell the story.
Push over polling
Order updates, driver assignments, admin notices — a marketplace
that polls for these feels dead. The schema carries a
PushSubscription model next to
Notification, so new events travel outward instead
of being asked for. The frontend stays a thin subscriber; the
database stays the source of truth.
Names in the domain language
The schema is written in French — Utilisateur,
Commande, Panier — because the
merchants and drivers who will one day read exports and invoices
think in French. An ORM schema is also documentation; write it
in the language of the people it serves.
Takeaway
Marketplace schemas fail when roles become separate user tables (duplicate identities) or when moderation is an afterthought (no counters, no context). Model identity once, extend per role, and give every report two sides from day one.