pub async fn run(
pool: &PgPool,
actor: &Actor,
project_id: Uuid,
plan: &SeasonPlan,
) -> AppResult<SeasonReport>Expand description
Runs a season handover plan on one group.
§Invariants
- Permission: the group is visible to the actor (“not found”
otherwise) and the actor manages it (or is an administrator; 403);
every step is checked again by its own service
(
projects::add_member,checkouts::release_held_because,projects::demote_manager,projects::set_member_expiry,projects::remove_member), so need-to-know rules (an administrator cannot add themselves) and “at least one active manager” hold. - Data: the chosen people must be members of the group (400 before
anything changes); at most
MAX_MEMBERSper list (400); an empty plan is refused (400); a reason is checked before anything changes (400). - Order: new lead → releases → “member until” → removals → demotions, so the lead is a manager before the old ones step down, locks are released while their holders are still members, and a manager who demotes themselves keeps the right to run the other steps.
- Audit / notifications: those of each step, per object.
- Atomic: one transaction per step; refused steps are reported and do not stop the others.