School management web app for an Islamic integrated school (SDIT/SMPIT). Single school per deployment, Indonesian language, web-first installable PWA.
Status: Phases 0–3 complete. Foundation, the nine MVP modules, the Filament admin panel with SPP billing, and the Phase-3 content additions (galeri, profil self-service) have all shipped. Cumulative gates: 89 Pest / 257 assertions, 23 Playwright, Larastan max 0, Pint clean. Phase 4 is closed-loop integrations (payment gateway client, accounting post). See "Roadmap".
This app is one of seven products in the Artivisi line. It is the vertical wedge for the SDIT/SMPIT/pesantren segment and intentionally does only the school-operations surface:
- SPP billing only — tagihan per siswa/periode, payments recorded against a
bill, status derived from sums. No chart of accounts, no payroll, no tax.
General-ledger posting lives in the sibling Balaka (
aplikasi-akunting) product; on payment cleared this app POSTs a journal entry over Balaka's REST API (Phase 4). - No embedded payment rail. Collection (VA / QRIS / etc.) runs through the
separate
snap-payment-gatewayproduct over HTTP — the SNAP-compliant Artivisi gateway, multi-bank, multi-tenant. This app calls it as a client (Phase 4); never bundles Midtrans / Xendit / DOKU / Faspay or any SaaS aggregator (keeps the open-core stack and avoids per-transaction fees). - No closed-loop wallet here either. Kantin / koperasi / minimarket prepaid
cards (topup via BSI VA, internal POS taps, outlet settlement) live in the
separate
closed-loop-walletproduct. This app calls it as a client for read-only balance + transaction views on the wali/siswa surfaces and the topup-initiation handoff; the POS authorization path, float ledger, outlet onboarding, and settlement runs do not live here. (PHP-FPM on cPanel cannot serve sub-200ms p99 POS auth; float is a PBI/POJK-regulated activity.) - Single-school per deployment by design. Multi-tenancy lives in the gateway
- the wallet + hosted Balaka. See
docs/MULTI_TENANCY.mdfor the reasoning + the migration path if that ever changes.
- the wallet + hosted Balaka. See
The closed loop from this app's viewpoint:
wali pays SPP ─► snap-payment-gateway ─► bank (SNAP VA / QRIS)
▲ │
│ ▼ webhook
└──── pembayaran row ─► Balaka journal (REST API)
siswa taps card ─► closed-loop-wallet POS ─► outlet balance
│ │
▼ daily settlement ▼ aggregate
disbursement-platform this app (read-only
(BSI H2H to outlets) balance + tx view)
| Role | Scope |
|---|---|
wali (parent) |
Read-only monitoring of own child(ren); multi-child switcher; inputs ibadah done at home |
siswa (student) |
Own schedule, tasks, hafalan, self-input mutaba'ah |
guru (teacher) |
Input absensi, grade setoran hafalan, input nilai, chat with wali |
admin (tata usaha) |
School-wide overview, publish announcements, manage students/classes |
✓ = shipped. The Phase column reflects when it landed (or is planned for).
| Module | Description | Phase |
|---|---|---|
| ✓ Auth & data model | Session login, role-based access, kelas/siswa/wali, tahun ajaran + semester + enrollment | 0 |
| ✓ Pengumuman | Categorized announcement feed; admin/guru publish | 1 |
| ✓ Jadwal pelajaran | Daily/weekly class schedule | 1 |
| ✓ Absensi | Teacher one-tap (H/S/I/A) with offline write-queue (PWA); parent/student view (heatmap, summary, log) | 1 |
| ✓ Nilai & Raport | Teacher input; per-subject scores (Islamic + general), ranking | 1 |
| ✓ Tugas & PR | Teacher assign; student/parent view + submit | 1 |
| ✓ Mutaba'ah Yaumiyah | Daily worship checklist (sholat wajib/sunnah, tilawah, dzikir, adab) + streak | 1 |
| ✓ Hafalan Quran | Per-surah Juz 30 progress, setoran history, tajwid grade, mutqin status | 1 |
| ✓ Kalender | Activity calendar, Hijri + Gregorian | 1 |
| ✓ Chat (guru–wali) | Teacher–wali messaging, htmx polling (no WebSockets) | 1 |
| ✓ Admin panel | Filament-based CRUD for users, siswa, kelas, tahun ajaran, semester, mapel, tagihan, pembayaran, albums | 2 |
| ✓ SPP (billing) | Tagihan + pembayaran with derived status; admin records, wali views. Payment rail is external — see Phase 4. | 2 |
| ✓ SPP konfirmasi manual | Wali uploads bukti transfer → TU verifies in Filament (one click) or rejects (with alasan). Bukti served via auth'd route. Pilot-ready without any payment-gateway dependency. | 2.5 |
| ✓ Galeri foto | Class activity photo feed; admin upload (S3-compatible media), all-role view | 3 |
| ✓ Profil self-service | Wali/guru/admin edit own name, email, password | 3 |
| Payment gateway client | HTTP client to snap-payment-gateway: wali-initiated VA/QRIS, webhook ingestion |
4 |
| General-ledger posting | On pembayaran cleared, POST journal entry to Balaka REST API |
4 |
| Wallet client (read-only) | HTTP client to closed-loop-wallet: card balance + recent transactions on wali/siswa views; topup-initiation handoff |
4 |
| Public API + native mobile | JSON /api (Laravel API Resources + Sanctum) + native shell (Capacitor or RN) |
4 |
| Materi belajar | Learning materials per kelas | 5 |
| Konsultasi BK | Counseling notes between wali ↔ BK guru | 5 |
| Layer | Choice |
|---|---|
| Language | PHP 8.3+ |
| Framework | Laravel (current major) |
| Architecture | thin controllers → service layer → Eloquent |
| Views | Blade |
| Interactivity | htmx (server partials) + Alpine.js (local UI state) |
| Styling | Tailwind CSS (standalone CLI, no Node toolchain) |
| Database | MySQL / MariaDB (migrations + Eloquent) |
| Auth | Laravel session/cookie, role-based; framework CSRF |
| Admin panel | Filament (Phase 2+) |
| Static analysis | Larastan/PHPStan (max) in CI |
| Client | server-rendered, installable PWA — offline read cache + absensi offline write-queue |
| Hosting | shared cPanel hosting first; central VPS (optionally Laravel Octane) path kept open |
Rationale: single-school, budget hosting → PHP runs on cheap cPanel shared hosting
(~Rp300–800rb/yr) that Go/JVM can't use, and Laravel fits this CRUD/RBAC/forms/admin
app with batteries included (auth, validation, queues, scheduler, localization). One
codebase, no separate frontend SPA. The same codebase scales up unchanged to a
central VPS — optionally Laravel Octane — for a large school: an infra migration, not
a rewrite, so one stack spans the whole market. Online-first: the only offline-write
flow is teacher attendance (a contained PWA module, see CLAUDE.md) — not a general
offline-first architecture. A native mobile app is deferred; it will consume a JSON
/api (API Resources + Sanctum) on top of the service layer — the reason controllers
stay thin and logic lives in services.
Requires PHP 8.3+, Composer, and Docker. Node is needed only for the Playwright E2E suite.
docker compose up -d # MySQL + Redis + Mailpit
composer setup # install, .env, key, migrate, Tailwind CLI, build CSS
php artisan db:seed # demo school: 3 children, a teacher, admin, a wali
php artisan serve # http://127.0.0.1:8000
composer assets:watch # (separate terminal) rebuild CSS on changeDemo logins (password password): admin@cahayatauhid.sch.id (admin),
sari@cahayatauhid.sch.id (guru), bunda@cahayatauhid.sch.id (wali).
Checks: composer test (Pest), composer analyse (Larastan, max), vendor/bin/pint
(style). E2E: npm install && npm run e2e:install && npm run e2e (Playwright).
A user manual (23 chapters, Indonesian) is published as a GitHub Pages site,
auto-generated by the Publish User Manual workflow on every push to main:
- Source:
docs/user-manual/*.md - Chapter registry:
config/manual.php - Renderer:
php artisan manual:render→storage/manual/index.html(self- contained: HTML + CSS + screenshots/, ready to host anywhere). - Screenshots: captured by
tests/e2e/manual-screenshots.spec.tsagainst the seeded demo data; lands underdocs/user-manual/screenshots/. - Workflow:
.github/workflows/publish-manual.ymlruns Playwright +manual:render+actions/deploy-pages@v4.
The published URL is the GitHub Pages site for this repo.
- Phase 0 — Foundation ✓ — project skeleton; session auth + RBAC; the
kelas/siswa/wali_siswa/tahun_ajaran/semester/enrollmentdata model; design-system port to Tailwind (earth-tone themes, Plus Jakarta Sans + Amiri); app shell + bottom nav + responsive desktop; PWA manifest + service worker; strict CSP middleware. - Phase 1 — MVP modules ✓ — the nine signature modules: pengumuman, jadwal, absensi (with offline write-queue + IndexedDB outbox + idempotent replay), nilai & raport, tugas, mutaba'ah, hafalan Quran (Juz 30), kalender (Hijri + Gregorian), chat (guru–wali, htmx polling).
- Phase 2 — Admin panel + SPP billing ✓ — Filament panel at
/admingated to admin role; foundational CRUD (users, siswa, kelas, tahun ajaran, semester, mapel). SPP billing only:tagihanupsert keyed on(siswa, periode),pembayaranlog, status derived from sums (belum_bayar | sebagian | lunas), money stored as integer rupiah (BIGINT). Payment rail is Phase 4. - Phase 2.5 — Manual SPP confirmation workflow ✓ — the standard Indonesian-
school manual collection workflow: wali uploads transfer receipt → row created
with
status = menunggu_verifikasi(doesn't count towardterbayaryet); TU in Filament verifies (one click) or rejects (withalasan). Wali may edit or cancel only while stillmenunggu; once verified/rejected the row is final. Bukti files served through an authenticated/bukti-transfer/{id}route, not via a public storage URL. Schools can collect SPP end-to-end on this app without any payment-gateway dependency — pilot-ready independently of the Phase 4 integrations. - Phase 3 — Content & self-service ✓ — galeri (album + foto on S3-compatible
storage;
disk('media')withthrow: true), profil self-service (name/email with unique-ignoring-self, password change with current-password verification), multi-tenancy stocktake (docs/MULTI_TENANCY.md). - Phase 4 — Closed-loop integrations + public API — the integration layer
with the sibling products, plus the Sanctum-issued JSON API and a native shell
on top.
snap-payment-gatewayclient (wali-initiated payment via VA/QRIS over HTTP; webhook ingestion writes apembayaranrow through the existing service).- Balaka REST client (on
pembayarancleared → one journal-entry POST; the school stays free of general-ledger code). closed-loop-walletclient (read-only views of card balance + recent transactions for the wali/siswa surfaces; topup-initiation handoff to the wallet's REST API. POS auth, ledger, settlement, and outlet onboarding all live in the wallet product — seeCLAUDE.md"Locked decisions".)- JSON
/apiwith Sanctum, reusing the existing services unchanged (controllers stay thin, services stay transport-agnostic — by design from Phase 0). - Native mobile shell (Capacitor over the existing PWA, or React Native —
decided when Phase 4 starts) consuming that API. Real push (APNs/FCM)
happens here, not on the PWA (iOS push gaps documented in
CLAUDE.md). - Gated on the sibling products' first releases — none of the three integrations is speculative.
- Phase 5 — Remaining content — materi belajar, konsultasi BK (when a pilot asks for them).
UI originates from a Claude Design handoff bundle (app "Cahaya Tauhid"): mobile
screens for all four roles plus one responsive desktop dashboard. Visual language
is fixed — earth-tone palettes, Plus Jakarta Sans (Latin) + Amiri (Arabic), Hijri
dates alongside Gregorian, subtle Islamic geometric motifs. Design tokens and the
component inventory are recorded in CLAUDE.md.
Apache License 2.0 — see LICENSE. Matches the rest of the Artivisi product line
(Balaka, snap-payment-gateway, disbursement-platform, closed-loop-wallet,
Tawqi), so cross-product integration carries no license friction.