160 lines
5.0 KiB
Markdown
160 lines
5.0 KiB
Markdown
# Sprint 6.11 Identity / Employee Cleanup Review
|
|
|
|
## Summary
|
|
|
|
This pass moves the system closer to the target architecture where:
|
|
|
|
- `users` is login identity
|
|
- `employees` is employee master
|
|
- training ownership is based on `employeeId`
|
|
- user actions remain tracked separately
|
|
|
|
The work completed in this pass focuses on the highest-risk operational paths first:
|
|
|
|
- schema support for user-to-employee mapping
|
|
- stopping employee import from auto-creating users
|
|
- employee-owned training records
|
|
- employee-based employee directory
|
|
- employee-based training matrix compliance
|
|
|
|
## Migration Changes
|
|
|
|
Migration file:
|
|
|
|
- `drizzle/0010_romantic_marauders.sql`
|
|
|
|
Changes included:
|
|
|
|
- create `user_employee_maps`
|
|
- make `training_records.user_id` nullable
|
|
- make `employee_training_targets.user_id` nullable
|
|
- add `training_records.submitted_by_user_id`
|
|
- add `training_records.reviewed_by_user_id`
|
|
- add unique index `employee_training_targets_org_employee_year_idx`
|
|
- backfill `user_employee_maps` from existing `users.employee_id`
|
|
- backfill `submitted_by_user_id` from `created_by`
|
|
- backfill `reviewed_by_user_id` from `reviewed_by`
|
|
|
|
## Code Changes
|
|
|
|
### Identity / Mapping
|
|
|
|
- `src/db/schema.ts`
|
|
- `src/features/employees/server/employee-identity-linking.ts`
|
|
|
|
Added:
|
|
|
|
- `user_employee_maps`
|
|
- helper to resolve employee ids for a user
|
|
- helper to maintain mapping during import or login linking
|
|
|
|
### Employee Import
|
|
|
|
- `src/app/api/import-employees/route.ts`
|
|
|
|
Changed behavior:
|
|
|
|
- import upserts into `employees`
|
|
- import upserts `employee_training_targets` by `employeeId`
|
|
- import links existing users when employee code matches
|
|
- import no longer auto-creates login users
|
|
|
|
### Employees API
|
|
|
|
- `src/app/api/employees/route.ts`
|
|
- `src/features/employees/server/employee-data.ts`
|
|
|
|
Changed behavior:
|
|
|
|
- employees API is active again
|
|
- `mode=options` returns active employee options for HRD workflows
|
|
|
|
### Training Records
|
|
|
|
- `src/features/training-records/api/types.ts`
|
|
- `src/features/training-records/api/service.ts`
|
|
- `src/features/training-records/schemas/training-record.ts`
|
|
- `src/features/training-records/components/training-record-form.tsx`
|
|
- `src/features/training-records/components/training-record-view-page.tsx`
|
|
- `src/features/training-records/server/training-record-data.ts`
|
|
- `src/app/api/training-records/route.ts`
|
|
- `src/app/api/training-records/[id]/route.ts`
|
|
- `src/app/api/training-records/[id]/review/route.ts`
|
|
- `src/app/dashboard/training-records/[trainingRecordId]/page.tsx`
|
|
|
|
Changed behavior:
|
|
|
|
- training record create/update now uses `employeeId` as owner
|
|
- `submittedByUserId` is written on create
|
|
- `reviewedByUserId` is written on review
|
|
- employee self-scope uses mapped employee ids
|
|
- HRD employee selector now reads from `employees`
|
|
|
|
### Employee Directory
|
|
|
|
- `src/features/employee-directory/server/employee-directory-data.ts`
|
|
- `src/features/employee-directory/components/employee-directory-detail-page.tsx`
|
|
|
|
Changed behavior:
|
|
|
|
- directory detail reads from `employees`
|
|
- training summary and transcript use `training_records.employee_id`
|
|
|
|
### Training Targets
|
|
|
|
- `src/features/training-policy/server/employee-training-target-data.ts`
|
|
|
|
Changed behavior:
|
|
|
|
- added employee-based target resolution
|
|
- user-based target resolution now falls through employee mapping
|
|
|
|
### Training Matrix
|
|
|
|
- `src/features/training-matrix/server/training-matrix-data.ts`
|
|
|
|
Changed behavior:
|
|
|
|
- compliance calculation now uses `employees`
|
|
- approved-course ownership now uses `training_records.employee_id`
|
|
|
|
## Regression Checklist
|
|
|
|
1. Run `npm run migrate`
|
|
2. Sign in with an existing credentials user
|
|
3. Import employee Excel with no pre-existing user account
|
|
4. Verify employee rows are created/updated in `employees`
|
|
5. Verify no new `users` row is auto-created from import
|
|
6. Verify `employee_training_targets` rows are created using `employee_id`
|
|
7. Verify existing users with matching employee code are linked in `user_employee_maps`
|
|
8. As employee user with a linked employee profile, create a training record
|
|
9. Verify `training_records.employee_id` is set
|
|
10. Verify `training_records.submitted_by_user_id` is set
|
|
11. Review a pending record as HRD
|
|
12. Verify `training_records.reviewed_by_user_id` is set
|
|
13. Open employee directory detail and verify totals still load
|
|
14. Open training matrix compliance and verify rows still load
|
|
|
|
## Verification
|
|
|
|
Verified in this pass:
|
|
|
|
- `npx tsc --noEmit`
|
|
|
|
## Known Remaining Work
|
|
|
|
This pass does **not** fully migrate every aggregation path yet.
|
|
|
|
Still recommended for the next pass:
|
|
|
|
- move `overview` fully to `employees` + `training_records.employee_id`
|
|
- move `reports` fully to `employees` + `training_records.employee_id`
|
|
- reduce remaining dependency on `users.employeeCode` as compatibility fallback
|
|
- add Keycloak runtime mapping using `user_employee_maps`
|
|
|
|
## Risk Notes
|
|
|
|
- some runtime paths still keep compatibility writes to legacy columns
|
|
- `users.employeeId` still exists as fallback and compatibility support
|
|
- notifications still depend on login users, so employees without user accounts will not receive login-bound notifications
|