Arsitektur
Komponen sistem yellow-bank-soal, alur data, dan pembagian tanggung jawab antar-lapisan.
Arsitektur
Diagram High-Level
flowchart LR
WP["WordPress + Sejoli Tryout"]
App["yellow-bank-soal (FastAPI)"]
DB[("PostgreSQL")]
Redis[("Redis + Celery")]
AI["OpenRouter API"]
Admin["Admin UI"]
Siswa["Browser Siswa"]
Siswa --> WP
WP -->|"verify_session + create session"| App
Admin -->|"CRUD + reports"| App
App --> DB
App --> Redis
App -->|"generate soal"| AI
App -->|"delivery soal + skor"| Siswa
Yellow Bank Soal adalah backend terpusat. Klien (browser siswa, admin UI, plugin Sejoli) berkomunikasi via REST API. Output dari sebuah sesi ujian adalah skor (NM, NN, theta) yang disimpan permanen di PostgreSQL.
Lapisan Aplikasi
Aplikasi mengikuti pola layered architecture klasik, dengan pemisahan jelas antara transport (HTTP), logika bisnis (services), dan persistensi (models).
flowchart TD
A["API Layer (routers/api/v1)"] --> B["Service Layer (services/)"]
B --> C["Data Layer (models/ + database.py)"]
B --> D["External (OpenRouter, WordPress JWT)"]
A --> E["Schema Layer (schemas/) — validasi Pydantic"]
C --> F[("PostgreSQL via SQLAlchemy 2.0 async")]
1. API Layer (backend/app/routers/, backend/app/api/v1/)
Endpoint HTTP FastAPI. Bertugas:
- Parsing & validasi request (via Pydantic schema)
- Delegasi ke service layer
- Format response JSON
Tidak boleh berisi logika bisnis. Hanya transport.
2. Service Layer (backend/app/services/)
Jantung aplikasi. Setiap file service punya satu domain tanggung jawab:
3. Schema Layer (backend/app/schemas/)
Definisi Pydantic v2 untuk request body, response model, dan validasi. Memisahkan kontrak API dari struktur internal model database.
4. Data Layer (backend/app/models/, backend/app/database.py)
SQLAlchemy 2.0 async ORM. Migrasi via Alembic (backend/alembic/). Setiap model punya website_id untuk isolasi multi-tenant. Detail lengkap di Data → Data Models.
Alur Data Runtime vs Batch
Dua jalur data berbeda di aplikasi, dengan karakteristik berbeda:
flowchart LR
subgraph RT["Runtime (real-time, saat sesi ujian)"]
R1["Siswa jawab"] --> R2["cat_selection"]
R2 --> R3["irt_calibration update theta"]
R3 --> R4["UserAnswer"]
end
subgraph BG["Batch (async, lewat Celery)"]
B1["Trigger kalibrate"] --> B2["irt_calibration joint MLE"]
B2 --> B3["Update semua Item.b"]
B4["Trigger AI generate"] --> B5["ai_generation"]
B5 --> B6["Insert Item baru"]
end
R4 -.->|"menyumbang data"| B2
Batch job dijalankan via Celery + Redis agar tidak memblokir API. Saat ini kalibrasi IRT dan AI generation adalah kandidat utama untuk background processing.
Boundary dengan Sejoli Tryout
Pemisahan tanggung jawab yang tegas — detail lengkap di Integrasi → Sejoli Tryout:
App tidak mengurangi quota attempt atau memvalidasi pembayaran — itu tanggung jawab Sejoli sebelum sesi dimulai.
Boundary Internal Modul
Aturan penting untuk kontributor kode:
routers/tidak boleh import langsung darimodels/— selalu lewat service.services/tidak boleh tahu soal HTTP (noRequest,Response, status code).models/tidak boleh berisi logika bisnis — hanya deklarasi tabel, relationship, constraint.- Cross-service call dihindari; jika perlu, lewat function eksplisit (bukan circular import).
Bacaan Lanjutan
- Tech Stack — daftar lengkap dependency & versi
- Data → ER Diagram — relasi antar entitas
- Operasional → Instalasi — cara setup lokal
- Konsep → Alur & Algoritma — diagram alur detail tiap modul
Last updated Jul 25, 2026