This commit is contained in:
2026-07-16 09:53:14 +07:00
parent 0fc112a2e8
commit 29cec708a3
1236 changed files with 212848 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
# 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