Cycle de vie d’une offre
Une offre traverse quatre états principaux : DRAFT → PUBLISHED → CLOSED → ARCHIVED.
Diagramme d’états
États détaillés
| État | Visible public | Candidatures | Indexée FTS | Dashboard recruteur |
|---|
DRAFT | Non | Non | Non | Oui |
PUBLISHED | Oui | Oui | Oui | Oui |
CLOSED | Oui (profil entreprise) | Non | Non | Oui |
ARCHIVED | Non | Non | Non | Oui (filtre “archivées”) |
Transitions autorisées
Validations à la publication
Modifications en PUBLISHED
Certains champs sont verrouillés une fois publié pour éviter le bait-and-switch :
| Champ | Modifiable en PUBLISHED |
|---|
titre | Non |
typeContrat | Non |
ville | Non |
salaireMin/Max | Non (sauf prolongation par admin) |
description | Oui |
competencesRequises | Oui |
dateExpiration | Oui (future uniquement) |
Pour changer un champ verrouillé, il faut unpublish → modifier en DRAFT → publish à nouveau. Les candidatures existantes restent attachées.
Expiration automatique
Quota offres actives par plan
| Plan | Max PUBLISHED simultanément |
|---|
| Gratuit | 2 |
| Essentiel | 10 |
| Pro | 50 |
| Entreprise | ∞ |
Impact sur les candidatures
Suppression
Une offre PUBLISHED ne peut pas être supprimée — seulement archivée. Une offre DRAFT peut être supprimée. Une offre ARCHIVED peut être supprimée après 30 jours pour laisser le temps de contester.
Événements émis
| État source | État cible | Événement | Notif email |
|---|
| * | PUBLISHED | offre.published | Abonnés alertes matchantes |
| PUBLISHED | CLOSED (auto) | offre.expired | Recruteur |
| PUBLISHED | CLOSED (manuel) | offre.closed | – |
| * | ARCHIVED | offre.archived | – |
Traces audit
Chaque transition d’état est loggée dans offres_status_history :
CREATE TABLE offres_status_history (
id BIGSERIAL PRIMARY KEY,
offre_id BIGINT REFERENCES offres(id),
from_status VARCHAR(20),
to_status VARCHAR(20),
changed_by BIGINT REFERENCES users(id),
changed_at TIMESTAMPTZ DEFAULT NOW(),
reason TEXT
);