2.0 KiB
Great—time-accurate historical data is exactly what the “effective-dated assignment” approach is for.
Recommended flow (historical accuracy)
1) Model “which branch the user belonged to when”
Use a history table, e.g. user_branch_assignments:
user_idbranch_idstarts_atends_at(nullable;null= current)- timestamps
Your rule for history:
- For any
user_id, at a given timestamp, exactly one assignment row is “active” (starts_at <= tand (ends_atis null ort < ends_at)).
2) Model branch-specific activities against the assignment
For any activity that should be tied to the user’s branch “at the time it happened”, store:
user_branch_assignment_id(FK)occurred_at(the activity time)- activity fields
When creating an activity at time occurred_at, you must pick the assignment row that was active at that time.
Transfer logic (what happens at transfer time)
At transfer time T:
- Close current assignment (branch A):
- set
ends_at = T
- set
- Create new assignment (branch B):
- set
starts_at = T ends_at = null
- set
From then on:
- old activities remain linked to the old assignment
- new activities link to the new assignment
Query pattern you’ll use
- “Current branch for a user”:
- assignment where
ends_at is null
- assignment where
- “Activities for a user in branch X at time range” (historical):
- join activities →
user_branch_assignmentsand filter bybranch_id
- join activities →
Laravel-specific implementation note (important)
When inserting an activity with occurred_at, do this in a transaction:
- read the assignment active at
occurred_at - create the activity pointing to
user_branch_assignment_id
Optionally lock the user’s assignment rows to avoid edge-case races around the transfer timestamp.
If you share your current activity table name + the column you use for the activity time (e.g. created_at vs occurred_at), I can sketch the exact Laravel query/transaction structure.