Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 18 additions & 55 deletions .pi/HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,35 @@ This is the repository's only active session checkpoint. `AGENTS.md`, source cod

## Current Objective

Complete production readiness for the deployed SIAB1 stack at `siab.man1rokanhulu.cloud` from the canonical repository at `https://github.com/kuker24/SIAB1`.
None. Student hot-path closeout is complete. Do not reopen Go routing, START/JOIN/ANSWER handlers, or live canary files without explicit ops intent.

## Current State

- Project identity is `SIAB1` / `Sistem Informasi Asesmen Berintegritas`.
- Technical slug, Compose project, database, images, and monitoring labels use `siab1`.
- Android native package is `id.siab1.kiosk`; Flutter fallback is `id.siab1.flutter`.
- Release clients require an explicit server URL; `siab1.invalid` is a non-release placeholder.
- Public hostname is `siab.man1rokanhulu.cloud`; Cloudflare remains authoritative DNS in DNS-only mode.
- SafeLine CE terminates public TLS and forwards to the loopback-only SIAB1 Nginx origin at `127.0.0.1:8080`.
- SafeLine management binds to `127.0.0.1:9443` and is accessed only through an SSH tunnel.
- SIAB1 and SafeLine are deployed at `/opt/siab1` and `/opt/safeline`; DNS cutover and public TLS are active.
- The deployed SIAB1 and SafeLine manifests and critical backend files match the canonical local sources by checksum.
- Native Android `2.0.1` build 3 is present on the VPS and its checksum is valid.
- Native Android `2.0.2+4` has been rebuilt with the original release key after a post-submit
exit-to-home fix and reinstalled on the Xiaomi `2306EPN60G`; it has not been published.
- Python/FastAPI and Flutter remain supported fallbacks.
- Legacy phase reports, stale deployment scripts, duplicate client sources, and unused web assets were removed after consolidation.
- Repo: `/home/fahmiagent/Downloads/LAB GITHUB/LAB_Transformation/SIAB1/SIAB1`.
- Branch `provenance/migration-reconciliation`. Closeout commit `2856e47dca8c4e6105825ebc552f31d031fd7058` (`scripts/go_hotpath_lifecycle.py` only).
- Production `/opt/siab1`: Go image `siab1-go:373c131` healthy. Six student routes GO 100% (join, start, submit-answer, auto-save, auto-save-batch, submit). FastAPI fallback remains in nginx maps and `go_start_backend` backup.
- VPS rerun of `2856e47` (2026-08-28): lifecycle PASS; mixed-50 50/50 100%; 5xx=0; 429=0; lost/dups/live/wrong/missing=0; Redis PASS; PgBouncer `cl_waiting=0` `maxwait=0`; origin/public `/health` 200/200.
- Codebase Memory project: `SIAB1-clean`.
- Leave dirty: `.scratch/`, `scripts/go_remaining_stage0.py`, `scripts/build_card_users_csv.py`, `scripts/sync_school_users.py`, their tests, `docker/Dockerfile.go-test`.

## Verification Evidence

- **PASS** - full Python suite: 528 tests.
- **PASS** - `python scripts/check_security.py` and release gate with `SKIP_HTTP=1`.
- **PASS** - Go test, vet, and build.
- **PASS** - Android kiosk Kotlin compile and lint.
- **PASS** - Compose config, shell syntax, and shellcheck.
- **PASS** - SIAB1 identity guard and local documentation-link guard.
- **PASS** - GitHub production hardening workflow through readiness commit `d00062e`.
- **PASS** - read-only VPS audit: 16 vCPU, 15 GiB RAM, 4 GiB unused swap, healthy SIAB1 containers, healthy ops summary, and 100% Redis stability.
- **PASS** - DNS, Let's Encrypt TLS, origin health, and public health; both health paths returned HTTP 200.
- **PASS** - automated daily backup and weekly non-destructive restore drill.
- **PASS** - weekly stateless auto-restart schedule, host-control path, and dry-run safety guard.
- **PASS** - controlled public load phases 50, 200, and 620 with 100% start/answer/submit.
- **PASS** - public violation/WebSocket smoke and upload smoke with synthetic cleanup.
- **PASS** - read-only capacity snapshot under root without weakening secret permissions.
- **PASS** - Flutter analyze and widget test using an isolated stable SDK.
- **PASS** - deployed runtime checksum dry-run and full release manifest verification.
- **POLICY BLOCKED** - export success-path while peak mode disables heavy exports; HTTP 503 guard verified.
- **PASS** - signed Android `2.0.2+4`; package, version, production URL, APK alignment, and
signer continuity with `2.0.1` were verified. SHA-256
`44030edda5aad3622ff813a8b4b75657d4691117690963a975542f21e1685a0b`.
- **PASS** - native post-submit contract: `examSubmitted` now stops the WebView, clears auth,
and calls `finishAndRemoveTask()` so `/student/` login never appears. Physical submit retest
of this rebuilt APK is still pending.
- **PASS** - burst-latency apply 2026-08-26 (no `down -v`, zero live sessions): Nginx serves
`/static/` from disk (critical JS still `no-store`); `start_exam_session` delegates to
`_build_start_question_responses`; Prometheus exporters postgres/redis/nginx/node `up`;
Celery `result_expires=3600` and `task_ignore_result=True`; student API `--workers 2`.
Origin and public `/health` HTTP 200. Rollback copies at `/opt/siab1/*.bak-burst-20260826`.
- **PASS** - physical-device Android `2.0.2+4` smoke: clean install, cold launch, invalid and
valid login/token flows, trusted native exam start, two-answer autosave, offline/reconnect,
final submit with score, screen pinning, screenshot blocking, clean kiosk exit, and no
crash/ANR/runtime error. The isolated synthetic exam/user/session and local credentials were
removed after verification; the pre-smoke backup remains at
`/opt/siab1/backups/pre-physical-smoke-20260826T052900.sql.gz` with its checksum sidecar.
- **PASS** - single lifecycle through nginx (`HOTPATH_MIXED=0`): all replicas `go-start`, score 100, redis PASS, cleanup PASS.
- **PASS** - mixed-50 paced closeout (`HOTPATH_MIXED=50`): correctness 100%; service p50 310.018 / p95 402.694 / p99 524.476 / max 524.476; wall 87.996s.
- **PASS** - canary files 100pct for all six routes; FastAPI fallback AVAILABLE; rollback not invoked.
- Docs refreshed to match this topology: `AGENTS.md`, `ARCHITECTURE.md`, `README.md`, `docs/HISTORY.md`.

## Remaining Decisions

- Back up the recovered release signing material to approved external private storage.
- Clarify whether trusted native sessions should populate `ExamSession.is_secure_app_verified`;
native header enforcement passed, but this currently unused observability field remains false.
- Publish signed Android `2.0.2+4` only after explicit release approval.
- Test export success-path only during an approved maintenance window with peak mode disabled.
- Refresh the finite weekly auto-restart entries before the current schedule horizon expires.
- Android `2.0.2+4` still needs signing material and physical-device smoke. Never ship `siab1.invalid`.
- Synchronized-burst p95 stays a watch item on real exam waves.
- Heavy export success-path only in an approved maintenance window.
- Repo Compose still marks `go_server` as profile `native-lean`; live routing is the canary maps, not that comment.
- Do not commit the leftover dirty files unless an operator asks.

## Production Safety Boundary

- Do not read or expose environment files, keys, tokens, certificates, participant answers, or credentials.
- Do not deploy, publish assessments, restart services, migrate data, or run heavy tests without explicit approval and a verified backup.
- Do not use `docker compose ... down -v` on production.
- Do not overwrite `runtime_control/nginx.*-canary.conf`. Dual-write answers is forbidden. Rollback is a per-route canary swap to FastAPI.
25 changes: 17 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,36 @@ SIAB1 (Sistem Informasi Asesmen Berintegritas) provides protected assessment del
- Context contract: this file is the durable project map; `.pi/HANDOFF.md` is the only active session checkpoint. Treat every other AI handoff, save, snapshot, or progress note as historical unless that checkpoint explicitly promotes it.

## Technology
- Backend: Python 3.11, FastAPI `0.135.1`, async SQLAlchemy `2.0.48`, PostgreSQL, Redis, Celery `5.6.2`, and Nginx.
- Control and non-hot-path API: Python 3.11, FastAPI `0.135.1`, async SQLAlchemy `2.0.48`.
- Student hot-path: Go `go_server` (image `siab1-go:373c131` at last VPS closeout). FastAPI stays nginx map default and `go_start_backend` backup.
- Shared: PostgreSQL, Redis, Celery `5.6.2`, Nginx, PgBouncer.
- Production images: PostgreSQL `15-alpine`, Redis `7-alpine`, Prometheus `v2.53.0`, Grafana `11.1.0`.
- Client: Flutter at `flutter_client_code`; entry `flutter_client_code/lib/main.dart`; package version `2.0.0+2`; Dart SDK `>=3.0.0 <4.0.0`.

## Entry Points
- API application: `app/main.py`.
- FastAPI application: `app/main.py`.
- Go hot-path server: `go/cmd/server/main.go`.
- Configuration: `app/config.py`; settings read from `.env`. Never read or print environment secrets.
- Database wiring: `app/database.py`.
- High-impact API path: `app/api/exams.py`.
- High-impact FastAPI path: `app/api/exams.py` (fallback + non-hot-path).
- Live nginx canary maps: `runtime_control/nginx.{start,join,answer,autosave,batch,submit}-canary.conf`.
- Production orchestration: `docker-compose.production.yml`.
- Flutter application: `flutter_client_code/lib/main.dart`.
- Topology: `ARCHITECTURE.md`. Session checkpoint: `.pi/HANDOFF.md`.

## Repository Structure
- `app/api`: API routes.
- `app/api`: FastAPI routes (control plane, login, poll, export, hot-path fallback).
- `app/core`: shared runtime, policy, and operational logic.
- `app/middleware`: HTTP security, SXB enforcement, logging, rate limiting, and performance middleware.
- `app/models`: SQLAlchemy ORM models.
- `app/schemas`: Pydantic request and response schemas.
- `app/services`: application services.
- `app/tasks`: Celery tasks and scheduler.
- `go`: native student hot-path (join, start, submit-answer, auto-save, auto-save-batch, submit).
- `runtime_control`: live nginx canary maps; treat as production routing.
- `flutter_client_code`: Flutter student client.
- `docker`: production Dockerfiles, Nginx config, certificates mount path, and database initialization.
- `scripts`: maintenance, security, release-gate, and VPS-readiness commands.
- `scripts`: maintenance, security, release-gate, VPS-readiness, and hot-path closeout (`scripts/go_hotpath_lifecycle.py`).
- `monitoring`: Prometheus and Grafana configuration.
- `tests`: committed pytest suite; 63 files at mapping snapshot.
- `docs`: operational, deployment, validation, and historical documentation.
Expand Down Expand Up @@ -64,6 +71,7 @@ SIAB1 (Sistem Informasi Asesmen Berintegritas) provides protected assessment del
- Production origin serves `/static/` from Nginx disk (`alias`); critical exam JS stays `no-store`. Prometheus exporters (postgres, redis, nginx, node) must stay `up`.
- Postgres production budget is `shared_buffers=512MB` / 1536M limit. Do not restore `2560MB` without a measured working-set need. Student API `--workers 2` stays for burst.
- `DEBUG=true` and `DISABLE_RATE_LIMIT=true` are development-only. Telegram alerts require configured `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_IDS`.
- Student hot-path writer is Go at 100% canary for join, start, submit-answer, auto-save, auto-save-batch, and submit. FastAPI remains the map default and `server api:8000 resolve backup`. One writer per session; dual-write answers is forbidden. Rollback is a per-route canary swap to FastAPI, not `docker compose down -v`. Do not overwrite live `runtime_control/nginx.*-canary.conf` or change START/JOIN/ANSWER Go handlers without explicit ops intent.

## Common Commands
### Local API
Expand Down Expand Up @@ -118,13 +126,14 @@ bash scripts/verify_stable_release_vps.sh
```

## VPS Deployment Map
The production stack is deployed on the target VPS. The facts below were verified read-only on 2026-08-22 and remain a documented snapshot rather than continuous monitoring evidence.
The production stack is deployed on the target VPS. Topology below matches the 2026-08-28 student hot-path closeout; treat host sizing and health as a snapshot, not continuous monitoring evidence.

- SIAB1 is deployed at `/opt/siab1`; SafeLine is deployed at `/opt/safeline`.
- Compose project, database, monitoring cluster, and image names use the `siab1` slug.
- Traffic contract: domain -> SafeLine -> loopback-only Nginx -> student or admin/control API lanes -> PgBouncer -> PostgreSQL. Service health path: `/health`.
- Nginx fronts eight student lanes (`api` through `api8`) and two isolated admin/control lanes (`api_admin`, `api_admin2`).
- Traffic contract: domain -> SafeLine -> loopback-only Nginx. Six student hot-path routes go to `go_start_backend` (Go primary, FastAPI backup). Remaining student and admin/control traffic stays on FastAPI lanes. Then PgBouncer -> PostgreSQL. Service health path: `/health`.
- Nginx fronts eight student FastAPI lanes (`api` through `api8`), two isolated admin/control lanes (`api_admin`, `api_admin2`), and `go_server` for the hot-path.
- Supporting services: PostgreSQL, PgBouncer, Redis, Celery worker, Celery beat, Prometheus, Grafana, and postgres/redis/nginx/node exporters. Optional `db_replica` is Compose profile `scaling`.
- Repo Compose still lists `go_server` under profile `native-lean`; live production runs `siab1-go:373c131`. Do not take the profile comment as current routing.
- Public hostname is `siab.man1rokanhulu.cloud`. Cloudflare provides authoritative DNS in DNS-only mode; SafeLine terminates public TLS and forwards to `127.0.0.1:8080`.
- SafeLine management binds to `127.0.0.1:9443` and must be accessed through an SSH tunnel. Never expose the management port publicly.
- The verified host has 16 vCPU, 15 GiB RAM, 4 GiB swap, and a 58 GiB root filesystem. All SIAB1 and SafeLine containers were running; public and origin health returned HTTP 200.
Expand Down
Loading
Loading