Lewati ke isi

04 — Authorization readiness dan proposed final authorization model

Status dan baseline

Dokumen ini mengusulkan penutupan authorization untuk Scola V1 Production Baseline. Ia bukan pernyataan bahwa model tersebut sudah diterapkan. Audit dilakukan dalam server-development mode dari /home/scola/odoo, pada frontend develop@68b77d88f78b3d32f0ede3a54b665e067b014062 dan backend main@2ff6ac7cb41810bbc3b66821cdad004b52d1658a (2026-08-08). Hardening statis pada e749832/2ff6ac7 tidak otomatis menutup item AUTH tanpa fresh-account, scope, tenant-isolation, dan runtime regression evidence (../custom_addons_scola/gcgscola/scola_core/models/student_import_job.py:67-96; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:1407-1597).

Pedoman aktif yang dibaca: root dan frontend AGENTS.md, docs/ai-guidelines/AI_AGENT_MASTER_GUIDE.md, docs/ai-guidelines/development-guide.md, docs/ai-guidelines/workspace-governance.md, docs/ai-guidelines/architecture-api.md, docs/ai-guidelines/ui-design-pattern.md, docs/ai-guidelines/menu-architecture.md, docs/ai-guidelines/datetime-timezone.md, docs/ai-guidelines/rbac-user-management.md, docs/ai-guidelines/DOCUMENTATION_GOVERNANCE.md, serta docs/qa/testing-guidelines.md. Evidence juga mencakup seluruh docs/recon/ dan docs/documentation-planning/.

Backend adalah authority akhir; FE guard hanya UX, domain API wajib menggantikan raw RPC, dan scope harus ditegakkan sebelum elevasi (docs/ai-guidelines/rbac-user-management.md:13-18; docs/ai-guidelines/architecture-api.md:33-38). Karena itu menu/route/component presence tidak pernah menjadi bukti authorization.

Kesimpulan readiness

Authorization RED / belum release-ready. Dua kontradiksi platform telah confirmed secara statis:

  1. role switch hanya mengubah active persona; backend tetap menghitung union capability dari semua authoritative groups (../custom_addons_scola/gcgscola/scola_core/controllers/auth.py:485-518; ../custom_addons_scola/gcgscola/scola_core/services/auth_capabilities.py:709-771);
  2. route registry memilih prefix pertama, bukan exact/longest prefix, sehingga rule spesifik dapat ter-shadow (../custom_addons_scola/gcgscola/scola_platform_support/api_route_access.py:482-500).

Selain itu, existing blocker register membuktikan view/mutation collapse dan scope/elevation gaps pada supported candidates (docs/documentation-planning/documentation-blockers.md:92-282). QG-03, QG-06, QG-07, dan QG-11 tidak dapat lulus sebelum AUTH-001–AUTH-014 ditutup (docs/release-readiness/09-release-quality-gate.md:132-142).

Execution note — T0-A (2026-08-08)

Platform slices AUTH-001 / AUTH-003 and the mail-tracking slice of AUTH-009 have code fixes under docs/release-readiness/execution/T0-A-result.md. Status: Code fixed, runtime verification pending (not Closed).

Execution note — T0-B1 (2026-08-08)

DEC-002 approved: session-scoped active role implemented (session_active_role.py). Golden Tenant fixture foundation + B2 matrix prepared. STAB-005/007/008 remain not Closed until T0-B2 runtime acceptance. See docs/release-readiness/execution/T0-B1-result.md.

1. Non-negotiable invariant

Setiap request terhadap route supported, termasuk read, export, download, dan mutation, harus lulus seluruh faktor berikut:

authenticated principal
AND enabled product entitlement
AND active-role capability
AND record scope
AND tenant/company/school scope
AND domain ownership
AND valid state/action policy
= ALLOW

missing/unknown/ambiguous factor = DENY

Untuk mutation berisiko tinggi ditambah separation-of-duties/approval gate. FE menu/action visibility harus diturunkan dari kontrak yang sama, tetapi direct API denial tetap authoritative. Tidak ada implicit allow dari auth='user', group generic, active menu, model ACL saja, request-supplied ID, atau .sudo().

2. Current gap and closure register

ID Gap saat ini Required closure Decision dependency Release evidence
AUTH-001 Active role bukan enforcement context. Switch mengubah scola_role, sedangkan permissions tetap union authoritative groups. FE juga memprioritaskan backend permission list. Active role harus menjadi signed/session-owned acting context; effective capabilities dibentuk hanya dari active role, entitlement, and scope. Assigned roles hanya daftar role yang boleh dipilih. Break-glass terpisah, time-bound, reasoned, and audited. RP-01, AM-03 Multi-role fixture: capability eksklusif role A menjadi 403 setelah switch ke B; forged role rejected; audit records both principal and acting role. Evidence: ../custom_addons_scola/gcgscola/scola_core/controllers/auth.py:167-210,485-518; ../custom_addons_scola/gcgscola/scola_core/services/auth_capabilities.py:676-771; src/stores/auth.store.js:510-537.
AUTH-002 Action capability taxonomy tidak atomik. Beberapa mutation digate capability .view; manage juga dipakai sebagai umbrella yang tidak menjelaskan approve/post/configure. Gunakan capability <domain>.<resource>.<action> dan pisahkan view/list/detail/create/edit/delete/submit/approve/reject/post/reconcile/configure/export/download/unmask. manage hanya transitional alias bertanggal, tidak boleh memberi approve/post/configure secara implisit. RP-02, PO-02, AM-01, SG-01 Generated inventory menunjukkan setiap supported controller action tepat satu declared action capability; viewer mutation 403; maker cannot approve/post unless separately granted. Evidence cases: ../custom_addons_scola/gcgscola/scola_payroll/controllers/payslip_admin_api.py:33-66,391-558; ../custom_addons_scola/gcgscola/scola_student_activity/controllers/kesiswaan_domain_api.py:42-54,165-221,1032-1077; ../custom_addons_scola/gcgscola/scola_account/controllers/accounting_modules_api.py:20-59,69-167,212-300.
AUTH-003 First-prefix resolver dapat memilih rule salah. Registry memakai exact match atau deterministic longest-prefix; method/action collision invalid; overlap detector dan FE/BE parity gate fail CI untuk unapproved shadow. RP-02 Unit/contract test seluruh overlapping prefixes, termasuk library/fees/LMS; resolver report contains chosen exact rule. Evidence: ../custom_addons_scola/gcgscola/scola_platform_support/api_route_access.py:60,226,254,289,294,458,482-500; BLK-A03 docs/documentation-planning/documentation-blockers.md:104-114.
AUTH-004 Unregistered protected API sebelumnya dapat melewati capability gate (resolveNone). Extractor parity dan deny-by-default belum terbukti. Pisahkan public allowlist, session endpoints, and protected registry. Setiap supported protected Scola API wajib terdaftar atau explicit public/internal; unknown protected path ditolak. Controller tetap menjalankan action/scope policy sendiri. RP-02, SM-01 T0-A.1 code: extractor 1712 routes / 0 UNREGISTERED_PROTECTED_BLOCKER; fail-closed in ir.http; CI api_route_surface_coverage_check.py; fixture denial unit tests. Runtime Golden Tenant denial crawl = PENDING T0-B. Evidence: T0-A1-route-coverage.md; api_route_surface.py; api_route_access.py classification contract.
AUTH-005 Tenant/company/school ownership tidak konsisten pada elevated browse, search, and foreign keys. Set active company/school from server session; target record and every supplied foreign key must belong to permitted tenant/company/school. Cross-company requires explicit cross-unit capability, purpose, and audit. Validation is atomic and before elevation/write. RP-03, PR-03 Two-tenant tests for guessed IDs, mixed-company payload, foreign key injection, export, and list totals; unauthorized response leaks neither record nor count. Evidence gaps: fee enrollment ../custom_addons_scola/gcgscola/scola_fees/controllers/fee_enrollment_api.py:135-175,180-235,263-267; calendar ../custom_addons_scola/gcgscola/scola_portal/controllers/calendar_admin_api.py:23-83; accounting ../custom_addons_scola/gcgscola/scola_account/controllers/accounting_modules_api.py:20-59,69-167,212-300.
AUTH-006 Class/batch/teacher assignment scope belum menjadi reusable mandatory policy. W05 regular save tidak membandingkan exact roster; first-save depends on legacy ACL group. Central domain policies resolve teacher session assignment, homeroom scope, class/batch membership, and exact roster at event date. No request-supplied student/session is trusted. Fresh canonical role provisioning must satisfy model access without unrelated legacy group. RP-03, PO-01, MD-01, RB-02 Assigned teacher positive; unassigned teacher, out-of-batch student, duplicate, missing roster, stale assignment, cross-company session negative; all atomic. Evidence: ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:3335,3398-3422,4238-4275,4304-4334; ../custom_addons_scola/gcgscola/scola_attendance/security/ir.model.access.csv:4,8; ../custom_addons_scola/gcgscola/scola_core/security/scola_security.xml:88-93.
AUTH-007 Self and parent-child scope must never depend on arbitrary target IDs. Some current attendance portal paths appear relationship-aware, but cross-domain parity is not certified. Student identity is resolved from session user; parent children are server-derived relations. Child/resource IDs are accepted only after relation + company + purpose check. No “admin-like” fallback for missing identity. RP-03, PR-01, MD-01 Student cannot request peer; parent cannot request unrelated/removed child; multi-child works; relationship end-date takes effect; result minimises fields. Attendance entry evidence: src/services/attendance/studentAttendance.service.js:311-381; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:2942-3024; required baseline docs/documentation-planning/decision-workshop.md:43-45,91-93.
AUTH-008 Sensitive-record access and field projection are not a single purpose-based contract. Complaint, counseling, payroll, discipline, proof, and messages expose different controls. Define data classification and purpose matrix; list projection minimal; detail/export/download/unmask separately capable; assigned-case scope; access logging; retention/deletion. DPO approves viewer set and redaction. PR-01, PR-02 Role/field snapshot tests, unrelated actor denial, export/download negative tests, response-size/raw-byte assertions, retention/access audit. Evidence: counseling ../custom_addons_scola/gcgscola/scola_counseling/controllers/counseling_domain_api.py:39-59,81,171-174,233-236,314-338; messaging ../custom_addons_scola/gcgscola/scola_portal/controllers/general_messaging_api.py:439-482,520-550,945-982; attendance proof ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:2795-2796,2816-2833,4323-4324.
AUTH-009 Elevated operations and generic model/res_id endpoints can bypass domain ownership if scope is not proved first. Eliminate generic model endpoints from user surface where possible. Otherwise model/action allowlist + normal access rules + tenant/domain policy precede narrowly scoped elevation. Re-check record after elevation; never use unfiltered elevated search/browse from supplied IDs. RP-03, PO-02, PR-02/PR-03 Sudo/elevation inventory with reason; arbitrary model/res_id and cross-scope tests; model allowlist; no-existence leak. Evidence: contextual tracking ../custom_addons_scola/gcgscola/scola_core/controllers/core_reference_api.py:42-49; BOS attachment ../custom_addons_scola/gcgscola/scola_bos_rkas_procurement/controllers/procurement_admin_api.py:35-62,355-384; development budget docs/ai-guidelines/development-guide.md:430-443.
AUTH-010 Approve/post/configure and process ownership are not consistently separated. State/action policy combines capability + current state + record owner + maker-checker/delegation. Maker cannot approve/post own record unless an explicit, signed exception. Config scope is tenant/global and effective-dated; break-glass cannot silently become normal workflow. PO-01/PO-02, AM-01–AM-03, MD-03, SG-01/SG-03 Self-approval, invalid transition, substitute/delegation expiry, cross-company approval, post/reversal, and config effective-date tests. Existing risks: BOS repeated approval ../custom_addons_scola/gcgscola/scola_bos_rkas_procurement/models/purchase_request.py:142-164; notification config ../custom_addons_scola/gcgscola/scola_portal/controllers/notification_config_api.py:25-57; W05 correction ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:3398-3422,4307-4334.
AUTH-011 Audit attribution is not yet a release-wide mutation contract. Active persona, union groups, elevation, correction reason, and before/after are not uniformly bound. Immutable audit captures principal user, active/acting role, tenant/company/school, capability, route/action, object, before/after (redacted), reason, approval/delegation, elevation, idempotency/correlation key, outcome, and UTC time. Sensitive read/export/download also audited. RP-01, AM-02/AM-03, PR-01 Mutation and sensitive-read tests assert one audit record; failed/denied attempts recorded without secrets; role switch audit; chain/integrity verification. Existing privacy audit surface shows a partial foundation, not universal proof: ../custom_addons_scola/gcgscola/scola_core/controllers/privacy_api.py:122-198; current role switch logging ../custom_addons_scola/gcgscola/scola_core/controllers/auth.py:504-518.
AUTH-012 Menu → route → action → API parity is not guaranteed. FE can show mutation CTA to read-only roles; route capability and API capability can differ. One generated contract maps page ID, menu, route, action, service endpoint, registry capability, controller policy, scope policy, and product flag. FE consumes it for availability only; backend remains authority. Parity drift fails CI. RP-02, SM-01, CH-01 Role crawl: visible route loads, hidden route direct navigation denied, hidden mutation direct API denied; no visible-forbidden/hidden-unguarded cases. Evidence: W05 CTA drift src/views/AttendanceManagement/Admin/AttendanceSheetList.vue:9-20,192 vs ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:146-199,3335-3337; SSOT map docs/ai-guidelines/rbac-user-management.md:43-49.
AUTH-013 Provisioning/runtime role baseline is not frozen. Fresh roles can differ from legacy users/groups; presence of scola_roles, active role, and group fallbacks complicates effective rights. Versioned role catalog and migrations; fresh single-role fixtures plus intentional conflict/multi-role fixtures; no superadmin/legacy extras for normal E2E; role/group drift report on upgrade. RB-01, RB-02 Fresh provision → login → effective capability snapshot per role; old-to-new migration diff approved; unexpected group makes gate fail. Evidence: role sources ../custom_addons_scola/gcgscola/scola_core/services/auth_capabilities.py:646-771; baseline gap BLK-A01 docs/documentation-planning/documentation-blockers.md:80-90.
AUTH-014 Authorization evidence is fragmented and source-level tests alone cannot certify route/scope behavior. Every supported route/mutation links to positive, negative role, record scope, tenant, state, retry, audit, and FE/API parity tests. Required tests cannot be skipped; result tied to exact release manifest. RB-03 100% matrix coverage dan PASS pada Golden Tenant; before/after DB assertion untuk denial; tidak ada path normal yang hanya lulus dengan superadmin. Required gate docs/release-readiness/09-release-quality-gate.md:132-142 (QG-03/QG-06/QG-07/QG-11) dan result semantics docs/release-readiness/09-release-quality-gate.md:67-96.

3. Proposed principal and active-role semantics

3.1 Canonical concepts

Concept Proposed contract
Principal Authenticated res.users identity. Immutable for request/audit.
Assigned roles Eligible named roles provisioned to principal and backed by authoritative security mapping. They grant eligibility to switch, not simultaneous request authority.
Active/acting role Exactly one role in server session for normal requests. It selects capability set and is recorded in every protected request/mutation audit.
Odoo groups Implementation mechanism for model access and role eligibility; not a second, hidden union authority at controller boundary.
Effective capability Capability granted to active role, enabled package, and explicit contextual delegation, never arbitrary union of assigned roles.
Delegation Named domain/action scope, source approver, delegate, company, start/end, reason, no self-approval expansion, revocable and audited.
Break-glass Internal/elevated path outside normal menu, explicit purpose/reason, time bound, separately capable, alerting and review. It does not make superadmin a valid normal E2E actor.

Recommended default: accept RP-01’s active-role enforcement model. If Product/Security chooses union permissions instead, Scola cannot claim persona-based least privilege; finance/payroll/counseling combinations would require separate-account or conflict-role restrictions. This is a product/security decision, not an engineering bug resolution (docs/documentation-planning/decision-workshop.md:43-45).

3.2 Request evaluation order

  1. Authenticate session and CSRF/request integrity as applicable.
  2. Resolve principal, active role, active company/school, assigned roles, and entitlements from server-owned session; ignore forged payload fields.
  3. Resolve an exact/longest route action entry. Unknown protected route: deny.
  4. Require package entitlement/feature and active-role action capability.
  5. Resolve target through a domain service in permitted company context; do not elevated-browse arbitrary ID first.
  6. Apply record scope (self/child/assigned class/batch/session/case/department, as applicable).
  7. Validate domain ownership and all foreign keys against tenant/company/school.
  8. Validate current state, mutation authority, maker-checker/delegation, and business prerequisites.
  9. Elevate only the minimal operation after all gates, rechecking target invariants atomically.
  10. Persist mutation and audit attribution in one transaction; return field-minimized response.

Any failure returns a safe denial/validation/conflict response and produces no partial side effect. A 403 must not be converted into empty data in FE.

4. Capability taxonomy

Proposed canonical shape:

<domain>.<resource>.<action>
Action family Canonical actions Rule
Read view, list, detail List/detail may have different field projection; view never mutates.
Create/update create, edit, delete, archive, restore, import Each has record/tenant scope and validation. Delete is never implied by edit.
Workflow submit, approve, reject, cancel, close Bound to transition and SoD policy; cannot be implied by generic manage.
Finance post, reconcile, receive_cash, refund, waive Separate from view/edit and normally maker-checker/audit constrained.
Configuration configure, optionally activate/deactivate Names tenant/global scope and effective-date policy.
Data egress export, download, unmask, print_sensitive Separate from onscreen list/detail for data minimization.
Elevated impersonate, break_glass, cross_company Internal-only, reason/time/audit required; never inherited from school admin.

Exact capabilities are generated only after RP-02 and domain owner decisions. The table defines separation, not permission grants to particular roles.

5. Scope and ownership policies

Scope Required policy Recommended default pending approval Mandatory negative tests
Tenant/company Target and every foreign key belong to active allowed company; company is server-resolved. One active school/company per normal mutation. Explicit cross-company reads only for approved foundation/platform roles. Guessed ID, mixed-company payload, changed active company, inactive company, export/list count leak.
School level User's approved, recognized school-level assignment intersects record level and company. Missing, unknown, unsupported, expired, or unassigned jenjang is DENY, never an implicit non-early-years fallback. No implied all-level access from generic staff role; menu and direct route must use the same recognized-code predicate as backend scope. Same company but other jenjang; empty/malformed/unsupported code; missing/expired assignment; direct URL despite hidden menu. Current drift: src/config/schoolJenjang.js:47-55 versus src/router/teacherRouteFragments/attendance.js:7-17; STAB-044.
Class/batch Event-date membership and actor assignment validated by domain policy. Admin-scoped roles according to approved catalog; teacher only assigned session/batch; homeroom only assigned homeroom scope unless separate subject assignment. Other batch, stale transfer, duplicate/missing roster, forged session/student.
Teacher assignment Faculty relationship plus timetable/session ownership at effective date. No access derived merely from teacher role. Teacher peer’s session, future/past assignment boundary, combined session child outside scope.
Student self Identity resolved from session-to-student link. Read/mutate only explicit self endpoints approved by domain. Supplied peer ID, missing/multiple ambiguous identity, cross-company identity.
Parent-child Active server-side parent-child relationship plus company/purpose. Read only approved child projection; no school-wide lookup. Unrelated/removed child, guessed child ID, attachment/download from another child.
Case/record owner Counselor, complaint handler, librarian, HR/finance operator assignment is explicit and effective-dated. Capability grants action eligibility; assignment grants record scope. Same role but unassigned case/department, reassigned/closed record.
Domain ownership Named process owner defines actor, transition, approval, and correction/reversal. No “school admin owns everything” fallback without explicit signed policy. Direct API action outside state/ownership, self-approval, expired delegation.

6. Sensitive data, elevated operations, and audit

Sensitive records

At minimum payroll, counseling, complaints, discipline/permits, attendance proof, messages/attachments, student/parent identity, and financial records require purpose-based projections. List endpoints must not return raw proof or full sensitive detail merely because detail/download may be authorized. Export/download/unmask receive separate capabilities and audits. PR-01–PR-03 and DPO sign-off remain blocking decisions (docs/documentation-planning/decision-workshop.md:91-93).

Elevated operations

  • .sudo() or equivalent elevation is not an authorization decision.
  • Target IDs/foreign keys are resolved and validated in scoped domain service first.
  • Generic model/res_id is removed from supported user surface or restricted by explicit model/action allowlist and native record rules.
  • No elevated helper accepts a view capability for mutation.
  • Break-glass is a separate internal platform workflow with reason, expiry, notification/review, and no normal menu exposure.

The repository’s own backend budget requires capability plus company/assignment filter before any necessary controller .sudo() (docs/ai-guidelines/development-guide.md:430-443).

Audit attribution contract

Every protected mutation and sensitive data access records, without secrets/raw sensitive payload:

  • principal user ID and immutable login/identity reference;
  • active/acting role and any delegation/break-glass reference;
  • active tenant/company/school and record company;
  • capability, route/action, domain/resource/record ID;
  • state/before/after diff with approved redaction;
  • reason, approver/maker relationship, idempotency key, correlation ID;
  • elevation used, outcome, denial/error class, UTC timestamp; and
  • source client/build where available.

Audit write must participate in the mutation transaction or use a guaranteed outbox with failure policy; an unaudited high-risk mutation must fail closed. Sensitive-read audit APIs already provide a partial mechanism (../custom_addons_scola/gcgscola/scola_core/controllers/privacy_api.py:122-198), but baseline requires coverage proof per supported domain.

7. Mapping seluruh Blocker A ke authorization closure

Items with non-authorization business/state defects remain listed so they cannot disappear behind an RBAC fix.

Blocker AUTH mapping Required fix / decision Mandatory tests for closure
BLK-A01 Runtime baseline AUTH-013, AUTH-014 Named build/tenant/module/role fixtures and approved supported surface. Fresh-role login/capability snapshots, module/entitlement on/off, exact manifest; QG-01/QG-04/QG-17. Evidence docs/documentation-planning/documentation-blockers.md:80-90.
BLK-A02 Multi-role union AUTH-001, AUTH-011, AUTH-013 Implement RP-01; active role constrains API; conflict/delegation model; acting-role audit. Switch A→B positive/negative, forged role, concurrent tabs/session refresh, conflict-role SoD. Evidence ../custom_addons_scola/gcgscola/scola_core/controllers/auth.py:485-518; ../custom_addons_scola/gcgscola/scola_core/services/auth_capabilities.py:709-771.
BLK-A03 Prefix shadow AUTH-002–AUTH-004, AUTH-012/014 Exact/longest match; overlap detector; action capability split and FE/BE parity. Specific library/fee/LMS rule tests, all overlap order permutations, unregistered protected route denial. Evidence ../custom_addons_scola/gcgscola/scola_platform_support/api_route_access.py:60,226,254,289,294,458,482-500.
BLK-A04 Complaint AUTH-002, AUTH-004/005, AUTH-008/009/011 Explicit public/internal contract; operator action/case scope; anti-abuse; attachment/privacy rules. PO-02, PR-01/02. Anonymous abuse, size/type, unassigned operator, cross-company, attachment download, redaction/retention/audit. Evidence ../custom_addons_scola/gcgscola/scola_public_complaint/controllers/public_complaint_api.py:107-120,140-155,223-231,351-405,440-478.
BLK-A05 Promotion helper failure AUTH-002, AUTH-004, AUTH-010/014 Restore explicit guard, define maker/approver and rollback; this is also a functional defect, not solved by capability names. Startup/import, authorized/unauthorized list/action, self-approval, transition, rollback. Evidence ../custom_addons_scola/gcgscola/scola_report_card/controllers/promotion_admin_api.py:21-24,63-172.
BLK-A06 Counseling AUTH-002, AUTH-005/006, AUTH-008–AUTH-011 Split view/respond/refer/close/export; counselor/case/company scope; sensitive projection and emergency policy. Viewer mutation, cross-counselor/company/student/parent, export, break-glass and audit. Evidence ../custom_addons_scola/gcgscola/scola_counseling/controllers/counseling_domain_api.py:39-59,81,171-174,233-236,314-338.
BLK-A07 Payroll AUTH-001/002, AUTH-005, AUTH-008, AUTH-010/011 Self/operator/reviewer/approver/auditor actions; employee/company scope, SoD and field projection. Self sees only own; viewer cannot mutate; cross-company; confirm/cancel/draft/refund/batch state/SoD; sensitive audit. Evidence ../custom_addons_scola/gcgscola/scola_payroll/controllers/payslip_admin_api.py:33-66,391-558; ../custom_addons_scola/gcgscola/scola_payroll/controllers/payroll_api.py:37-149,274-354.
BLK-A08 Kesiswaan AUTH-002, AUTH-005/006, AUTH-008, AUTH-010/011 Domain actions and class/case/company ownership; approve/reject split. Viewer mutation; other class/case; maker self-approval; transition and audit. Evidence ../custom_addons_scola/gcgscola/scola_student_activity/controllers/kesiswaan_domain_api.py:42-54,78-84,165-221,1032-1077.
BLK-A09 Accounting AUTH-002/003, AUTH-005, AUTH-009–AUTH-011 Split view/create/edit/post/reconcile/approve; scoped service before elevation; Finance approval matrix. Viewer mutation, cross-company ledger/budget, self-post/reconcile, invalid/repeated action, immutable audit. Evidence ../custom_addons_scola/gcgscola/scola_account/controllers/accounting_modules_api.py:20-59,69-167,212-300.
BLK-A10 BOS/RKAS AUTH-002/003, AUTH-005, AUTH-009–AUTH-011/014 State/idempotency guard, SoD, attachment ownership/type/size/scan. Repeated/concurrent approval one effect; invalid state; viewer; cross-company/model attachment; audit/reversal. Evidence ../custom_addons_scola/gcgscola/scola_bos_rkas_procurement/models/purchase_request.py:142-164; ../custom_addons_scola/gcgscola/scola_bos_rkas_procurement/controllers/procurement_admin_api.py:35-62,355-384.
BLK-A11 Dapodik AUTH-002/003, AUTH-005/006, AUTH-009–AUTH-011/014 View/config/sync split; tenant-scoped identifiers; approved source ownership, preview/diff, idempotency and recovery. NISN/NUPTK/rombel cross-tenant collision; viewer sync; preview/write equality; concurrent/retry; rollback/audit. Evidence ../custom_addons_scola/gcgscola/scola_dapodik_connector/controllers/dapodik_api.py:22-95,214-313,327-435,474-571.
BLK-A12 Contextual tracking AUTH-004/005, AUTH-008/009/011 Remove generic user surface or enforce model/action allowlist, native access rules, domain/company ownership. Arbitrary model rejected; guessed inaccessible record 403 without existence leak; allowed model positive; audit. Evidence ../custom_addons_scola/gcgscola/scola_core/controllers/core_reference_api.py:42-49.
BLK-A13 SPMB config AUTH-002/003, AUTH-005, AUTH-010–AUTH-012 View/configure/delete separation; company/effective-date/reference protection; SC-ADM entitlement. Viewer mutation, cross-company, referenced delete, flag off, audit/rollback. Evidence ../custom_addons_scola/gcgscola/scola_admission/controllers/admission_config_api.py:31-58,268-295,327-352,393-424,451-476,532-554.
BLK-A14 Fee enrollment AUTH-005/006, AUTH-009/014 Validate ownership of enrollment, student, course, batch, schedules before read/write. Cross-company target and mixed foreign keys denied atomically; list/lookups filtered; guessed detail ID. Evidence ../custom_addons_scola/gcgscola/scola_fees/controllers/fee_enrollment_api.py:135-175,180-235,263-267.
BLK-A15 Messaging AUTH-005, AUTH-007–AUTH-009/011 Membership on every batch item; attachment linked to accessible channel/message; safe field allowlist. Unauthorized/mixed channel batch no leak; unrelated attachment; revoked member; parent/student privacy; read/download audit. Evidence ../custom_addons_scola/gcgscola/scola_portal/controllers/general_messaging_api.py:439-482,520-550,945-982.
BLK-A16 Calendar AUTH-002, AUTH-005/006, AUTH-009–AUTH-012 Manage capability; owner/company/event scope; attendee scope and notification policy. Viewer save, guessed event/user, cross-company attendee, owner transfer, cancellation/invite audit. Evidence ../custom_addons_scola/gcgscola/scola_portal/controllers/calendar_admin_api.py:23-83.
BLK-A17 Settings AUTH-002/005, AUTH-010–AUTH-012 Separate company/notification view/configure; tenant vs global ownership, secret handling, approval/audit. Viewer write; tenant/global isolation; secret non-return/log; rollback/effective date; route/CTA/API parity. Evidence src/router/settingsRoutes.js:34-39; ../custom_addons_scola/gcgscola/scola_core/controllers/company_settings_api.py:119-125,205-249; ../custom_addons_scola/gcgscola/scola_portal/controllers/notification_config_api.py:25-57.
BLK-A18 Placeholder/register AUTH-004, AUTH-012–AUTH-014 Remove/hide unless product-supported and fully registered; incomplete route must not be reachable by supported roles. Role route/menu crawl zero visible placeholder; direct route/API denied/removed; no registry orphan. Evidence docs/recon/open-questions.md:41-50; docs/documentation-planning/documentation-blockers.md:284-294.
BLK-A19 W05 first save AUTH-001, AUTH-006, AUTH-013/014 Canonical teacher provisioning/model access or scoped service; no unrelated legacy group/broad sudo. Fresh teacher first save; unassigned teacher denied; create/write/read ACL regression. Evidence ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:4304-4332; ../custom_addons_scola/gcgscola/scola_attendance/security/ir.model.access.csv:4,8.
BLK-A20 W05 roster AUTH-005/006, AUTH-009/014 Exact effective-date roster, duplicate/membership/company/completeness check on all save paths. Missing/duplicate/out-of-batch/zero/cross-company rejected with zero partial writes; exact roster positive. Evidence ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:3335,3398-3422,4238-4275,4307-4334.
BLK-A21 W05 correction AUTH-002, AUTH-006, AUTH-010/011/014 PO-01/AM-02/SG-01 state/owner decision; distinct complete/correct action, reason/window/approval/audit. Invalid/late correction; teacher/admin/principal policies; before/after/reason audit; downstream propagation. Evidence ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:3398-3422,4307-4334; src/views/AttendanceManagement/Faculty/AttendanceSheet.vue:667-671,733-772.
BLK-A22 W05 status glossary AUTH-002, AUTH-010/014 (authorization-adjacent) SG-02 decides canonical state/subtype; enforce allowed transition/action and migrate serializers/aggregates. Auth alone cannot close semantic defect. Status round-trip, aggregation, invalid value, actor-specific transition, legacy-row interpretation. Evidence src/i18n/attendanceStatus.js:33-54; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:63-73,2855-2875,4313-4324.
BLK-A23 W05 proof AUTH-005, AUTH-007–AUTH-009/011/014 PR-01/02 viewer/retention policy; server file controls; authorized download; no raw proof in list payload. MIME/size/signature/malware, parent-child/company denial, field projection, retention/delete, sensitive access audit. Evidence src/views/AttendanceManagement/Faculty/AttendanceSheet.vue:315-319,592-603,749-750; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:2795-2796,2816-2833,4323-4324.

8. Decision dependencies — not engineering bugs

Engineering must not silently encode the recommended defaults below. These decisions are tracked separately from S0–S3 defects in 08-stabilization-backlog.md.

Decision Why it blocks authorization Required owner
RP-01 Select active-role enforcement, union permission, or separate-account policy. Security Owner + Product Owner
RP-02 Approve action-level capability taxonomy and migration from .view/manage. Security + Platform Auth Owner
RP-03 / PR-03 Approve company/school/class/assignment/self/child/cross-company baseline. Security + DPO + domain owners
PO-01 / AM-02 Name W05 record/complete/correct actors, cutoff, approval and exception path. Attendance SME + Product Owner/Operations
PO-02 / AM-01 Assign process owner and maker-checker rules for sensitive/high-impact domains. Product Owner + Finance/HR/Academic owners
AM-03 Define delegation, substitute approver and conflict-of-interest. Product + Security + Operations
SG-01–SG-03 Define state meanings, irreversibility, and recovery that capability checks must enforce. Domain Product Owners + SMEs
MD-01–MD-03 Define master-data ownership, matching/deletion, and config ownership/effective dates. Data Steward + Integration/domain owners
PR-01–PR-02 Define sensitive field and attachment viewer/purpose/retention matrix. DPO + Security + Storage/domain owners
RB-01–RB-03 Name baseline environment, representative fixtures, and evidence required for authorization certification. Operations + QA + Identity/RBAC Owner

Question and recommended options are evidence-backed in docs/documentation-planning/decision-workshop.md:43-45,51-77,91-93,115-117.

9. Required authorization test portfolio

Test family Minimum matrix Pass criterion
Active-role/multi-role Single-role each supported role; multi-role non-conflict; conflict-role; switch; forged role; session refresh/concurrent tab. Effective API permissions match active-role contract; no residual union; audit attribution exact.
Capability/action Every supported route and mutation; view-only, action-capable, unrelated role, direct API. Authorized action succeeds; all other actions 403; denied request changes no data.
Registry/deny-default Exact, overlapping prefix, method/action, unknown protected route, explicit public route. Deterministic exact/longest match; no unintended overlap; unknown protected denied.
Tenant/company/school Own tenant plus second tenant, same-company other level, cross-company FK, changed active company, list/export. No cross-scope data/existence/count/mutation leak; all writes atomic.
Assignment/record Assigned/unassigned teacher, homeroom, class/batch transfer date, case owner, department, roster. Event-date scope enforced on read/write; stale/forged assignment denied.
Self/parent-child Self, peer, linked/unlinked/expired child, multiple children, guessed ID/download. Only server-derived relation permitted; minimal projection.
Sensitive data Viewer/detail/export/download/unmask, redaction, retention, audit, large/raw attachment. Purpose matrix exact; raw sensitive bytes absent from list; every sensitive access audited.
Elevation All .sudo()/elevated paths, arbitrary IDs/model, cross-domain/cross-company. Authorization/scope precedes elevation; no generic bypass; reason inventory complete.
SoD/state Maker, approver, self-approval, delegate expiry, invalid transition, post/reconcile/correct/reverse. Only approved matrix/state works; actor/reason/before-after audited.
FE/API parity Menu visibility, direct route, action button, service API, controller capability, feature off/on. Zero visible-forbidden or hidden-unguarded case; direct API remains secure.
Provisioning/migration Fresh role, legacy migrated role, unexpected group, module entitlement on/off. Expected group/capability snapshot only; drift fails; no superadmin dependency.
Failure/retry Denied request, timeout, duplicate token, concurrent mutation, audit/outbox failure. No partial/duplicate effect; high-risk mutation fails closed if required audit unavailable.

All cases require exact FE/BE/database/module build, Golden Tenant and second-tenant fixtures, before/after assertions, and no required skip. This follows the release result/evidence rules in docs/release-readiness/09-release-quality-gate.md:67-96.

10. Implementation closure sequence

  1. Decide: close RP-01–RP-03, PR-03, RB-01/02; classify every supported route/action before code changes.
  2. Platform contract: implement active-role context, action taxonomy, exact/longest registry and protected-route deny default; version the contract.
  3. Shared policy services: tenant/company/school, assignment/class/batch, self/child, case ownership, sensitive projection, and audit/elevation wrappers.
  4. High-risk migrations: complaint, counseling, payroll, kesiswaan, accounting, BOS/RKAS, Dapodik, contextual tracking, SPMB config, fees, messaging, calendar, settings, and W05; remove unsupported surfaces rather than carrying accidental access.
  5. FE parity: canonical menu/route/action availability consumes the approved contract; aliases/legacy surfaces cannot bypass it.
  6. Runtime certification: fresh-role and multi-role tests, second-tenant isolation, SoD/state/privacy, served-bundle role crawl, exact release manifest.

Definition of authorization-ready

Authorization is ready only when:

  • AUTH-001–AUTH-014 are closed or explicitly out of approved product scope;
  • every supported route/mutation has named capability, record scope, tenant/company/school scope, domain owner, state policy, audit policy, and tests;
  • active role semantics and all critical business/security decisions are signed;
  • backend deny-by-default and FE/API parity tests are 100% PASS;
  • cross-tenant, assignment, self, parent-child, sensitive-data, elevated-operation, SoD and audit tests are 100% PASS;
  • no open S0/S1 authorization defect and no security/privacy issue is treated as Accepted Limitation; and
  • evidence is tied to the exact Scola V1 release manifest, not merely these source snapshots.