Departments
Organizational units structuring the Renewa One team. Departments define team hierarchy, skill-level ownership, and are used for responsibility filtering in Document Obtaining and access scoping in RBAC Authorization.
Entra-owned (2026-06): departments and internal employees are sourced from Microsoft Entra ID via an hourly BullMQ sync job (
entra-sync, cron30 * * * *inbackend/src/lib/jobs/schedulers.ts; servicebackend/src/services/entra/entra-sync-service.ts). Neither mocks nor migrations may re-seed them. Spec:docs/superpowers/specs/2026-06-09-mock-people-defer-to-entra-design.md.
Source Files
| Layer | Path |
|---|---|
| Schema | backend/src/db/schema.ts (departments) |
| Routes | backend/src/routes/admin/departments/ (department-crud.ts, members.ts) |
| Entra Sync | backend/src/services/entra/entra-sync-service.ts, backend/src/lib/jobs/processors/entra-sync.ts |
| Admin Page | frontend/src/pages/admin/DepartmentsAdmin.tsx |
| Team Page | frontend/src/pages/internal/TeamPage.tsx |
| Filter Context | frontend/src/contexts/ResponsibilityFilterContext.tsx |
Database Tables
| Table | Purpose |
|---|---|
departments | Main entity — localized name, code, skill level, ownership flag, Entra sync key |
The
user_departmentsM2M junction was removed (RNW-336): department placement is now a single FKcontacts.departmentIdon Contacts — one contact, one department — populated by the Entra profile sync.
Key Fields
| Field | Type | Notes |
|---|---|---|
name | jsonb (LocalizedText) | Bilingual name {de, en}; German name unique (admin invariant) |
code | varchar(30) | Unique internal code (e.g., RENOVATION_MANAGEMENT, OPM, SALES) |
shortName | varchar(20) | Badge/UI label (e.g., SAM, FP, FD, EBO) |
skill | enum | pro or basic — skill level this department handles |
isOwner | boolean | Whether this is the “owner” department for its skill level |
description | jsonb (LocalizedText) | Bilingual description |
entraKey | varchar(255) | Entra department string used for sync matching (unique, case-insensitive); null for departments outside Entra sync |
origin | enum | curated (admin-created) or entra_auto (auto-created by sync) |
sortOrder | integer | UI display order |
isActive | boolean | Active flag |
Skill-Level Ownership
Departments are categorized by the project skill level they handle:
| Skill | Owner Dept | Meaning |
|---|---|---|
pro | SAM Pro | Owns PRO-level projects (complex renovations) |
basic | SAL Basic | Owns BASIC-level projects (simpler renovations) |
The isOwner flag determines which department is the primary owner for projects at that skill level.
Relationships
Department 1──* Contacts (contacts.departmentId, Entra-synced)
Department -- used by --> Document Obtaining (responsibility filter)
Department -- used by --> RBAC Authorization (team lead scoping)
Membership
Department membership lives on Contacts (contacts.departmentId, single FK — RNW-336):
- One contact belongs to at most one department
- Populated by the Entra profile sync (Entra
user.departmentstring matched againstdepartments.entraKey; unknown departments are auto-created withorigin: entra_auto) - Used by team leads to scope their admin access (see RBAC Authorization); user lists filter via
contacts.departmentIdjoins (backend/src/routes/admin/users/user-crud.ts)
Frontend
- Admin page (
DepartmentsAdmin.tsx) — department curation (display names, ordering); membership itself is Entra-owned - Team page (
TeamPage.tsx) — internal team directory grouped by department - Responsibility filter (
ResponsibilityFilterContext.tsx) — context provider that lets users filter views by department responsibility
Access Scoping
Team leads see only users in departments they manage. This is enforced in:
backend/src/routes/admin/users/user-crud.ts— filters user lists by managed departmentsbackend/src/middleware/rbac.ts—requireTeamLeadOrAdminmiddleware
Related Pages
Users | Contacts | Document Obtaining | RBAC Authorization | Admin Dashboard | Database Architecture | Service Layer Pattern