201→200 envelope data = created Teacher doc (timestamps auto, teacher.schema.ts:14).
409 DUPLICATE_RESOURCE: user-linked profile exists / employee number exists
(teacher.service.ts:29-37) → inline AppBanner; keep form state (no reload).
400 VALIDATION_ERROR: field details mapped (00-shared/07 §3).
Notes: tenantIdnever sent (from token, base.repository.ts:33-35);
metadata not part of create DTO (update only).
Conflict rules on update: no server checks — PATCH can set
employeeNumber to an existing number with no 409 (unlike create; teacher.service.ts:80-93
only checks existence of the target record). Client pre-validates against loaded
roster; server-side race remains (OQ-3).
Status transitions allowed: any of 4 enum values, no workflow restriction server-side.
Duplicate guard: block exact (teacher, subject, class, year) already in matrix —
no server uniqueness (subject-assignment.schema.ts:24-25 indexes are non-unique;
subject-assignment.service.ts:13-17 has no check) (OQ-2).
Same teacher teaching 2 subjects in one class: allowed (no cross-check with
timetable slots — timetable has its own conflict detection at
timetable.service.ts:16-30).
Submit disabled until all 4 set; double-submit guard.
200 data = SubjectAssignment doc. Errors: 400 (invalid ids), 500; no 404 path
for unknown teacherId/subjectId/classId (no existence checks — client must ensure
picker values are valid).