URL: https://zxparenting.zomet.my.id/admin
Stack: Next.js 15 + Prisma + PostgreSQL
Repo: djvpri/zx_parenting (private)
Deploy: Coolify VPS 103.93.129.94, container pd59y3gb3k6nkqjqvm873uim
/login?tab=adminsesiAdmin())| Route | Fungsi | File |
|-------|--------|------|
| /admin | Dashboard overview: summary cards (anak, ortu, tugas, device online) | admin/page.tsx |
| /admin/anak | CRUD anak (list, tambah, edit, hapus) | admin/anak/page.tsx |
| /admin/tugas | CRUD tugas + assign ke anak | admin/tugas/page.tsx |
| /admin/insights | AI insights per anak (Gemini/rule-based) | admin/insights/page.tsx |
| /admin/error-log | Error log dari app anak + ortu | admin/error-log/page.tsx |
#### Admin Page: /admin/error-log
ActivityLog where tipe='error'/mockup-error-log.html (live)#### Machine-Readable API: GET /api/error-log
?token=<CRON_TOKEN> (sama pola /api/cron/jadwal-ai) - limit ā max rows (default 50, max 500)
- since ā filter age: 24h, 7d, 30d, all (default 24h)
- platform ā filter source: anak, ortu, all (default all)
{
"summary": { "total": 0, "last24h": 0, "anakCount": 0, "ortuCount": 0 },
"errors": [
{
"id": "cmv...",
"waktu": "2026-10-13T04:24:48.304Z",
"ageMs": 3600000,
"sumber": "anak|ortu",
"nama": "Budi",
"screen": "LayarKuisAI",
"message": "kuisStart fail",
"extra": { "code": 500 }
}
]
}{
"summary": { "total": 0, "last24h": 0, "anakCount": 0, "ortuCount": 0 },
"errors": [
{
"id": "cmv...",
"waktu": "2026-10-13T04:24:48.304Z",
"ageMs": 3600000,
"sumber": "anak|ortu",
"nama": "Budi",
"screen": "LayarKuisAI",
"message": "kuisStart fail",
"extra": { "code": 500 }
}
]
}
- **AI agent usage:**
curl "https://zxparenting.zomet.my.id/api/error-log?token=zx-cron-2026&since=24h&platform=anak"
curl "https://zxparenting.zomet.my.id/api/error-log?token=zx-cron-2026&since=24h&platform=anak"
#### Endpoint Error Report (push dari app)
| App | Endpoint | Auth | Body |
|-----|----------|------|------|
| Anak | `POST /api/agent` | `x-device-token` header | `{"aksi":"lapor-error","detail":{"screen":"...","message":"..."}}` |
| Ortu | `POST /api/ortu/lapor-error` | `Authorization: Bearer <jwt>` | `{"screen":"...","message":"...","extra":{}}` |
#### Schema: `ActivityLog`#### Endpoint Error Report (push dari app)
| App | Endpoint | Auth | Body |
|-----|----------|------|------|
| Anak | POST /api/agent | x-device-token header | {"aksi":"lapor-error","detail":{"screen":"...","message":"..."}} |
| Ortu | POST /api/ortu/lapor-error | Authorization: Bearer <jwt> | {"screen":"...","message":"...","extra":{}} |
#### Schema: ActivityLog
model ActivityLog {
id String @id @default(cuid())
anakId String? // nullable sejak v3.6.0 (error ortu punya no anakId)
userId String? // NEW v3.6.0 (FK ā User.id, nullable)
tipe String // 'error' | 'activity' | 'lapor-error' (rewrite ā 'error')
detail Json?
createdAt DateTime @default(now())
anak Anak? @relation(fields: [anakId], references: [id])
user User? @relation(fields: [userId], references: [id])
}model ActivityLog {
id String @id @default(cuid())
anakId String? // nullable sejak v3.6.0 (error ortu punya no anakId)
userId String? // NEW v3.6.0 (FK ā User.id, nullable)
tipe String // 'error' | 'activity' | 'lapor-error' (rewrite ā 'error')
detail Json?
createdAt DateTime @default(now())
anak Anak? @relation(fields: [anakId], references: [id])
user User? @relation(fields: [userId], references: [id])
}
### Sidebar Navigation
Dashboard āāā Anak āāā Tugas āāā Insights āāā Error Log ā NEW v3.6.0
Dashboard
āāā Anak
āāā Tugas
āāā Insights
āāā Error Log ā NEW v3.6.0
### API Routes (admin) | Endpoint | Method | Auth | Fungsi | |----------|--------|------|--------| | `/api/admin/metrics` | GET | `sesiAdmin()` | Summary stats dashboard | | `/api/error-log` | GET | `?token=<CRON_TOKEN>` | Machine-readable error JSON | ### Commits - `0f53b98` ā schema + `/api/ortu/lapor-error` + `/admin/error-log` page - `2fab773` ā `/api/error-log` machine-readable JSON endpoint - Mockup: `mockup-error-log.html` (committed to repo)
| Endpoint | Method | Auth | Fungsi |
|----------|--------|------|--------|
| /api/admin/metrics | GET | sesiAdmin() | Summary stats dashboard |
| /api/error-log | GET | ?token=<CRON_TOKEN> | Machine-readable error JSON |
0f53b98 ā schema + /api/ortu/lapor-error + /admin/error-log page2fab773 ā /api/error-log machine-readable JSON endpointmockup-error-log.html (committed to repo)