The member-facing Training API

FeatureDocsService
Ya
11 Agosti 2026, 16:25 UTC
Mwandishi
Kamo
Ahadi ya
8ade029

Registers com.kamo.z.shared.hr.training in @EnableJpaRepositories — @EntityScan is broad so the entities are found either way, but repositories are not. Two authorization funnels, deliberately separate, mirroring the legal module: TrainingAccess gates /api/docs/training/** on MANAGE_TRAINING (RoleRightType 185) read AND write, which must stay exactly the right app/hr/hrTabs.ts gates the tab on. A server set narrower than the tab's leaves a member able to open the tab and collect a 403 over an empty grid; wider, and it is an endpoint reachable by somebody the UI never offered it to. Rights are read from member_rights_applied, never from the token, because the OTK session map carries no rights. TrainingAssignmentOwnership authorizes the member's own surface by IDENTITY. TrainingMemberController therefore holds no TrainingAccess field at all — a member taking a course they were assigned has no HR right, and routing them through the HR funnel would mean either locking every employee out of their own training or widening the HR right set until the catalog and audience roster open to the whole org. Ownership answers 404, never 403: a 403 confirms the uid is real and turns the endpoint into an oracle for who was assigned what, and an assessment record must not be enumerable by a peer. TrainingMemberSurfaceAuthTest pins all three properties by reflection, because the failure mode is somebody adding the field later "so the endpoint is secured too". GET /assignments and GET /assignments/pending-count. No mapping takes a member or org id — both come from the session. status is a REPEATABLE param, never CSV: APIService hands its upstream URL to RestTemplate as a String, which re-encodes %2C to %252C, so a comma arrives as one literal token matching no enum constant. An unrecognised filter means "no filter", never "match nothing", so a stale bookmark shows everything rather than an empty grid that reads as data loss. The paged read is a DocsService-local repository over the shared entity, sorted (deliveredAt DESC, uid DESC) — paging on a non-unique key duplicates and skips rows, and a 200-member assignment writes deliveredAt inside the same millisecond. pending-count returns the same JSON shape as the badge's pushed frame so one client parser serves both. Rows are mapped inside the transaction; course and version are LAZY. 413 tests pass.

Mabadiliko yote

Je, unaona nini kuhusu usafiri?

Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.

Kuwa Huru MileleMtazamo wa bei