Skip to content

Employee monthly schedules

Status: Implemented (API + UI).
Last updated: July 11, 2026

Monthly work schedules drive working_days per employee per month. That count feeds attendance KPIs and other scorecard logic once wired (see Next integrations).


Collections

CollectionPurpose
tbl_scorecard_configDay codes document _id: schedule-day-codes (field codes[])
tbl_employee_schedulesOne document per employee per month

Schedule document id: {employee_id}:{YYYY}-{MM}

Fields:

FieldDescription
employee_id, year, monthIdentity
working_daysCached count of days whose code_id maps to is_working_day: true
days[]Per calendar day: day, code_id, time_ranges[]

Legacy documents may still store code (abbreviation) on a day; the API migrates to code_id on read when possible.


Day codes (catalog)

Each catalog row has:

FieldDescription
idStable ID (employee cells reference this, not the abbreviation)
codeShort label on the grid (e.g. WD, OFF)
descriptionLong label
is_working_dayWhen true, the day counts toward working_days (attendance KPI)
is_task_delivery_dayWhen true, the day is a task-delivery workday (BSC quantity KPI + scorecard grid). Defaults to is_working_day when omitted on legacy rows. VL and SL default to is_task_delivery_day: true but is_working_day: false.
sort_orderConfig UI ordering

Empty cells (no code_id) are non-working and have no times.

Configured at Scorecard → Configurations → Schedule Day Codes.


Time ranges

Optional shift times per day (time_ranges[]):

FieldDescription
start_minutesMinutes from midnight (0 = 12:00 AM)
end_minutesExclusive end (e.g. 5:00 AM → 300)
  • Up to 8 non-overlapping ranges per day.
  • Same-day shift: end_minutes > start_minutes (e.g. 8:00 AM–5:00 PM).
  • Overnight shift: end_minutes <= start_minutes — end is the next morning, exclusive (e.g. 8:00 PM–5:00 AM → start_minutes=1200, end_minutes=300). Legacy data may still use two segments (0–300 and 1200–1440); the UI merges those for display.

Default weekday template

Used for auto-fill and Apply weekday template:

DayCodeTimes
Mon–FriWD8:00 PM – 5:00 AM (single overnight range)
Sat–SunOFF(none)

Defined in api/app/services/schedule_time_ranges.py (default_weekday_time_ranges()).


Employees in the grid

  • Active employees (status: true), regardless of bsc_status.
  • Grid includes employee name, department, cluster (primary department), and WD (working-day count).
  • Default scope: departments of the signed-in user.
  • Level 3+: scope=all or department_ids (comma-separated) to widen the list.

Auto-fill

When loading the month grid for the current month or next month (one month ahead):

  • Any active employee without a saved schedule gets the weekday template above.
  • Existing saved schedules are never overwritten by auto-fill.

Manual bulk actions (level 3+, audit-logged):

ActionBehavior
Copy from last monthCopies prior month day-by-day; weekday template if prior month missing
Apply weekday templateOverwrites the whole month for filtered employees

Month locking

AccessEdit which months
Any authenticatedView all months
Level 3–4Current month and future only
Level 5Any month (including past)

Past months return month_locked: true for levels 3–4; saves and bulk actions return HTTP 403.


Working days for attendance

text
resolve_working_days_for_employee(db, employee_id, year, month) → int
  1. Saved schedule in tbl_employee_schedulesworking_days on that document (recomputed on save from day codes).
  2. Else → Mon–Fri count in the calendar month (weekdays_in_calendar_month).

HTTP: GET /v1/scorecard/employee-schedules/working-days/{employee_id}?year=&month=

Attendance KPI formula (when working_days is used):

text
(working_days − violation_count) / working_days × 100

See also BSC metrics.


Next integrations

ConsumerStatus
GET .../working-days/{employee_id}Done — per-employee resolved count
BSC attendance KPI calculationDoneresolve_working_days_for_employee in bsc_employee_compute
Task delivery workdaysDoneis_task_delivery_day on day codes; task_delivery/workdays.py resolves TD calendar per employee-month
Task delivery scorecard gridDone — day code abbreviations on off/non-WD cells; pending/missing highlights — see Fiscal cycles § Task delivery
Dashboard / analyticsPlanned (Phase 2)

API

MethodPathWho
GET/v1/scorecard/schedule-day-codesAuthenticated
PUT/v1/scorecard/schedule-day-codesLevel ≥ 3
GET/v1/scorecard/employee-schedules/month?year=&month=&search=&scope=&department_ids=Authenticated (auto-fill on load; default scope=my)
PUT/v1/scorecard/employee-schedules/monthLevel ≥ 3 (respects month lock)
POST/v1/scorecard/employee-schedules/month/copy-from-previousLevel ≥ 3
POST/v1/scorecard/employee-schedules/month/apply-templateLevel ≥ 3
GET/v1/scorecard/employee-schedules/{employee_id}/{year}/{month}Authenticated
GET/v1/scorecard/employee-schedules/working-days/{employee_id}?year=&month=Authenticated

Audit logging

Creates/updates write to tbl_logs with resources employee_schedule and schedule_day_codes (same pattern as SBS/ATW entries).


UI

RouteDescription
/organization/schedulesMonthly grid: frozen identity columns, scrollable days, filters, bulk actions, save month
/organizationChart + list (schedules are a separate nav link) — see Organization
Scorecard → Configurations → Schedule Day CodesCode catalog

Grid behavior (summary):

  • Sort default: employee → department → cluster; column headers toggle primary sort.
  • Today column: US Eastern (America/New_York) date; header highlight only.
  • Day headers: May 27 + weekday line; weekend headers use opaque styling.
  • Status line: Showing N employees · May 2026 · {active filter summary}.

Key frontend files:

  • web/src/pages/OrganizationSchedulesPage.tsx
  • web/src/pages/organization_components/EmployeeSchedulesPanel.tsx
  • web/src/pages/organization_components/scheduleFilterUtils.ts
  • web/src/pages/organization_components/scheduleTimeUtils.ts

Key backend files:

  • api/app/services/employee_schedules.py
  • api/app/services/schedule_day_codes.py
  • api/app/services/schedule_time_ranges.py
  • api/app/services/employee_schedule_policy.py

Not in v1

  • CSV import/export for schedules
  • Schedule data on Organization chart/list pages (schedules are only on /organization/schedules)
  • Pagination (acceptable for <200 employees per filter today)
  • Auto-migrating legacy two-segment overnight rows to one range on save (optional future)