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.py → grade_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/gradebook → op.teaching.assignment.get_gradebook() |
| Cache | Method-level cache, invalidated on submission create/write |
| Publish | POST /api/lms/grades/publish → academic.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.py → get_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.vue → StudentReportDetail.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.vue → HomeroomReportDetail.vue |
Filter by homeroom batch |
3. Data Flow per Path¶
Path A: Assignment → Gradebook → academic.grade → eRaport¶
- Student submit →
lms.submissioncreated - Faculty grades →
lms.submission.scoreupdated - Faculty opens Gradebook →
get_gradebook()aggregates - Faculty publishes →
publish_grade()creates/updatesacademic.grade - eRaport refresh →
_fetch_score_from_source()readsacademic.grade
Path B: CBT Exam → academic.grade → eRaport¶
- Student takes exam →
scola.cbt.attemptauto-graded - Faculty publishes CBT scores dari Gradebook →
academic.grade(source_type=cbt_exam) - eRaport picks up (sama seperti Path A step 5)
Path C: Manual Input → eRaport (Direct)¶
- Admin/Teacher opens
ReportLineEditModal - Input score per komponen → saved ke
scola.student.report.component(source=manual) - 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:
Opsi A: Via Platform Tier (Recommended)¶
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)¶
ReportLineEditModal.vue— Sembunyikan tombol "Refresh Nilai dari Sumber" jikascola_lmsdanscola_cbtdisabledReportLineDetailModal.vue— Jangan tampilkan source_ref link ke assignment/exam jika flag disabledAdminReportDetail.vue/HomeroomReportDetail.vue— Hide "Buka Gradebook" link jikascola_lmsdisabledTeacherReportLineList.vue— Tambahkan info banner "Input manual aktif — LMS/CBT tidak tersedia" jika flags disabledGenerateReportWizard.vue— Skip "Refresh otomatis dari sumber" step jika LMS/CBT disabled
Backend (2 perubahan)¶
scola.student.report.component._fetch_score_from_source()— Return early dengan pesan jelas jika source module non-aktif, bukan silent emptyreport_card_api.py— Tambahkanlms_active/cbt_activeflag di responseGET /api/v1/report-card/filtersagar FE tahu status module
Konfigurasi (1 perubahan)¶
- Backend
ir.config_parameter— Pastikan ada keysscola.feature.lms_enableddanscola.feature.cbt_enabledyang 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) |