Skip to main content

Module contractor_evaluation

Module contractor_evaluation 

Source
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

  1. A syndic (or a mandated owner) opens an evaluation against a contractor user once a TechnicalSpec has reached TechnicalSpecStatus::Approved.
  2. The evaluator fills the 5 scores (EvaluationScores) and writes a comment.
  3. 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 SMALLINT CHECK in 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§

ContractorEvaluation
EvaluationScores
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.

Constants§

MAX_COMMENT_LEN
MAX_LINKED_TICKETS
MAX_SCORE
MIN_COMMENT_LEN
MIN_SCORE