E-Rapor Product Contract (SSOT) — SC-REPORT / W07¶
| Field | Value |
|---|---|
| Status | CANONICAL (supersedes T6C-W07-report-card-contract-DRAFT.md) |
| Wave | W07 / SC-REPORT (+ optional SC-LEARN bridge deferred) |
| SKU | SC-REPORT / PKG-REPORT-W07 |
| Modules | scola_report_card, scola_assessment_bridge |
| Authz SSOT | scola_report_card/services/report_card_authz.py |
| Last aligned | 2026-09-08 |
| Module version (aligned) | scola_report_card 17.0.2.7.0 |
1. Scope¶
| In scope | Out of scope (later stages / deferred) |
|---|---|
| Grade entry → wali review → KS approve → homeroom publish | Full LMS authoring |
| Homeroom + principal workflow with company/capability/SoD | Online Dapodik sync before acceptance |
| Portal read of published reports only | Destructive P5→kokurikuler conversion |
| PDF backend generation | Production promote without Stage F gates |
Preserve: portal published-only; reject reason required; PDF backend; component status missing / filled / exempt; auto-sync only into draft.
2. Live state machine (API tokens)¶
Do not invent or treat as live tokens: reviewed, approved, finalized, released.
stateDiagram-v2
[*] --> draft
draft --> submitted: submit
rejected --> submitted: submit
submitted --> wali_kelas: approve_wk
wali_kelas --> kepala_sekolah: approve_ks
kepala_sekolah --> published: publish
submitted --> rejected: reject
wali_kelas --> rejected: reject
kepala_sekolah --> rejected: reject
submitted --> draft: draft (reset)
wali_kelas --> draft: draft (reset)
kepala_sekolah --> draft: draft (reset)
rejected --> draft: draft (reset)
| Live state | UI label (FE) | Meaning | Typical next actors |
|---|---|---|---|
draft |
Draft | Editable score entry / generate | Subject teacher, homeroom, admin config |
submitted |
Menunggu wali kelas | Waiting wali kelas (soft-lock) | Homeroom (approve_wk / reject / edit); subject teacher may still edit own lines (can_grade_line) until approve_wk |
wali_kelas |
Menunggu Kepala Sekolah | Homeroom approved → KS queue | Principal (approve_ks / reject); homeroom may reject |
kepala_sekolah |
Disahkan KS — menunggu publish wali | Principal approved, not yet portal-visible | Homeroom (publish / reject) |
published |
Dipublikasi | Frozen for portal/PDF; no draft reset | Student / parent read; QR verify metadata |
rejected |
Ditolak | Returned with mandatory reason | Teacher / homeroom fix → submit |
Correction¶
published → correct(reason) creates an archived revision, then returns to
draft; rejected may also be corrected and resubmitted. No legacy state
token or compatibility alias is accepted by the live state machine.
3. Actors, entitlement, capabilities¶
Entitlement gate: company platform flag scola_report_card (SKU SC-REPORT). Off → feature_disabled.
| Actor | Role codes (session) | Logical actions | Capability buckets |
|---|---|---|---|
| Subject teacher | teacher, guru |
input; submit if can_grade_line on ≥1 line |
report_cards.list.view, report_cards.records.manage, or report_cards.* |
| Homeroom | homeroom / teacher + batch homeroom |
approve_wk, reject, edit lines while submitted, publish after KS (is_homeroom_of_report) |
same + batch assignment |
| Principal | principal |
approve_ks + reject at KS queue (not portal publish) |
report_cards.* / report_cards.records.manage plus company |
| VP / delegate | vice_principal* (review read; mutate only if authz allows delegate) |
review queue read; may approve_ks if delegate |
report_cards.* |
| School admin | admin, school_admin, … |
config, generate, monitoring | report_cards.* / setup helpers |
| Student / parent | student, parent |
read published only | portal scope |
Logical action codes used by authz service: config, input, review, publish, reject, correct, export, promotion_view, promotion_mutate.
Publish authority: Wali kelas (homeroom for the batch via is_homeroom_of_report) after Kepala Sekolah has set state to kepala_sekolah. Principal approves (approve_ks) but does not portal-publish. Admin/principal is_admin_operator alone does not grant publish.
Homeroom shortcuts: UI must not chain draft → wali_kelas in one click. approve_wk only from submitted and re-runs publish-level blockers (numeric/PKL/narrative).
4. Authorization stack (mandatory order)¶
Implemented in report_card_authz.py and called from controllers and model write/unlink/override paths:
- Entitlement — SC-REPORT /
scola_report_card - Capability — action bucket (see §3)
- Company — acting user tenant ∩ record
company_id - Assignment / batch —
op.teaching.assignment(active) or homeroom policy; P5 uses the same model - State — subject-teacher score mutate in
draft/rejectedand own lines whilesubmitted(soft-lock untilapprove_wk); homeroom may edit lines whilesubmitted; EY/EN/PKL follow the same editable score states; delete only unlocked states; publish only fromkepala_sekolah+is_homeroom_of_report - SoD —
approve_ks≠ submitter (submitted_by) and ≠ recorded wali kelas reviewer (wali_kelas_approved_by) when set.publishhas no submitter SoD — onlyis_homeroom_of_report+ capability + statekepala_sekolah(wali who submitted may still publish; otherwise PAUD/small-school single-wali flows dead-end). Admin/principal do not get a blanket SoD bypass onapprove_ks; principalapprove_ksmust pass company+capability (not role-only).
Negative cases that must fail closed: foreign ID, cross-company principal by-ID, expired (active=False) assignment, entitlement off, parent other child, principal/admin_operator publish without homeroom.
5. API surface (workflow)¶
| Client action | Model method | From state | To state |
|---|---|---|---|
submit |
action_submit |
draft, rejected | submitted |
approve_wk |
action_approve_wali_kelas |
submitted | wali_kelas |
approve_ks |
action_approve_kepala_sekolah |
wali_kelas | kepala_sekolah |
publish |
action_publish |
kepala_sekolah | published |
reject |
action_reject(reason) |
submitted, wali_kelas, kepala_sekolah | rejected |
draft |
action_draft |
not published | draft |
delete |
unlink |
draft/rejected only (authz) | — |
Teacher score routes (override-score, clear-override, refresh-scores) require assignment + company + editable state.
Public verify_qr: metadata only (validity, term/batch labels, publish date, version, artifact hash) — no scores, NIS/NISN, or sensitive identity. Canonical anonymous route: /api/public/report-card/verify-qr (also registered on /api/v1/report-card/verify-qr with auth=public; /api/v1 may still require session via global API gate — prefer /api/public/... for anon scanners).
Promotion admin: company domain on list/mutate; operational mutations use report_cards.records.manage (or admin/principal), not report_cards.curriculum.view alone.
6. Requirement matrix (Stage A slice)¶
| ID | Requirement | Jenjang/periode | Policy basis | Actor | API / code | Test | Evidence |
|---|---|---|---|---|---|---|---|
| G01 | Mutations by-ID respect company | all | tenant isolation | principal+ | workflow + authz | cross-company by-ID deny | structure + authz unit |
| G02 | Override/clear/refresh gated | all | assignment+state | teacher | teacher_score_api + model | expired assignment / locked state | authz + API unit |
| G09 | P5 uses teaching assignment | all | same assignment SSOT | teacher/P5 | p5_* controllers | no op.assignment in P5 |
structure |
| G10 | Promotion company + mutate cap | all | operational vs curriculum view | admin/homeroom/KS | promotion_admin_api | curriculum.view alone insufficient for mutate | structure |
| G12 | QR public metadata only | all | privacy | anon | verify_qr / verify_qr_code |
no average_score / student_name | structure + model |
| G14 | Single authz + no dup helpers | all | maintainability | — | report_card_authz + api | one _can_manage_report def |
structure |
7. Bound decisions¶
| ID | Decision |
|---|---|
| DEC-004 | Maker-checker: KS approve SoD vs submitter+wali; portal publish by homeroom only (no submitter SoD) |
| DEC-005 | KS stops at approve_ks; portal publish is homeroom-only (is_homeroom_of_report) |
| Live SM | Tokens above are the only workflow states |
| Portal | Published-only for student/parent |
| Reject | Reason required |
Archive/PDF freeze and correction revision are implemented in the current source. Jenjang profiles, promotion/Dapodik, and the full QA matrix remain separate evidence tracks; none of them changes the live workflow tokens above.