fix(core): leave employees whose work ended out of every member list
Problem
#11506 removed employees whose work ended from project member lists. They still showed up in every other member list:
- teams: the Teams page, and Ever Teams via
GET /organization-team/meandGET /organization-team/:id; - sprints;
- project modules;
- departments;
- clients (the employees assigned to a contact).
"End Work" keeps an employee's memberships so that "Back to Work" restores them, and none of these lists filtered them out. The edit forms only offer working employees, so these hidden members also could not be seen or managed there.
Fix
Reads: FormerEmployeesInterceptor. It is mounted on the team, sprint, project module, department and client controllers and resolvers. It removes employees whose work ended from every members list in the response, at any depth, in the shapes both ORMs and both protocols return:
- Membership rows (team, sprint, module) are matched by
employeeId. For MikroORM, whereemployeeIdis not set, theemployeerelation or its key is used. One lookup per response:EmployeeService.findWorkingEmployeeIds(active, not archived, not deleted). - Employee rows in many-to-many lists (department, client) are judged by their own
isActive/isArchived, so no lookup is needed. - Unidentifiable members are kept. A member is removed only when its employee is known not to be working.
- Only the response is changed. Nothing is saved from it, so filtering can never remove a membership.
- No new module dependency.
EmployeeServiceis resolved at runtime (ModuleRef, non-strict), so the department and client modules, which don't importEmployeeModule, get the lookup too.
Edits keep what the form could not show:
- Team, sprint and project-module member edits keep the memberships of employees whose work ended instead of deleting rows the form never sent back. A working member taken off is still removed.
- Department and client edits keep their links to those employees (
withFormerEmployeeLinks). An edit that does not mentionmembersleaves them untouched.
Employees whose work ended are now listed only on the Employees page, when its filter asks for them. Historical records (task assignees, time logs, time-off requests, comments, approvals) are unchanged, because they record who actually did the work.
Tests
former-employees.spec.tscovers:- pages of teams filtered with one lookup;
- a single team with nested lists;
- a GraphQL connection (nodes and edges share rows);
- MikroORM-shaped rows (relation object or key);
- department/client employee rows judged by their flags (no lookup);
- employee rows without flags (looked up);
- unidentifiable members kept;
- responses without member lists untouched;
withFormerEmployeeLinks.
former-employees.interceptor.spec.ts: the interceptor is mounted on all 10 controllers/resolvers; it filters through the application'sEmployeeService; without that service it still filters rows that carry their own flags.former-employees.edits.spec.ts:- sprint and project-module edits keep a former employee's membership and remove a working member taken off;
- department and client edits keep links to former employees;
- an edit that doesn't mention members leaves them alone.
organization-team-employee.service.spec.ts: a team edit keeps a former member's row (no delete, no unsubscribe) and still removes a working member taken off.organization-sprint.service.spec.ts: the harness now provides the working-employee lookup.- Results: 402 tests across the team, team-employee, sprint, module, department and contact suites pass. Core
tscis clean, the static gates pass, and ESLint reports no findings on the new files.
🤖 Generated with Claude Code