Lewati ke isi

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

publishedcorrect(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 draftwali_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:

  1. Entitlement — SC-REPORT / scola_report_card
  2. Capability — action bucket (see §3)
  3. Company — acting user tenant ∩ record company_id
  4. Assignment / batchop.teaching.assignment (active) or homeroom policy; P5 uses the same model
  5. State — subject-teacher score mutate in draft/rejected and own lines while submitted (soft-lock until approve_wk); homeroom may edit lines while submitted; EY/EN/PKL follow the same editable score states; delete only unlocked states; publish only from kepala_sekolah + is_homeroom_of_report
  6. SoDapprove_ks ≠ submitter (submitted_by) and ≠ recorded wali kelas reviewer (wali_kelas_approved_by) when set. publish has no submitter SoD — only is_homeroom_of_report + capability + state kepala_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 on approve_ks; principal approve_ks must 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.