Expand description
ContractorEvaluation — append-only rating of a contractor’s prestation
on an approved TechnicalSpec (Story 3.9 — FR34 FR35 INV-21 INV-24).
Distinct from ContractEvaluation (module retiré depuis ; la distinction
reste utile, le lien ne pointait plus nulle part),
which is the legacy marketplace-rating entity (Issue #276). The two live
side-by-side intentionally: Story 3.9 only introduces the new audit-grade
flow gated by a signed TechnicalSpec; the legacy free-form rating remains
for the marketplace use-case.
§Workflow
- A syndic (or a mandated owner) opens an evaluation against a
contractor user once a
TechnicalSpechas reachedTechnicalSpecStatus::Approved. - The evaluator fills the 5 scores (
EvaluationScores) and writes a comment. - The row is persisted append-only — there are no public setters and a DB trigger blocks UPDATE / DELETE.
§Invariants enforced at new() time
- every score MUST be in
[1, 5](matches the SMALLINTCHECKin the migration); linked_ticket_ids.len()≤MAX_LINKED_TICKETS, no duplicates;comment.len()∈[MIN_COMMENT_LEN, MAX_COMMENT_LEN](after trim);evaluator_user_id != contractor_user_id(no self-evaluation — INV-21);- no nil UUIDs (defensive — surface a 400 instead of an FK error at persistence time).
Note: the additional invariant “the referenced TechnicalSpec MUST be
in Approved status” lives at the use-case boundary
(crate::application::use_cases::contractor_evaluation_use_cases) —
it is a workflow guard, not a structural one.
Structs§
- Contractor
Evaluation - Evaluation
Scores - 5 dimensions rated on a 1..=5 Likert scale. The “overall” dimension is stored explicitly (not computed) because the evaluator may weigh the dimensions differently in their head — we don’t want to surface a stale arithmetic average as the headline number.