SERVICE_OVERVIEW — staff-service
Catalog:
docs/03-microservices/staff-service.mdSibling: DOMAIN_MODEL · APPLICATION_LOGIC · API_CONTRACTS · EVENT_SCHEMAS · DATA_MODEL · SYNC_CONTRACT · SECURITY_MODEL · AI_INTEGRATION · OBSERVABILITY
Strategic anchors: 02 Enterprise Architecture · 04 Event-Driven Architecture · 05 API Design · 07 Security & Tenancy · ADR-0003 Electron Offline-First
1. Purpose
staff-service is the operational HR backbone of Ghasi Melmastoon. It tracks who works where, when they are scheduled, and when they are physically on the property. Its single most important downstream signal is the capacity snapshot — the live list of staff currently on the floor, by position and department — which housekeeping-service and maintenance-service use to assign rooms and tickets, and which bff-backoffice-service uses to render the front-desk dashboard.
It is deliberately lightweight HR, not a payroll system or HRIS. Adding payroll, performance reviews, complex compensation, benefits administration, or learning management requires an ADR amendment, not a feature ticket. The hospitality target market — small-to-mid hotels and guest houses across Pashtun, Persian, Tajik, and Pakistani regions — already runs payroll out of band; what it lacks is reliable, multilingual, offline-tolerant scheduling and clock-in. That is what we provide.
2. Bounded Context
| Property | Value |
|---|---|
| Bounded context | Staff & Shifts |
| Domain class | Supporting |
| Strategic patterns | Conformist to iam-service (User), tenant-service (Membership); OHS publisher to housekeeping-service, maintenance-service, front-desk-service, reservation-service |
| Ubiquitous language | Staff · Position · Department · Shift · Pattern · Assignment · Clock · Break · Leave · Certification · On-Call · Hand-off · Capacity |
A Staff is not a User. A Staff is the operational projection of a person's employment within a tenant; the underlying authentication identity (and tenant membership) lives in iam-service / tenant-service. The two are connected by Staff.userId which is nullable — a staff record can exist before an invitation is accepted (see APPLICATION_LOGIC §6 CreateStaff) and a staff record can exist forever without a User if the staff member never gets a personal device (PIN-only path).
3. Aggregates Owned
| Aggregate | Prefix | Brief |
|---|---|---|
Staff | stf_ | Hospitality-specific extension of iam.User. Owns: position, department, languages, certifications (refs), emergency contact, employment dates, status, multi-property access list, clock-in PIN. |
Position | pos_ | Tenant-defined job role (front desk, housekeeper, GM, maintenance, F&B, security, …). Localized labels. |
Department | dpt_ | Tenant-defined org grouping per property; many positions per department. |
ShiftPattern | shp_ | Recurring weekly/bi-weekly schedule template. Carries position requirement and headcount. |
Shift | shf_ | Concrete time window for a property/date materialized from a pattern (or ad-hoc). |
ShiftAssignment | sha_ | Many-to-many between Shift and Staff with role (primary / standby / on_call). |
ClockEntry | clk_ | Append-only punch (in / out / break_start / break_end) with source attribution and device binding. |
LeaveRequest | lvr_ | Sick / vacation / unpaid; lifecycle: requested → approved / rejected / cancelled. |
StaffSkill | skl_ | Language, equipment, soft skill — used by AI suggestion + housekeeping matching. Light catalog, tenant-extensible. |
StaffCertification | crt_ | Food handling, first aid, fire safety, etc.; carries expires_at → emits .expired.v1 on TTL. |
HandoffNote | hno_ | Append-only between-shift notes scoped to a position/department/property. |
The supporting infrastructure (outbox, inbox, idempotency, audit) is persistence-only and not part of the domain.
4. Top Responsibilities
- Staff CRUD with hospitality attributes — supports the
informal staffingreality of target markets. - No-email staff — first-class support for staff records that have only a manager email + PIN.
- Pattern-based scheduling — define a recurring template, generate concrete shifts for a date window per property.
- Manual + AI-suggested assignment — accept manual assignments, materialize AI suggestions advisory-only.
- Conflict detection — double-shift, leave collision, multi-property simultaneous, expired certification.
- Clock in / out / break — from front-desk Electron desktop (PIN) or via manager override on mobile/web.
- Light leave management — request + approve; collisions block until
forceUnassignis set. - Capacity signal —
GET /capacityand thestaff.shift.started.v1/.ended.v1event stream. - On-call / standby — auto-promote standby to primary if a no-show is detected.
- Multi-property staff — same tenant, multiple properties, but at most one active shift across all of them.
- Hand-off notes — append-only between-shift notes scoped per position.
- Staffing gap detection — proactive
.staffing_gap_detected.v1when a shift is N minutes from start with no clocked-in primary. - Basic attendance reports — per staff / per period / per position (CSV + JSON).
5. Out of Scope (Explicitly)
- Payroll, payslips, tax withholding, deductions, benefits — never. Use external payroll; export attendance via the read API or BigQuery.
- Performance reviews, 360-feedback, OKRs, KPIs.
- Complex compensation — no hourly rates, overtime calculation, shift differentials. We track time, not money.
- Recruitment / ATS / onboarding workflows beyond "create record and invite".
- Learning Management — certifications are tracked (existence + expiry), not their training delivery.
- Authentication / sessions / MFA — owned by
iam-service. We never store passwords or issue tokens. - Tenant role assignment — owned by
tenant-service. We listen.
6. Context Map (Upstream / Downstream)
┌──────────────────────┐
│ iam-service │ user.registered.v1
│ (Generic, Conformist)│ ─────────────────────┐
└──────────────────────┘ │
▼
┌──────────────────────┐ membership.* ┌────────────────────┐
│ tenant-service │ ──────────────────▶│ staff-service │
│ (Supporting, Conformist) │ (Supporting, │
└──────────────────────┘ │ OHS publisher) │
└────────────────────┘
│ │
┌──────────────────────────────────────────────────┘ │
│ shift.started.v1 │
│ shift.ended.v1 │
│ clock.in.v1 / .out.v1 │
│ shift.staffing_gap_detected.v1 │
│ capacity (REST) │
▼ │
┌────────────────────────┐ ┌────────────────────────┐ │
│ housekeeping-service │ │ maintenance-service │ │
│ (consumer, OHS conformist) │ (consumer, OHS conformist) │
└────────────────────────┘ └────────────────────────┘ │
│
┌───────────────────────────────────────────────────┘
│ certification.expired.v1, terminated.v1
▼
┌────────────────────────────┐
│ bff-backoffice-service │ (front-desk dashboards, schedules)
└────────────────────────────┘
▲
ai.suggestion.shift_optimization.v1
│
┌──────────────────────┐
│ ai-orchestrator │ (advisory schedule, never auto-applied)
└──────────────────────┘
7. Hot Read Paths
| Surface | Query | Latency budget (p95) |
|---|---|---|
| Front-desk Electron capacity widget | GET /capacity?propertyId&position&at | 80 ms (cache-hit), 250 ms (miss) |
| Backoffice schedule grid | GET /shifts?propertyId&from&to | 300 ms |
| Housekeeping assignment loop | GET /capacity?propertyId&position=housekeeper | 80 ms |
| Reports — attendance per period | GET /reports/attendance?… | 5 s (paginated) |
8. Cost / Scale Envelope (M0 → M2)
| Metric | M0 (single region) | M2 (multi-region active-active) |
|---|---|---|
| Tenants | 50 | 5 000 |
| Properties / tenant | up to 5 | up to 25 |
| Staff / property | up to 80 | up to 250 |
| Punches / property / day | ~ 400 | ~ 1 200 |
| Peak punches / second (cluster) | 5 | 200 |
| Outbox depth normal | < 20 | < 200 |
| DB IOPS (avg) | 100 | 4 000 |
Capacity events are fan-out heavy (every consumer of staff.shift.started.v1 is property-scoped) but each carries a small payload (< 1 KiB). Pub/Sub cost dominates at M2.
9. Decision Log
| # | Decision | Why |
|---|---|---|
| 1 | Staff is a separate aggregate, not extension of iam.User | Different lifecycle, different bounded context, multi-property scoping needed |
| 2 | PIN-based clock-in (no biometric in M0/M1) | Hardware availability and cultural fit; biometric reserved for M2 ADR |
| 3 | Staff.userId is nullable | Real-world hotel staff often lack personal devices/email |
| 4 | Append-only clock_entries table, no updates | Audit, sync simplicity, regulatory alignment |
| 5 | Multi-property staff with at-most-one active shift across all | Operational sanity; physical impossibility |
| 6 | AI suggestions are advisory only, never auto-applied | Trust + auditability; aligns with 02 §10 AI provenance |
| 7 | Lightweight leave only (3 types, single-step approval) | Scope discipline; not an HRIS |
| 8 | Pattern-based scheduling, not optimizer-first | Simpler, comprehensible, AI-augmentable later |
10. External Dependencies
| Dependency | Direction | Why | Failure response |
|---|---|---|---|
iam-service | inbound | user.registered.v1, session-revoke RPC on terminate | Inbox dedup; revoke is fire-and-forget with retry |
tenant-service | inbound | membership.created/removed.v1 | Inbox dedup |
property-service | inbound | property existence, departments scope | Cache + circuit breaker; degrade to last-known |
ai-orchestrator-service | inbound | ai.suggestion.shift_optimization.v1 | Drop after 7 d retention; never blocks |
notification-service | outbound | .staffing_gap_detected.v1 triggers ops alerts (Pub/Sub) | Async; no synchronous coupling |
| Cloud SQL Postgres 16 | sync | System of record | Readiness fails until DB reachable |
| Memorystore Redis 7 | sync | Capacity cache, PIN attempt counter, idempotency | Degrade: skip cache, allow attempts (rate-limited via DB) |
| Pub/Sub | sync | Outbox publish + inbox subscribe | Outbox retries with backoff |
| Cloud KMS | sync | PIN HMAC pepper | Readiness fails until KMS reachable |
11. Quick Links
| Concern | Document |
|---|---|
| Domain types & invariants | DOMAIN_MODEL |
| Use cases, ports, sagas | APPLICATION_LOGIC |
| REST surface | API_CONTRACTS |
| Pub/Sub schemas | EVENT_SCHEMAS |
| DDL, RLS, indexes | DATA_MODEL |
| Electron sync | SYNC_CONTRACT |
| RBAC, PIN, audit | SECURITY_MODEL |
| AI usage | AI_INTEGRATION |
| SLIs, alerts, dashboards | OBSERVABILITY |
| Test pyramid | TESTING_STRATEGY |
| Cloud Run topology | DEPLOYMENT_TOPOLOGY |
| Failure catalog | FAILURE_MODES |
| Local dev | LOCAL_DEV_SETUP |
| Readiness gate | SERVICE_READINESS |
| Risks | SERVICE_RISK_REGISTER |
| Onboarding existing staff | MIGRATION_PLAN |