Lewati ke isi

Score Pipeline: Assignment/CBT → Gradebook → eRaport

Dokumentasi arsitektur alur nilai dari sumber (LMS Assignment, CBT Exam, Manual Input) melalui Gradebook hingga menjadi komponen rapor siswa (eRaport).

Last verified: 2026-03-21


1. Ringkasan

Pipeline nilai di Scola terdiri dari 4 layer:

┌─────────────────────────────────────────────────────────────────────┐
│                     SUMBER NILAI (Input Layer)                       │
│                                                                      │
│  ┌──────────────────┐    ┌──────────────────┐    ┌───────────────┐  │
│  │  LMS Assignment  │    │   CBT Exam       │    │ Manual Input  │  │
│  │  (lms.submission) │    │ (scola.cbt.      │    │ (via eRaport  │  │
│  │                   │    │  attempt)        │    │  EditModal)   │  │
│  └────────┬──────────┘    └────────┬─────────┘    └───────┬───────┘  │
│           │ Faculty grades          │ Auto-scored          │          │
│           ▼                         ▼                      │          │
│  ┌──────────────────────────────────────────┐              │          │
│  │         GRADEBOOK (Aggregation Layer)     │              │          │
│  │  FE: Gradebook.vue + useGradebook.js      │              │          │
│  │  BE: op.teaching.assignment.get_gradebook │              │          │
│  └──────────────────┬───────────────────────┘              │          │
│                     │ publishGradesToAcademic()             │          │
│                     ▼                                       │          │
│  ┌──────────────────────────────────────────┐              │          │
│  │      academic.grade (SSOT Bridge Table)   │              │          │
│  │  • Idempotent publish_grade()             │              │          │
│  │  • Component normalization                │              │          │
│  │  • Audit trail via grade.event            │              │          │
│  └──────────────────┬───────────────────────┘              │          │
│                     │ _fetch_score_from_source()            │          │
│                     ▼                                       ▼          │
│  ┌──────────────────────────────────────────────────────────────────┐│
│  │                    eRAPORT (Report Card Layer)                    ││
│  │  scola.student.report → .report.line → .report.component        ││
│  │                                                                   ││
│  │  Workflow: draft → submitted → wali_kelas →                      ││
│  │           kepala_sekolah → published                              ││
│  └──────────────────────────────────────────────────────────────────┘│
│                     │                                                │
│  ┌──────────────────▼──────────────────────────────────────────────┐│
│  │                 KONSUMSI (Output Layer)                          ││
│  │  • Student: StudentReportList / StudentReportDetail             ││
│  │  • Parent:  raportList.vue → Download PDF                       ││
│  │  • Admin:   Dapodik sync                                        ││
│  └─────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────┘

2. Layer Detail

2.1 Input Layer — Sumber Nilai

LMS Assignment

Aspek Detail
Model lms.submission (scola_lms module)
Trigger Student submit tugas → faculty grades via POST /api/lms/items/:id/grade
Fitur Versioning, plagiarism check, rubric grading, storage quota, late detection
Output lms.submission.score + lms.submission.grade_state

File References:

Layer File
FE Service src/services/lms/assignment.service.js
FE View (Faculty) src/views/AssignmentManagement/Faculty/
FE View (Student) src/views/AssignmentManagement/Student/
BE Model scola_lms/models/lms_submission.py
BE API scola_lms/controllers/lms_api.pygrade_submission()

CBT Exam

Aspek Detail
Model scola.cbt.attempt (scola_cbt module)
Trigger Student takes exam via CBT Runner → auto-graded (objektif) atau manual (essay)
Fitur Timer, auto-save, randomization, integrity monitoring, proctor console
Output scola.cbt.attempt.score

File References:

Layer File
FE Service src/services/cbt/cbtRunnerService.js
FE Composable src/composables/cbt/useExamState.js
FE View (Student) src/views/ExamManagement/Student/CBTRunner.vue
FE View (Student List) src/views/StudentViews/CBT/CBTExamList.vue
BE Module scola_cbt/ (EP0–EP9)

Manual Input

Aspek Detail
Entry Point ReportLineEditModal.vue — admin/teacher langsung input score per komponen
Model scola.student.report.component dengan source='manual'
Bypass Tidak melalui academic.grade — langsung ke eRaport component

2.2 Aggregation Layer — Gradebook

Gradebook mengagregasi semua submission dan CBT score per course (batch + subject).

Aspek Detail
BE API GET /api/lms/courses/:id/gradebookop.teaching.assignment.get_gradebook()
Cache Method-level cache, invalidated on submission create/write
Publish POST /api/lms/grades/publishacademic.grade.publish_grade()
Policy CBT non-learning context (admission/independent) blocked from publish kecuali admin override

File References:

Layer File
FE Service src/services/lms/gradebook.service.js
FE Composable src/composables/lms/useGradebook.js
FE View src/views/LearningManagement/Faculty/Gradebook.vue
BE API scola_lms/controllers/lms_api.pyget_gradebook(), publish_grade()

2.3 Bridge Table — academic.grade

Single Source of Truth antara LMS dan eRaport.

Aspek Detail
Unique Constraint (student_id, batch_id, subject_id, component_type)
Component Types PH, PTS, PAS, PAT, US, TUGAS, PRAKTIK, PORTOFOLIO
Normalization Alias resolution (e.g., ASSIGNMENT → TUGAS, QUIZ → PH) via normalize_component_type()
Idempotency Via grade.event + idempotency_key — replay-safe, conflict detection
Source Tracking source: lms | manual; source_type: assignment | cbt_exam | exam | manual
Grade Mapping Admin-configured via lms.grade.mapping.template (component mapping rules)
Weight Profile Admin-configured via lms.grading.weight.profile (curriculum weighting)

File Reference: scola_lms/models/academic_grade.py

2.4 Report Card Layer — eRaport

Model Deskripsi
scola.student.report Report card utama — per siswa per semester
scola.student.report.line Per-mapel line (final_score, final_grade, teacher)
scola.student.report.component Per-assessment-component score — linked ke scola.assessment.component
scola.assessment.component Definisi komponen (PH/PTS/PAS/dll), weight, hierarchy, source_type
scola.curriculum Konfigurasi kurikulum aktif + grade scale

Score Fetching:

scola.student.report.component._fetch_score_from_source() query academic.grade dengan: - student_id + subject_id + component_type matching - Date bounds dari academic term

Workflow States:

draft → submitted → wali_kelas → kepala_sekolah → published
                 ↘ rejected (back to draft) ↙

File References:

Layer File
FE Service src/services/reportCard/reportCard.service.js
FE Workflow src/services/reportCard/assessmentWorkflow.service.js
FE Views src/views/ReportCardManagement/{Admin,Faculty,Student,Parent,VicePrincipal}/
BE Model scola_report_card/models/student_report.py
BE Model scola_report_card/models/assessment_component.py
BE Model scola_report_card/models/curriculum.py
BE API scola_report_card/controllers/report_card_api.py

2.5 Output Layer — Konsumsi

Konsumen View Data Source
Student StudentReportList.vueStudentReportDetail.vue listReportCards({ scope: 'student' }) — hanya state=published
Parent raportList.vue → Download PDF fetchParentReports()generateRaportPDF() — hanya state=published
Admin DapodikRaporSync.vue Sync ke Dapodik
Teacher TeacherReportLineList.vue Filter by assigned report lines
Homeroom HomeroomReportList.vueHomeroomReportDetail.vue Filter by homeroom batch

3. Data Flow per Path

Path A: Assignment → Gradebook → academic.grade → eRaport

  1. Student submit → lms.submission created
  2. Faculty grades → lms.submission.score updated
  3. Faculty opens Gradebook → get_gradebook() aggregates
  4. Faculty publishes → publish_grade() creates/updates academic.grade
  5. eRaport refresh → _fetch_score_from_source() reads academic.grade

Path B: CBT Exam → academic.grade → eRaport

  1. Student takes exam → scola.cbt.attempt auto-graded
  2. Faculty publishes CBT scores dari Gradebook → academic.grade (source_type=cbt_exam)
  3. eRaport picks up (sama seperti Path A step 5)

Path C: Manual Input → eRaport (Direct)

  1. Admin/Teacher opens ReportLineEditModal
  2. Input score per komponen → saved ke scola.student.report.component (source=manual)
  3. Tidak melalui academic.grade — langsung ke eRaport component

4. Skenario Operasional

Skenario 1: Student sebagai User (Tier 2 — LMS + CBT Aktif)

Semua siswa punya akun, mengerjakan tugas & ulangan via app.

Fitur Status Alur
Assignment submission ✅ Aktif Student submit → Faculty grade → Gradebook
CBT exam ✅ Aktif Student exam → Auto-grade → Gradebook
Gradebook publish ✅ Aktif Faculty publish → academic.grade
eRaport auto-fill ✅ Aktif Komponen fetch dari academic.grade
Student view raport ✅ Aktif StudentReportList.vue
Parent download PDF ✅ Aktif raportList.vue
Notification ✅ Aktif publish_grade() sends to student.user_id

Skenario 2: Student Non-User (Tier 1 — LMS & CBT Non-Aktif)

Siswa tidak punya akun. Sekolah hanya pakai fitur basic.

Fitur Status Keterangan
Assignment submission ❌ N/A Tidak ada student user
CBT exam ❌ N/A Module non-aktif
Gradebook (LMS) ❌ Kosong Tidak ada data untuk di-aggregate
academic.grade ⚠️ Terbatas Hanya terisi jika admin manual publish via API
eRaport manual input ✅ Aktif Admin/Teacher input via ReportLineEditModal
eRaport auto-fetch ⚠️ Empty _fetch_score_from_source() return kosong
eRaport workflow ✅ Aktif Workflow tetap berjalan normal
Student view raport ❌ N/A Tidak ada student user
Parent download PDF ✅ Jika ada akun Report harus published

5. Feature Flag & Tier Gating

5.1 Infrastruktur yang Sudah Ada

LMS dan CBT sudah memiliki mekanisme feature flag dan tier gating:

Feature Flags (src/config/featureFlags.js):

DEFAULT_FEATURE_FLAGS = {
  scola_lms: true,    // LMS module
  scola_cbt: true,    // CBT module
  // ... lainnya
}

Platform Tiers (src/config/platformTiers.js):

FEATURE_FLAG_MINIMUM_TIERS = {
  scola_lms: 'professional',  // Tier 2+
  scola_cbt: 'professional',  // Tier 2+
}

Capability Prefix Rules — Capabilities yang dimulai dengan prefix berikut otomatis di-gate oleh feature flag:

Prefix Feature Flag
academics.lms. / academics.lms_ scola_lms
academics.cbt. / academics.cbt_ / academics.question_bank. scola_cbt

Route Prefix Rules — Routes yang dimulai dengan prefix berikut otomatis di-gate:

Route Prefix Feature Flag
/faculty/lms, /student/lms scola_lms
/faculty/cbt, /student/cbt, /faculty/question-bank scola_cbt

5.2 Bagaimana Konfigurasi Bekerja

Backend (Odoo ir.config_parameter / subscription)
        │
        ▼  GET /api/auth/session → feature_flags + platform_tier
Frontend (auth.store.js)
        │
        ├── updateFeatureFlags(flags)  → featureFlags reactive object
        ├── resolveTierManagedFeatureFlags(tier) → override flags per tier
        │
        ├── Router guard (index.js) → cek capability + feature flag + tier
        ├── Menu registry (menuRegistry.js) → hide menu items jika flag disabled
        └── Capability check (roleCapabilities.js + backendCapabilityAccess.service.js)

5.3 Mengonfigurasi LMS/CBT sebagai Opsional

Untuk menonaktifkan LMS dan CBT (Tier 1 / Starter):

Ada 2 pendekatan, keduanya sudah didukung infrastruktur:

Set platform_tier = starter di backend user/subscription. Frontend otomatis: - resolveTierManagedFeatureFlags('starter')scola_lms: false, scola_cbt: false - Router guard block semua route LMS/CBT - Menu registry hide menu items LMS/CBT

Opsi B: Via Feature Flag Individual

Set scola_lms: false dan scola_cbt: false di backend ir.config_parameter. Frontend: - updateFeatureFlags({ scola_lms: false, scola_cbt: false }) - Efek sama dengan Opsi A

5.4 Gap — Apa yang Belum Ter-gate dengan Benar

Meskipun infrastruktur sudah ada, beberapa area belum sepenuhnya sadar tier:

Area Gap Impact
eRaport "Refresh dari Sumber" button ReportLineEditModal.vue selalu tampil tombol refresh meski LMS non-aktif UX confusing — button muncul tapi selalu gagal/empty
Gradebook menu di eRaport context Link ke Gradebook ada di beberapa eRaport views Dead link jika LMS non-aktif
academic.grade dependency _fetch_score_from_source() selalu query academic.grade No error, tapi return empty — user bingung kenapa auto-fill kosong
Assignment routes di eRaport Report line detail shows assignment source_ref links Dead link jika LMS non-aktif
Student CBT route /student/cbt di-gate, tapi halaman schedule masih di-fetch Silently fails (no error, empty list)
Backend scola_lms module dependency scola_report_card depends pada academic.grade yang ada di scola_lms Module dependency harus tetap ada meski fitur LMS non-aktif di FE

5.5 Rekomendasi Perubahan untuk Full Tier-Awareness

Frontend (5 perubahan)

  1. ReportLineEditModal.vue — Sembunyikan tombol "Refresh Nilai dari Sumber" jika scola_lms dan scola_cbt disabled
  2. ReportLineDetailModal.vue — Jangan tampilkan source_ref link ke assignment/exam jika flag disabled
  3. AdminReportDetail.vue / HomeroomReportDetail.vue — Hide "Buka Gradebook" link jika scola_lms disabled
  4. TeacherReportLineList.vue — Tambahkan info banner "Input manual aktif — LMS/CBT tidak tersedia" jika flags disabled
  5. GenerateReportWizard.vue — Skip "Refresh otomatis dari sumber" step jika LMS/CBT disabled

Backend (2 perubahan)

  1. scola.student.report.component._fetch_score_from_source() — Return early dengan pesan jelas jika source module non-aktif, bukan silent empty
  2. report_card_api.py — Tambahkan lms_active / cbt_active flag di response GET /api/v1/report-card/filters agar FE tahu status module

Konfigurasi (1 perubahan)

  1. Backend ir.config_parameter — Pastikan ada keys scola.feature.lms_enabled dan scola.feature.cbt_enabled yang di-sync ke frontend via session response

6. Relasi ke Domain Docs Lain

Domain Doc Relevansi
domains/academic/README.md Master data akademik, penilaian, rapor
domains/lms/README.md LMS course, assignment, gradebook
domains/cbt/README.md CBT exam, runner, grading
architecture/platform-tiers.md Tier definitions, feature gating strategy

7. File Reference Index

Frontend — Services

File Fungsi
src/services/lms/assignment.service.js Assignment CRUD API
src/services/lms/gradebook.service.js Gradebook aggregation + publish
src/services/cbt/cbtRunnerService.js CBT Runner API (start, answer, submit)
src/services/cbt/studentExamSchedule.service.js Student exam schedule fetch
src/services/reportCard/reportCard.service.js Report card CRUD + workflow
src/services/reportCard/assessmentWorkflow.service.js Workflow orchestration + audit
src/config/featureFlags.js Feature flag definitions + runtime update
src/config/platformTiers.js Tier gating logic

Frontend — Views

File Role Fungsi
src/views/LearningManagement/Faculty/Gradebook.vue Faculty Gradebook matrix + publish
src/views/AssignmentManagement/Faculty/ Faculty Assignment management
src/views/AssignmentManagement/Student/ Student Assignment submission
src/views/ExamManagement/Student/CBTRunner.vue Student CBT exam runner
src/views/StudentViews/CBT/CBTExamList.vue Student CBT exam list
src/views/ReportCardManagement/Admin/ Admin Full eRaport management
src/views/ReportCardManagement/Faculty/ Faculty Teacher/homeroom report views
src/views/ReportCardManagement/Student/ Student View published reports
src/views/ReportCardManagement/Parent/ Parent Download PDF
src/views/ReportCardManagement/VicePrincipal/ VP Quality gate

Backend — Models

File Model Fungsi
scola_lms/models/lms_submission.py lms.submission Assignment submissions
scola_lms/models/academic_grade.py academic.grade SSOT bridge table
scola_report_card/models/student_report.py scola.student.report Report card + lines + components
scola_report_card/models/assessment_component.py scola.assessment.component Assessment component definitions
scola_report_card/models/curriculum.py scola.curriculum Curriculum config

Backend — Controllers

File Endpoints
scola_lms/controllers/lms_api.py /api/lms/items/:id/grade, /api/lms/courses/:id/gradebook, /api/lms/grades/publish
scola_report_card/controllers/report_card_api.py /api/v1/report-card/* (filters, list, detail, workflow, setup)