Lewati ke isi

Scola V1 Production Baseline — Information Architecture Audit

Status: Proposed canonical IA for approval. Current navigation is inventory evidence, not approved product design. No source code was changed by this audit.

Metadata Value
Last verified 2026-08-08 UTC
Mode / workspace Server development, static read-only audit; /home/scola/odoo
Frontend baseline scola-fe-v2 develop @ 68b77d88f78b3d32f0ede3a54b665e067b014062
Backend baseline custom_addons_scola/gcgscola main @ 2ff6ac7cb41810bbc3b66821cdad004b52d1658a
Product boundary Proposed product contract
Release gates QG-02 canonical IA, QG-03 authorization, QG-14 package separation, QG-18 freeze
Runtime limitation Tenant module state, entitlement, effective permissions, served bundle, breadcrumbs, and actual click/403 behavior were not certified here

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/menu-architecture.md, docs/ai-guidelines/DOCUMENTATION_GOVERNANCE.md, serta seluruh evidence docs/recon/ dan docs/documentation-planning/ yang dirujuk. Delta backend e749832/2ff6ac7 mengeraskan ACL/elevation dan topology pins, tetapi tidak mengubah inventaris app/menu/route FE; tanpa bukti runtime, delta itu belum membuat QG-02 GREEN (../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; docs/documentation-planning/product-surface-candidates.md:420-430).

1. Executive finding and audit method

QG-02 is RED. Source saat ini mempunyai satu apps-based registry, tetapi belum merupakan satu product IA: 36 shell memuat 143 group dan 528 leaf; role registry memiliki 33 role; recon mencatat 1.003 effective route records (884 component pages, 119 redirect/alias); model statis menemukan 79 leaf yang dapat tampil tetapi ditolak route. Angka route dan denial berasal dari docs/recon/route-inventory.md:10-18 dan docs/recon/role-permission-matrix.md:983-1105. Current registry dan consumer contract berada di src/config/apps/index.js:1-100, src/config/apps/roleApps.js:1-951, dan src/composables/useApps.js:270-340,670-731.

Audit ini membedakan empat identitas yang tidak boleh dihitung sebagai empat produk:

  1. Product task — outcome yang disetujui dalam package/workflow contract.
  2. Canonical page — satu page identity dengan satu owner, walau dipakai beberapa role.
  3. Canonical route — URL utama untuk page identity itu.
  4. Compatibility route — alias/redirect sementara atau permanen yang tidak boleh menjadi menu, breadcrumb, analytics dimension, atau target dokumentasi terpisah.

Read-only current-code extraction mengonfirmasi 36 app, 143 group, 528 leaf, dan 33 ROLE_APPS entries. Dari leaf tersebut terdapat 36 route key berulang pada 122 leaf instances. Sebagian adalah reuse yang sah lintas role (/calendar, /news, employee self-service); sebagian adalah duplicate IA. Karena registry tidak menyimpan canonicalPageId atau alias owner, semuanya memerlukan klasifikasi eksplisit sebelum freeze. Status Confirmed from code hanya berlaku pada struktur source; impact tenant tetap Requires runtime verification.

1.1 Current navigation mechanics

Layer Current contract Audit conclusion
App registry APP_REGISTRY adalah ordered list global dan lookup by ID; consumers termasuk launcher/header/search (src/config/apps/index.js:1-100). Satu registry adalah fondasi yang benar, tetapi isinya belum mengikuti approved package boundary.
Role composition ROLE_APPS mengatur app order, default/home, desktop/mobile mode, hidden nodes, pin, dan quick access (src/config/apps/roleApps.js:1-32,57-951). Role configuration adalah presentation composition, bukan authorization SSOT.
Route authority Router memakai auth, capability, feature flag, allowed role, portal scope, dan admin-shell policy (src/router/routerGuardPolicy.js:1-220). Menu visibility dan route/API authority harus dihitung dari contract yang sama; current denials membuktikan drift.
Breadcrumb useApps mencari longest route/context match dan menyusun App → Section → Leaf; detail tail ditambahkan terpisah (src/composables/useApps.js:285-340,670-731; src/composables/useBreadcrumbs.js:22-74; src/components/Topbar.vue:185-217). Hidden/direct/detail/alias route tidak otomatis mempunyai parent kanonis atau breadcrumb yang authorized.
Mobile SSOT meminta empat pinned task + Menu dan folder drill-down (docs/ai-guidelines/menu-architecture.md:22-67). Specialist compact-role exception ada di config tetapi audit script tidak memodelkannya konsisten.

2. Complete shell and menu-group disposition — 36 apps / 143 groups

Ledger ini mencakup setiap sections[]. Keep berarti candidate core group pada shell kanonis; entitle berarti pindahkan/pertahankan hanya dalam package yang aktif; withhold berarti tidak boleh muncul sampai product decision; remove berarti legacy/incomplete; internal berarti provider-only. Evidence per-group dan line source lengkap ada di docs/documentation-planning/product-surface-candidates.md:186-335; current app definitions berada di src/config/apps/appFragments/.

Current planning distribution adalah 13 core, 83 optional, 37 decision, 3 pilot, 4 incomplete, dan 3 internal groups. Proposed IA mengubah hanya analytics.executive dari decision menjadi legacy karena source sendiri menyebut app itu legacy (src/config/apps/appFragments/analyticsApp.js:1-6): hasil proposed disposition tetap tepat 143 = 13 keep + 83 entitle + 36 withhold + 3 pilot + 4 remove-incomplete + 3 internal + 1 remove-legacy.

App shell (group count) Keep in canonical core IA Entitle / controlled pilot Withhold, remove, or externalize Evidence
admin-dashboard (2) admin_dashboard.overview admin_dashboard.hr_personal (peer SC-PEOPLE/ATTEND+) src/config/apps/appFragments/adminDashboardApp.js:34-75
teacher-portal (9) teacher.today, teacher.school_calendar teacher.grades, teacher.digital_learning, teacher.kesiswaan, teacher.hr_personal, teacher.library Withhold mixed teacher.teaching, teacher.homeroom; split core leaves from package leaves src/config/apps/appFragments/teacherPortalApp.js:78-578
student-portal (7) student.school_calendar student.grades, student.discipline, student.library Withhold mixed student.today, student.learning, student.extras; rebuild each by package src/config/apps/appFragments/studentPortalApp.js:62-338
parent-portal (6) parent.dashboard parent.finance, parent.studentlife, parent.library Withhold mixed parent.academics, parent.communications; remove announcement leaf src/config/apps/appFragments/parentPortalApp.js:60-363
principal-exec (10) principal.finance_ops, principal.admissions, principal.library, principal.hr_personal only after entitlement and role approval Withhold principal.overview, principal.approvals_bucket, principal.academics, principal.people, principal.communication, principal.analytics src/config/apps/appFragments/principalApp.js:58-469
counselor (6) All six: counselor.overview, .students, .sessions, .pembinaan, .career, .hr_personal Keep SC-PEOPLE utility separate from sensitive SC-STUDENT workspace src/config/apps/appFragments/counselorApp.js:58-304
extracurricular-coach (1) extracurricular_coach.overview Consolidate two competing leaves to list → detail → attendance hierarchy src/config/apps/appFragments/extracurricularCoachApp.js:13-39
librarian (7) All seven: librarian.collection, .circulation, .textbook, .gls, .reports, .config, .attendance Move personal HR utility out of SC-LIB domain group src/config/apps/appFragments/librarianApp.js:47-331
lab-technician (5) Externalize lab.hr_personal only if SC-PEOPLE/ATTEND+ permits Remove lab.overview, .inventory, .maintenance, .reports and shell until implemented src/config/apps/appFragments/labTechnicianApp.js:37-158; docs/recon/open-questions.md:44-54
security-officer (1) Withhold security.overview; no approved package/owner src/config/apps/appFragments/securityOfficerApp.js:22-40
school-committee (1) Withhold committee.overview; no approved package/aggregate audience src/config/apps/appFragments/schoolCommitteeApp.js:22-40
bos-admin (1) Pilot bos.overview Never leak into core finance/inventory IA src/config/apps/appFragments/bosAdminApp.js:23-61
dapodik-operator (1) Pilot dapodik.overview Never leak into core settings/report-card IA src/config/apps/appFragments/dapodikOperatorApp.js:24-55
dpo (1) Withhold dpo.overview pending privacy/compliance product contract src/config/apps/appFragments/dpoApp.js:23-52
foundation-auditor (1) foundation_auditor.overview Read-only scope must be proven src/config/apps/appFragments/foundationAuditorApp.js:24-65
pickup-officer (1) Withhold pickup.tasks; pickup is not W05/manual attendance src/config/apps/appFragments/pickupOfficerApp.js:20-31
admin-staff (6) Move admin_staff.academics task to canonical Academic app admin_staff.admissions, .finance, .hr_personal after entitlement Withhold admin_staff.overview, .students until role/package scope closes src/config/apps/appFragments/adminStaffApp.js:43-243
foundation (6) All six foundation groups, with each peer finance/people/admission/attendance entitlement enforced Generic foundation role itself remains withheld until catalog closure src/config/apps/appFragments/foundationApp.js:49-250
foundation-hr-ops (6) All six: foundation_hr.people, .structure, .operations, .leave, .compensation, .personal Split SC-PEOPLE, SC-ATTEND+, and transport entitlements src/config/apps/appFragments/foundationHrOperationsApp.js:42-254
vp-curriculum (4) vp_curriculum.hr_personal after peer entitlement Withhold vp_curriculum.overview, .academics, .review; do not invent approval authority src/config/apps/appFragments/vicePrincipalApps.js:72-211
vp-student-affairs (5) vp_sa.guidance, .admissions, .hr_personal after role/package approval Withhold vp_sa.overview, .core src/config/apps/appFragments/vicePrincipalApps.js:225-398
vp-infrastructure (4) vp_inf.inventory, .hr_personal after role/package approval Withhold vp_inf.overview, .approval_maintenance src/config/apps/appFragments/vicePrincipalApps.js:409-508
vp-public-relations (4) Move vp_pr.communication tasks to canonical Communication app vp_pr.admissions, .hr_personal after entitlement Withhold vp_pr.overview src/config/apps/appFragments/vicePrincipalApps.js:525-602
vp-finance (3) vp_fin.core, .hr_personal after role/package approval Withhold vp_fin.overview src/config/apps/appFragments/vicePrincipalApps.js:616-686
academic (7) academic.master academic.assessment, .report_card, .lms, .cbt Split mixed academic.schedule; withhold legacy-vs-CBT academic.exam decision src/config/apps/appFragments/academicApp.js:51-377
student-affairs (2) student-affairs.data student-affairs.pembinaan src/config/apps/appFragments/studentAffairsApp.js:47-146
hr (3) hr.employees, hr.attendance, hr.leave under SC-PEOPLE/ATTEND+ src/config/apps/appFragments/hrApp.js:35-186
finance (8) finance.spp, .payables, .receivables, .cash, .reports, .config_assets, .hr_personal Withhold mixed finance.budget_approval; split SC-FIN/SC-BOS src/config/apps/appFragments/financeApp.js:61-452
inventory (7) inventory.master, .operations, .assets, .reports, .hr_personal; pilot inventory.budget Withhold inventory.procurement until SC-OPS/SC-BOS ownership closes src/config/apps/appFragments/inventoryApp.js:63-351
library (2) library.management, library.portal Merge page identities with librarian; do not create duplicate articles/routes src/config/apps/appFragments/libraryApp.js:47-253
admissions (2) admissions.pipeline, admissions.config Optional assessment/foundation/fees leaves need peer entitlement src/config/apps/appFragments/admissionsApp.js:30-142
attendance (3) attendance.rfid, attendance.face.students only under SC-ATTEND+ Withhold mixed attendance.students until W05/pickup/settings split; W05 remains pilot src/config/apps/appFragments/attendanceApp.js:38-128
analytics (1) Remove legacy analytics.executive; link approved destinations from their owning domain src/config/apps/appFragments/analyticsApp.js:1-59; src/router/analyticsAdminRoutes.js:1-49
communication (5) communication.news, .calendar, .notifications Withhold communication.messaging, .complaints; remove legacy announcement page src/config/apps/appFragments/communicationApp.js:24-125
settings (2) settings.access Split mixed settings.school into core company settings plus package-specific configuration src/config/apps/appFragments/settingsApp.js:36-112
platform (3) Internal-only platform.ops, .tenants, .observability src/config/apps/appFragments/platformApp.js:26-132

3. Proposed canonical IA by role — 33/33 current role compositions

Ini adalah IA proposal, bukan grant. Supported di sini selalu berarti sesudah package, capability, record scope, tenant scope, domain owner, dan E2E disahkan. Role yang product contract-nya belum diputuskan diberi withhold, bukan diberi menu berdasarkan kode kebetulan. Current assignments/denials dapat diverifikasi di docs/recon/role-permission-matrix.md:983-1020; exact role composition ada di src/config/apps/roleApps.js:57-951.

Current role Proposed canonical navigation Product disposition / release condition Evidence
admin Tidak menjadi school workflow persona; technical/break-glass entry terpisah dari school launcher Internal/elevated contract must be approved; never use wildcard admin as ordinary E2E proof src/config/apps/roleApps.js:57-104; src/config/roles.js:10-42
school_admin Home → Academic → Students → Attendance → Communication → Settings; optional apps appear only as separately entitled domains Core V1 candidate; remove Analytics and all unavailable apps src/config/apps/roleApps.js:105-152
teacher Section-first Teacher portal: Today, Calendar, Teaching core; optional Report, Learning, Student Services, Library, Personal as entitled folders Core shell; W05 mutation remains controlled pilot src/config/apps/roleApps.js:153-194
extracurricular_coach One SC-STUDENT workspace: list → activity detail → attendance sessions; account utility only Optional Supported after duplicate/home fixes and assignment scope tests src/config/apps/roleApps.js:195-211
student Student home with core Calendar/Schedule/Attendance; each optional package becomes a separate folder Core portal; self-scope and enabled-package proof required src/config/apps/roleApps.js:212-244
parent Parent home → child context → core schedule/attendance/news/calendar; finance/report/learning/student-service/library folders by entitlement Core portal; every page must retain selected-child scope src/config/apps/roleApps.js:245-263
principal Withhold current cross-domain shell; after decision, one executive read/approval inbox whose actions link to owning domain Requires Product Decision; no implicit approve/edit rights src/config/apps/roleApps.js:264-315
platform_operator Platform Operations → Tenants → Observability; no school-user domain apps Internal Platform and separate shell/audit session src/config/apps/roleApps.js:316-334
admin_staff Withhold synthetic mixed shell; approve task set, then reuse canonical Academic/Student/Admissions/Fees pages Requires Product Decision and route parity src/config/apps/roleApps.js:335-361
pickup_officer Withhold; if approved later, dedicated pickup/transport task shell, never Attendance W05 Requires Product Decision/privacy/child-release owner src/config/apps/roleApps.js:362-372
counselor Sensitive SC-STUDENT workspace: caseload → session → follow-up; optional Library/Personal utilities separated Optional Supported only after least-privilege/DPO closure src/config/apps/roleApps.js:373-403
librarian Library dashboard → Collection → Circulation → Textbook → GLS → Reports → Configuration; account utility outside domain Optional Supported; one canonical Library page family src/config/apps/roleApps.js:404-431
lab_technician No customer launcher until pages are implemented; optional employee self-service accessed from account shell only Incomplete / Remove from Product Surface src/config/apps/roleApps.js:432-460; docs/recon/open-questions.md:44-54
dpo Withhold until audit/consent purpose, data classes, retention, export, and authority are approved Requires Product Decision src/config/apps/roleApps.js:461-475
security_officer Withhold until visitor/security package and school scope are approved Requires Product Decision src/config/apps/roleApps.js:476-486
school_committee Withhold until aggregate audience and confidentiality contract are approved Requires Product Decision src/config/apps/roleApps.js:487-497
bos_admin Dedicated BOS pilot: Dashboard → Budget/RKAS → Procurement → Ledger/Reports; no general Finance app Controlled Pilot; SC-FIN + SC-OPS and maker-checker gates src/config/apps/roleApps.js:498-517
dapodik_operator Dedicated Dapodik pilot: Status → Preview → Sync → Conflict/Recovery; related report/attendance links only when companions enabled Controlled Pilot with kill switch and tenant mapping src/config/apps/roleApps.js:518-536
foundation_auditor Read-only Foundation audit workspace; no mutation controls Optional Supported after cross-company/foundation scope proof src/config/apps/roleApps.js:537-556
inventory_officer SC-OPS Inventory app only; Finance links only for an approved integration task; personal utility outside domain Optional Supported; BOS nodes pilot-only src/config/apps/roleApps.js:557-588
foundation Withhold generic role; use an approved canonical foundation role instead Requires role-catalog Product Decision despite optional foundation app src/config/apps/roleApps.js:589-620; ../custom_addons_scola/gcgscola/scola_core/services/role_catalog.py:7-40
foundation_hr_admin Foundation HR: People → Structure → Leave → Compensation; Attendance/Transport only by peer entitlement Optional Supported after one-role/one-scope closure src/config/apps/roleApps.js:621-649
foundation_chairman Foundation executive read/approval shell with separately entitled domains; remove legacy Analytics shortcut Optional Supported after approval matrix and company aggregation proof src/config/apps/roleApps.js:650-682
head_admin Withhold current mixed assignment; after role decision use task-scoped school operations IA and canonical domain pages Requires role/route parity; 15 modeled denials cannot be normalized src/config/apps/roleApps.js:683-717; docs/recon/role-permission-matrix.md:1008
treasurer Finance app with Fees/Accounting split; BOS only when pilot enabled; account utility outside domain Optional Supported; post/reconcile/approve separation required src/config/apps/roleApps.js:718-753
homeroom Reuse Teacher portal with homeroom section enabled by dated class assignment; no parallel homeroom app Core shell plus entitled optional tasks src/config/apps/roleApps.js:754-793
alumni Withhold current Student/Library/Communication composition; if supported, minimal historical self-service portal Requires Product/Privacy Decision; two modeled denials and retention scope src/config/apps/roleApps.js:794-834; docs/recon/role-permission-matrix.md:1011
pendaftar Standalone /spmb/* journey; no authenticated apps launcher Optional SC-ADM portal with explicit public/auth boundary src/config/apps/roleApps.js:835-840; src/router/routerGuardPolicy.js:49-82
vice_principal_curriculum Withhold shell; after decision, curriculum overview/review pages only, linking to owning Academic/Report domains Requires Product Decision and approval matrix src/config/apps/roleApps.js:841-860
vice_principal_student_affairs Withhold shell; after decision, student-affairs oversight with explicit read/approve/correct split Requires Product Decision; current communication denials src/config/apps/roleApps.js:861-888
vice_principal_infrastructure Withhold shell; after decision, SC-OPS oversight pages only Requires Product Decision; current 27-denial cluster blocks release src/config/apps/roleApps.js:889-911; docs/recon/role-permission-matrix.md:1014
vice_principal_public_relations Withhold shell; if approved, canonical Communication tasks plus separately entitled Admissions outreach Requires Product Decision; do not duplicate domain pages src/config/apps/roleApps.js:912-933
vice_principal_finance Withhold shell; if approved, Finance oversight/read/approval tasks with explicit action capability Requires Product Decision src/config/apps/roleApps.js:934-951

cashier is not a 34th role contract: it occurs in a finance route allowlist but is absent from ROLES, ROLE_APPS, and the backend role catalog (src/router/financeRoutes.js:124; src/config/roles.js:10-42; ../custom_addons_scola/gcgscola/scola_core/services/role_catalog.py:7-40). It must be removed as stale or formally added by Product/Security before any IA assignment.

4. Proposed Scola IA contract

4.1 Shell and package boundary

  • One customer shell per active role context, with one canonical home that resolves. Apps represent approved product domains, not arbitrary component folders.
  • Core apps appear first: Home, Academic, Students, Attendance, Communication, Settings. Optional apps appear only when installed and entitled and authorized; pilots have a persistent pilot label and tenant/user allowlist. Internal, legacy, incomplete, and undecided apps are absent from launcher, sidebar, search, recents, favorites, deep links, breadcrumbs, and notifications.
  • Employee self-service is an account utility reused by eligible staff roles, not copied into every domain section. Cross-domain approvals live in an approval inbox only after each action delegates to the owning domain capability/API.
  • A hidden route is not a security control. Direct navigation must apply the same package, capability, record, tenant, and domain-owner contract as its menu node.

4.2 Page, route, alias, and duplicate contract

Surface family Proposed canonical treatment Compatibility disposition Evidence
Teacher home /faculty/dashboard /faculty/home redirect only; never use as home/menu/breadcrumb src/router/teacherRouteFragments/core.js:22-30; src/config/apps/appFragments/teacherPortalApp.js:47-81
Grade level /grade-levels /course-level alias retained only if migration evidence requires it src/router/academicCoreRoutes.js:22-27; current menu alias src/config/apps/appFragments/academicApp.js:51-75
News /news and authorized admin publication routes /announcement page/model is deprecated; migrate or remove, not a competing page src/router/sharedExperienceRoutes.js:57-66; docs/recon/open-questions.md:39-40
Analytics shortcuts Owning Principal/VP/domain route Remove /admin/analytics/* menu/app; compatibility redirects get owner and expiry src/router/analyticsAdminRoutes.js:1-49
Extracurricular /faculty/extracurricular list; child /:id/absensi* for attendance Remove the second same-route leaf src/config/apps/appFragments/extracurricularCoachApp.js:19-37; src/router/counselingRoutes.js:578-622
Library management One canonical /library/* domain family (exact migration list requires route decision) /librarian/* and /config/* mirrors become scoped redirects only when they do not change scope src/router/libraryConfigRoutes.js:1-55; src/router/libraryManagementRoutes.js:270-274; src/router/librarianRoutes.js:144-149
Shared calendar/news/self-service One canonical page identity may be referenced by many role menus Same route reuse is intentional only when component, capability, scope, and terminology are identical src/composables/useApps.js:285-340; duplicate inventory requires runtime closure
All remaining aliases Canonical route declared in route metadata/registry Each of 119 records gets canonical target, owner, reason, telemetry, test, and expiry/permanent rationale docs/recon/route-inventory.md:1293-1415

Canonical technical route/name convention is English kebab-case; visible terminology is approved Bahasa Indonesia and comes from one label/glossary registry. Existing mixes such as Analytics, Academic Governance, Admission Terpusat, Absensi, and Kehadiran are not silently normalized here; Product/School SME must approve the term, then menu, page title, breadcrumb, status, and help key use the same value (src/config/apps/appFragments/analyticsApp.js:13-20; src/config/apps/appFragments/vicePrincipalApps.js:107-158; src/config/apps/appFragments/foundationApp.js:205-222; docs/ai-guidelines/AI_AGENT_MASTER_GUIDE.md:103-105,267).

4.3 Breadcrumb, dashboard, and entry-point contract

  • Every supported page has canonicalPageId, owning app/group, canonical route, page title, allowed role/capability/scope, package gate, and related/detail route patterns.
  • Breadcrumb is generated only from authorized ancestors and always resolves to canonical routes. Detail/create/edit/import pages inherit the list/workspace parent; alias URLs replace browser history with their canonical target.
  • Dashboard cards, global search, notifications, recents, favorites, contextual links, and mobile pins are all entry points and use the same resolver as the menu. No card may link to a route omitted/forbidden by the role IA.
  • A supported role has exactly one resolvable home. Failure to resolve is an explicit access/configuration error, not fallback to /, an unrelated dashboard, or technical admin.
  • Empty/incomplete shells return an approved unavailable boundary only for sold-but-disabled packages; placeholders and removed products return not-found/unsupported and are not discoverable.

4.4 Menu-to-authority contract

Rendered navigation is the intersection of approved product status + installed addon + entitlement + active-role capability + record scope + tenant/company scope + domain ownership. Router and API must independently deny everything outside that intersection. This makes menu hiding a usability outcome, not an authorization mechanism. The active-role and deny-by-default semantics are owned by the authorization plan; QG-02 cannot pass while QG-03 is RED.

5. IA finding register

Severity menunjukkan impact bila surface tetap masuk baseline. Item Decision bukan ordinary bug: Product/Security/SME harus menetapkan contract sebelum engineering dapat menutupnya. Disposition removal/hide adalah preferred default ketika mempertahankan surface hanya menambah accidental complexity.

ID Severity / type Finding and affected surface Proposed disposition / acceptance Exact evidence
IA-001 Release blocker Core, optional, pilot, internal, and undecided leaves coexist in the same launcher/section; menu existence can imply unsupported product availability. Approve package ownership per leaf; split groups; unavailable leaves absent from every entry point. docs/documentation-planning/product-surface-candidates.md:186-335; src/config/apps/index.js:45-94
IA-002 Release blocker — Decision Role catalogs are not one set: FE ROLES omits security_officer, school_committee, bos_admin, and generic foundation; backend has 32 roles without foundation; route admits orphan cashier. Approve one versioned role catalog; remove stale aliases or add full contract; contract test exact equality. src/config/roles.js:10-42; src/config/apps/roleApps.js:57-951; ../custom_addons_scola/gcgscola/scola_core/services/role_catalog.py:7-40; src/router/financeRoutes.js:124
IA-003 Release blocker Eight configured homes do not resolve: five /vice-principal/*/dashboard, /finance/dashboard, /library/dashboard, and /faculty/extracurricular/dashboard. Point each role/app to an existing canonical home; route/menu/home contract test for all 33 roles. src/config/roles.js:43-77; src/config/apps/roleApps.js:195-203; canonical VP homes src/config/apps/appFragments/vicePrincipalApps.js:78,232,416,532,623; current inventory docs/recon/route-inventory.md:10-18
IA-004 Release blocker Static role model finds 79 visible-but-forbidden leaves; a menu can advertise an action that route guard rejects. Zero visible-forbidden leaf for supported runtime account/module combinations; unauthorized direct route still denied. docs/recon/role-permission-matrix.md:983-1105
IA-005 Major consistency issue analytics is explicitly a legacy shortcut app, still competes with principal/VP/domain/platform routes through redirects. Remove app from supported role configs; retain only measured compatibility redirects with owner/expiry. src/config/apps/appFragments/analyticsApp.js:1-59; src/router/analyticsAdminRoutes.js:1-49
IA-006 Release blocker Lab shell exposes dashboard plus six literal placeholder child pages; optional HR utilities make incomplete shell appear usable. Remove shell/routes/menu from customer surface; reintroduce only with package/API/E2E contract. docs/recon/open-questions.md:44-54; src/views/Laboran/Inventory/LabInventoryList.vue:1-12; src/config/apps/appFragments/labTechnicianApp.js:37-158
IA-007 Release blocker Public /register renders only a Register heading and competes with implemented SPMB registration. Remove generic route or redirect only after an explicit acquisition-flow decision; canonical SPMB register remains SC-ADM. src/router/sharedExperienceRoutes.js:1-25; src/views/Register.vue:1-7; src/router/spmbRoutes.js:45-55
IA-008 Major consistency issue Teacher app/role home uses compatibility /faculty/home while canonical component route is /faculty/dashboard. Canonicalize every home/menu/breadcrumb to /faculty/dashboard; retain redirect only for compatibility. src/router/teacherRouteFragments/core.js:22-30; src/config/apps/appFragments/teacherPortalApp.js:47-81; src/config/roles.js:61-62
IA-009 Major consistency issue “Daftar Ekskul” and “Absensi Ekskul” are two leaf labels/capabilities pointing to the same list route, while actual attendance pages are children. Keep one list leaf; put attendance beneath selected extracurricular detail; manage capability on mutation routes/API. src/config/apps/appFragments/extracurricularCoachApp.js:19-37; src/router/counselingRoutes.js:578-622
IA-010 Release blocker Canonical scola.news and parallel /announcement page/model coexist; parent communication advertises the legacy concept. Remove announcement from menus/search; migrate or deprecate data; one canonical News identity. src/router/sharedExperienceRoutes.js:57-66; src/config/apps/appFragments/parentPortalApp.js:257-315; docs/documentation-planning/documentation-blockers.md:478-488
IA-011 Release blocker Settings school group mixes core company/capacity with attendance, LMS, and Dapodik config; visible root does not prove every package/manage authority. Split settings by owning package and configure capability; core Settings contains only approved core configuration/access. src/config/apps/appFragments/settingsApp.js:20-112; docs/documentation-planning/documentation-blockers.md:272-282
IA-012 Release blocker — Decision Attendance shell mixes manual student attendance/W05, pickup, settings, RFID, and face recognition despite different packages, actors, privacy bases, and maturity. Separate Core read hub, controlled W05 pilot, SC-ATTEND+ app, and pickup decision surface. src/config/apps/appFragments/attendanceApp.js:22-128; docs/documentation-planning/pilot-attendance-plan.md:15-30,317-343
IA-013 Major consistency issue Student/parent groups mix core timetable/attendance/news with Fees, Report, Learning, Assessment, Student Services, Library, and analytics. Preserve role shell but split package folders; absent package leaves disappear without leaving empty group. src/config/apps/appFragments/studentPortalApp.js:62-338; src/config/apps/appFragments/parentPortalApp.js:60-363
IA-014 Release blocker — Decision Principal shell is a cross-domain dashboard, mutation/approval bucket, analytics, and personal utility without approved leadership SKU or action ownership. Withhold; approve read/approve task matrix, then link to owning domains instead of copying full apps. src/config/apps/appFragments/principalApp.js:58-469; docs/recon/open-questions.md:35-42
IA-015 Release blocker — Decision Five VP shells use mixed English/Indonesian names, configured /dashboard homes that do not exist, shared components, optional-domain duplication, and unapproved approval semantics. Approve each role’s task contract or consolidate into one leadership shell; canonical routes reuse owning page identity. src/config/apps/appFragments/vicePrincipalApps.js:72-686; src/config/roles.js:50-54
IA-016 Release blocker — Decision Technical admin and school school_admin receive nearly the same broad domain launcher, while backend labels admin as technical; wildcard authority can mask ordinary-role defects. Separate technical/break-glass IA from school administration; never certify school workflow with admin. src/config/apps/roleApps.js:57-152; ../custom_addons_scola/gcgscola/scola_core/services/role_catalog.py:7-10; src/router/routerGuardPolicy.js:18-31,151-179
IA-017 Release blocker — Decision head_admin is assigned 12 mixed apps but access filtering leaves a different subset and 15 denied leaves. Approve Kepala TU task/package contract; use canonical domain pages; zero modeled/runtime contradictions. src/config/apps/roleApps.js:683-717; docs/recon/role-permission-matrix.md:1008,1025-1105
IA-018 Release blocker — Decision VP infrastructure receives both a VP shell and Inventory/HR/Communication, but 27 modeled leaves are forbidden—the largest denial cluster. Withhold role navigation until SC-OPS read/approve scope is approved and route/API parity tests pass. src/config/apps/roleApps.js:889-911; docs/recon/role-permission-matrix.md:1014,1060-1105
IA-019 Major consistency issue Auto breadcrumb depends on visible menu route matching; hidden/direct/detail/import pages can lack an authorized canonical ancestor, and duplicate routes can pick role-preferred context. Add canonical page owner and related-route metadata; crawl every supported route/role and assert breadcrumb targets resolve and authorize. src/composables/useApps.js:285-340,670-731; src/composables/useBreadcrumbs.js:22-74; src/components/Topbar.vue:185-217
IA-020 Major consistency issue Current registry has 36 repeated route keys across 122 leaf instances; reuse and accidental duplication are not distinguished in schema. Add canonicalPageId/intentional-reuse allowlist; one search/result/help/analytics identity per page; zero unclassified duplicates. src/config/apps/appSchema.js:1-74; src/config/apps/index.js:45-100; static current-code extraction in §1
IA-021 Major consistency issue 119 redirect/alias records lack a single lifecycle/owner contract and can be counted as pages or chosen by menu/home. Inventory canonical target, owner, reason, telemetry, test, and expiry/permanent rationale; no alias in canonical UI. docs/recon/route-inventory.md:1293-1415
IA-022 Major consistency issue npm run audit:menu currently reports false missing routes for template-generated Library config and grade-level alias; it also hardcodes compact exceptions and exact pin counts inconsistent with compactPortal. Repair audit before making it a gate; parse effective router, use navigation metadata, and add fixtures for generated/alias routes. package.json:10; scripts/audit-menu-ia.mjs:8-39,122-205; src/router/libraryConfigRoutes.js:1-55; src/config/apps/roleApps.js:25-28,195-203
IA-023 Release blocker UI/package gates are not proven as one contract; route metadata includes secondaryFeatureFlag, while the router policy only evaluates featureFlag, and feature aliases include non-catalog flags. One resolver for primary+secondary package requirements across app/menu/route/API; all optional combinations negative-tested. src/router/foundationRoutes.js:93-103,163-174; src/router/routerGuardPolicy.js:350-394,504-519; src/config/featureFlagFragments/moduleFeatureFlags.js:1-58; docs/modular/product-tier-and-feature-flags.md:19-31
IA-024 Release blocker /students/create and /students/import are direct-routable using students.list.view; menu hiding/import UX cannot replace create/import authority. Define create/import capabilities, route guards, API guards, package/scope parity, and negative direct-route tests. src/router/studentDataAdminRoutes.js:14-44; docs/documentation-planning/documentation-blockers.md:382-392
IA-025 Release blocker Principal/VP attendance pages can expose Create/Pending mutation CTA while backend treats those actors as read-only. Hide unauthorized actions and keep mutation API denied, or approve/implement a different role contract; test menu → route → API parity. src/views/AttendanceManagement/Admin/AttendanceSheetList.vue:9-20,192; src/router/principalRoutes.js:196-218; src/router/vicePrincipalRoutes.js:214-231; docs/documentation-planning/documentation-blockers.md:394-404
IA-026 Release blocker Counts and source consistency are static; no named tenant/build has proven homes, dead links, hidden-route denial, optional-module combinations, breadcrumbs, responsive launcher, or served-bundle parity. Execute canonical IA crawl on Golden Tenant for every supported role and module matrix; record exact FE/BE/DB/module build. docs/documentation-planning/documentation-blockers.md:80-90; QG-02/QG-18

No current inconsistency was accepted as an Intentional domain-specific difference without an explicit owner/rationale. Candidate intentional reuse (calendar/news/self-service) remains subject to the IA-020 allowlist and runtime scope proof.

6. Audit coverage and closure tests

Requested audit dimension Coverage/result Closure evidence required
Application shells All 36 covered in §2; proposed app status remains in 01-product-contract.md Approved allowlist; unsupported shell absent; app home resolves
Role dashboards All 33 role compositions covered in §3; eight invalid homes in IA-003 Fresh account lands on authorized canonical home for each supported role
Menus/submenus All 143 groups covered in §2; 528 current leaf total; mixed package issues IA-001, 011015 Registry snapshot equals approved product/package manifest
Page and route names 884 component pages remain the exhaustive recon inventory; this audit establishes page identity/canonical route contract, not support for all pages Every routed component tagged supported, direct child, compatibility, internal, or remove; no unclassified page
Breadcrumbs Auto lineage and dynamic tail audited in IA-019 Role-aware crawl proves every supported page has authorized canonical parent/back target
Aliases All 119 recon redirect/alias records covered by IA-021; key families in §4.2 Canonical target/owner/reason/expiry registry; aliases absent from UI/search/help
Duplicate/shared pages 36 repeated route keys / 122 leaf instances covered by IA-020; library/extracurricular examples in §4.2 canonicalPageId and intentional-reuse allowlist; same component is not counted twice
Legacy pages Analytics and Announcement covered by IA-005/IA-010 Removed from role configs and all entry points; migration/redirect tests only if retained
Placeholders Lab and /register covered by IA-006/IA-007 Zero reachable placeholder on supported role/module matrix
Dead links Known eight invalid homes in IA-003; current audit-tool limitation in IA-022 Effective-router crawler covers literal, generated, alias, param, card, notification, and breadcrumb links
Hidden-but-routable pages Direct import/create in IA-024; 884 pages versus 528 leaves shows that no-menu pages need classification, not automatic removal Direct route positive/negative tests and canonical parent for every supported hidden child
Visible-but-forbidden pages 79 modeled leaves in IA-004, including IA-017/IA-018 clusters and IA-025 CTA conflict Zero supported menu/card/action contradiction with route/API for fresh accounts
Optional-module leakage IA-001, IA-011IA-013, and IA-023 Pairwise and dependency module/entitlement matrix; no empty or leaked group
Navigation differences by role §3 covers 33/33; differences are task/scope/package-driven Product-approved rationale for each role-specific variant; otherwise consolidate

6.1 QG-02 measurable acceptance

QG-02 can become GREEN only when one exact Golden Tenant release candidate proves all of the following:

  1. Approved app/group/leaf manifest contains only Core V1 plus enabled Optional Supported/Controlled Pilot nodes; legacy, internal, incomplete, and undecided nodes have zero discoverability.
  2. All supported fresh-role accounts resolve one canonical home; zero fallback to /, technical admin, missing route, unrelated domain, or forbidden route.
  3. Every menu, submenu, launcher folder, dashboard card, mobile pin, quick action, notification link, search result, favorite, recent item, breadcrumb, and contextual link resolves to an authorized canonical route.
  4. Every supported direct route passes its own package/capability/scope checks; the same negative matrix returns the approved deny/not-found response for unauthorized, out-of-assignment, and cross-tenant actors.
  5. Alias crawl reports 119 or an approved reduced count, with zero alias used as a current menu/home/breadcrumb target and zero redirect loop.
  6. Duplicate report contains zero unclassified route/component/page identity; allowed reuse has identical authority/scope or an explicit role-context reason.
  7. Effective router audit understands generated routes and compactPortal; npm run audit:menu and contract tests pass without regex false positives (scripts/audit-menu-ia.mjs:23-39,122-205).
  8. Desktop and 320/360/390 px mobile navigation expose the same task contract, with four task pins plus Menu except an approved compact-role rule represented in both runtime and audit metadata.
  9. Runtime evidence records role, active role, assigned roles, permissions, tenant/company, installed modules, entitlement flags, route, API outcome, FE/BE/database/module build, and served asset hash.

7. Decision ownership and implementation boundary

Decision class Accountable owner Engineering may do before decision Engineering must not infer
Product/package boundary Product + Commercial Hide/remove clearly legacy/incomplete/internal surfaces; prepare manifest That coded module/menu is sold/supported
Role/task IA Product + Security + School SME Fix confirmed broken links/aliases that preserve approved outcome Leadership/admin approval authority or sensitive-data access
Privacy-sensitive navigation DPO + Security + domain owner Fail closed and minimize discoverability Counseling, biometric, proof, alumni, DPO, committee, pickup audience
Compatibility/deprecation Product + Operations Measure route use and add redirect tests Permanent support merely because an alias exists
Terminology Product + School SME; DPO for identifiers/status Centralize approved label after decision Whether “Absensi”, “Kehadiran”, “Sakit”, “Izin”, or English domain terms are equivalent

8. Self-review

  • Unsupported claims: all proposed role/menu structures are explicitly proposals; no static result is described as runtime production behavior.
  • Duplicated surfaces: all 36 shells, 143 groups, 119 aliases, repeated leaf routes, Library mirrors, Analytics redirects, News/Announcement, and extracurricular duplicate are assigned a disposition.
  • Unresolved contradictions: role catalogs, eight homes, 79 denials, settings/attendance/package mixing, and audit-script drift remain visible blocker IDs rather than normalized behavior.
  • Security boundaries: menu hiding is never treated as authorization; direct routes, active role, capability, record/assignment, tenant/company, sensitive data, and domain ownership are release criteria.
  • E2E links: IA gate explicitly covers launcher/menu/card/search/notification/breadcrumb → route → API and cross-module combinations; detailed workflows/tests remain owned by the workflow catalog and release matrix.
  • Decision hygiene: principal/VP/head-admin/admin-staff/foundation/alumni/DPO/security/committee/pickup/cashier decisions are not disguised as engineering bugs; removal/withhold is the default until approved.

Until QG-01, QG-02, QG-03, QG-14, QG-16, and QG-18 pass together, this document is an auditable stabilization proposal—not a frozen IA and not a source for user documentation.