Full enterprise web operating system including: - Next.js 14 frontend with App Router, i18n (DE/EN), shadcn/ui - NestJS 10 backend with Prisma, JWT auth, Swagger docs - Keycloak 24 SSO with role-based access control - HR module (employees, time tracking, absences, org chart) - LEAN module (3S planning, morning meeting SQCDM, skill matrix) - Integrations module (PlentyONE, Zulip, Todoist, FreeScout, Nextcloud, ecoDMS, GembaDocs) - Dashboard with customizable drag & drop widget grid - Docker Compose infrastructure (PostgreSQL 16, Redis 7, Keycloak 24) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
72 lines
3.7 KiB
Markdown
72 lines
3.7 KiB
Markdown
# Phase 7 - Full Backend Code Review (2026-02-06)
|
|
|
|
## Overall Score: 7.8/10
|
|
|
|
## Module Scores
|
|
|
|
| Module | Score | Key Issue |
|
|
|--------|-------|-----------|
|
|
| Auth (guards, strategy, decorators) | 8/10 | Role names leaked in error messages |
|
|
| Prisma (service, module) | 7/10 | cleanDatabase() ignores FK constraints |
|
|
| HR/Employees | 8/10 | `as any` type casts for encrypted data |
|
|
| HR/Time Tracking | 7/10 | Break tracking via string parsing, private method access |
|
|
| HR/Absences | 8/10 | Missing holiday calc, vacation carry-over TODO |
|
|
| LEAN/Skill Matrix | 8/10 | N+1 in analyzeGaps, non-transactional bulkUpsert |
|
|
| LEAN/Morning Meeting | 7/10 | ALL endpoints use DASHBOARD_VIEW permission |
|
|
| LEAN/S3 Planning | 8/10 | File upload MIME not validated, N+1 in findAll |
|
|
| Dashboard | 8/10 | Hardcoded role strings |
|
|
| Common (filters, interceptors) | 8/10 | Logging/Timeout interceptors never registered |
|
|
| Users | 8/10 | GET /users has no permission restriction |
|
|
| Audit | 7/10 | oldData always undefined, salary not sanitized |
|
|
| app.module + main.ts | 9/10 | enableImplicitConversion risk |
|
|
|
|
## Critical Issues (3)
|
|
|
|
### 1. Morning Meeting Permission Escalation
|
|
- **File:** `apps/api/src/modules/lean/morning-meeting/morning-meeting.controller.ts`
|
|
- **Lines:** 47, 59, 66, 79, 99, 120, 149, 159, 170, 183, 193, 211, 221, 234, 249, 259, 270
|
|
- **Issue:** ALL endpoints (including create, update, delete) use `Permission.DASHBOARD_VIEW`
|
|
- **Impact:** Any authenticated user with dashboard access can create/modify/delete morning meetings
|
|
|
|
### 2. Private Method Access via Bracket Notation
|
|
- **File:** `apps/api/src/modules/hr/time-tracking/time-tracking.controller.ts`
|
|
- **Lines:** 237-239
|
|
- **Issue:** `this.timeTrackingService['getEmployeeByUserId'](user.sub)` accesses private method
|
|
- **Impact:** Circumvents TypeScript access modifiers, fragile to refactoring
|
|
|
|
### 3. Prisma cleanDatabase() with Promise.all
|
|
- **File:** `apps/api/src/prisma/prisma.service.ts`
|
|
- **Lines:** 48-61
|
|
- **Issue:** Deletes all tables in parallel ignoring foreign key constraints
|
|
- **Impact:** Can fail in production/staging if FK constraints exist; should use sequential deletion or raw SQL truncate cascade
|
|
|
|
## Important Issues (14)
|
|
|
|
1. **Roles guard leaks role names** - roles.guard.ts L31-33
|
|
2. **Permissions guard leaks permission names** - permissions.guard.ts
|
|
3. **enableImplicitConversion in ValidationPipe** - main.ts L44
|
|
4. **Break tracking via note string parsing** - time-tracking.service.ts L216-219, L257-258
|
|
5. **No backdating limit** for manual time entries
|
|
6. **Holiday calculation missing** in absences calculateWorkingDays
|
|
7. **Vacation carry-over not implemented** - absences.service.ts L979 (BUrlG)
|
|
8. **Event queue in-memory only** - absences.service.ts L1414
|
|
9. **N+1 query in analyzeGaps** - skill-entries.service.ts L515-523
|
|
10. **bulkUpsert not transactional** - skill-entries.service.ts L429-476
|
|
11. **File upload MIME not validated** - s3-planning.controller.ts
|
|
12. **LoggingInterceptor + TimeoutInterceptor never registered**
|
|
13. **GET /users no permission check** - users.controller.ts L88-97
|
|
14. **Audit oldData always undefined** - audit.interceptor.ts L60
|
|
|
|
## Positive Observations
|
|
|
|
- JWT verification (not just decode) with user existence check on every request
|
|
- AES-256-GCM encryption for sensitive employee data (salary, bank account)
|
|
- Consistent error response format via global HttpExceptionFilter
|
|
- Response envelope pattern via TransformInterceptor
|
|
- ArbZG break rules correctly implemented in time tracking
|
|
- Comprehensive absence workflow with approval chain
|
|
- Global ValidationPipe with whitelist + forbidNonWhitelisted
|
|
- Proper soft delete patterns for employees
|
|
- Well-structured module hierarchy (HrModule -> sub-modules)
|
|
- Swagger/OpenAPI documentation on all endpoints
|