6.0 KiB
Domain model
Schedules vs assignments
A schedule describes when a duty exists and how its initial assignee is chosen. An assignment is the actual duty on a concrete date. Once an assignment exists, it is not recalculated from the schedule.
This distinction is intentional: editing a rotation must not retroactively change an already published month.
Seeded schedules
Seeded names are Portuguese (Noite, Almoço - Sábados, Almoço - Domingo); the slugs stay night, saturday-lunch and sunday-lunch.
Night (Noite)
- Exists every day (
MondaythroughSunday). - Type:
fixed. - Configured once as a repeating monthly pattern: one person per calendar day of the month (1 to 31), configured on
/admin/schedules/<night id>. - Generation fills a missing assignment with the person configured for that day of the month. Days 29 to 31 only apply to months that have them.
- There is no per-month configuration for Night: the same pattern is used every month.
- Existing assignments are never rewritten by a pattern change; they keep the person they already had.
Saturday Lunch (Almoço - Sábados)
- Saturdays only.
- Type:
rotation. - Has its own ordered member list.
- Continues after the previous assigned person's position in the rotation, including across month boundaries. The anchor date is the fallback when there is no usable previous assignee.
Sunday Lunch (Almoço - Domingo)
- Sundays only.
- Type:
rotation. - Has its own ordered member list, independent of Saturday.
The data model supports a schedule matching multiple weekdays even though the seeded lunch schedules each use one day.
Rotation generation
For a rotation schedule, use the last assigned person on an earlier date in that same schedule as the reference. Choose the next active member after that person's position in the current rotation order, wrapping to the beginning. Unassigned dates are skipped when finding the reference. Manual assignments and completed swaps also supply the reference for later dates. Saturday and Sunday never use each other's assignees.
Inactive members are skipped as recipients, but their position can still supply the reference if they remain in the rotation. When no previous assignee exists, or that person has been removed from the rotation, fall back to the number of matching schedule days from the anchor date modulo the active member count. An empty active rotation leaves the shift unassigned.
Generation and explicit month/range application process dates chronologically, so each newly assigned date supplies the reference for the next date. Regenerating one assignment only recalculates that date; later existing assignments remain unchanged until an administrator explicitly applies the rotation.
Only missing assignments are generated. Existing rows are never rewritten.
An administrator can explicitly Apply rotation on a lunch schedule's month page. This recalculates that month's generated assignments using the current active rotation members and fills missing dates for that schedule. Manual assignments and completed swaps are preserved. Simply editing the rotation order still does not rewrite any assignment.
Every assignment on a lunch schedule page has a Regenerate button. An administrator can explicitly regenerate any assignment, including an automatic assignment, manual override, or completed swap. It immediately recalculates that date from the current rotation and its source becomes generated; if there are no active rotation members, it becomes unassigned. These actions preserve assignment IDs, notes, and completed request history. If ownership changes, open or pending-approval change requests for the assignment are cancelled, and assignment-change notifications are attempted after saving.
Generate after date fills missing shifts and recalculates automatic assignments in that schedule strictly after the selected reference date, through an explicit end date (inclusive). The range can span multiple months. Assignments on or before the reference date and after the end date are not edited. Manual assignments and completed swaps within the range are preserved and supply references for later dates. The default range covers the displayed month.
People and logins
emailandphoneare optional.- A username and password are optional, but they are all-or-nothing: a person can either sign in or be rota-only. A username without a password (or the reverse) is not allowed, and a person without credentials can never sign in.
- A username, when set, is unique.
- Rota-only people can be assigned by an administrator, appear in rotations, and can be named as the target of a change request, but cannot accept it; an administrator completes the transfer on the schedule's own configuration page.
- A person cannot remove their own login.
Access
/is the rota and is the landing page for everyone, signed in or not. Signed-out visitors see the month read-only: no "mine" highlighting, no change-request actions.- Change requests,
/swaps, and every/adminpage still require a signed-in, active account.
Change request state machine
open → pending_approval → approved
Other terminal states: rejected, cancelled.
- A member can offer one of their future/current assignments to a specific active member or to anyone.
- The requester cannot accept their own request.
- A targeted request can only be accepted/rejected by that target.
- An open request can be accepted by any other active member who can sign in.
- If the schedule requires manager approval, acceptance moves to
pending_approval. - Approval transfers the assignment and sets its source to
swap. - If the requester no longer owns the assignment, the request must not be applied.
Notifications
Email is optional per user and per installation.
Events include:
- assignment updated/removed by admin;
- change requested;
- change accepted;
- manager approval required;
- change approved/rejected;
- shift reminder.
An email error is logged but must not undo a scheduling action.