Files
GMW/.hermes/plans/2026-08-24_135602-gmw-fe-constellation-rombak.md
T
asepharyana 1accfd9390 perf(ai-moderation): naikkan cache hit dgn guard akurasi
- Fase-1 exact-cache lookup: N query serial -> SATU query ANY($1::text[])
- Global reuse utk bare key legacy, HANYA verdict non-actionable
  (clean/flagless/action=none, conf>=0.85, umur<=72h) — flagged/warn
  tetap context-scoped
- Semantic cache dua-band: clean band 0.92 default, actionable tetap
  0.97; di antara band -> LLM (fail-open ke akurasi)
- hit_count kini di-increment (bulk UPDATE per batch) -> hit-rate terukur
- Cache hasil wikipediaSearch di Redis (6h, hanya hasil non-kosong)
- Memoize fetchUrlSafely utk type=text (LRU 30m + in-flight dedupe)
- makeImageCacheKey strip query CDN Discord (?ex/is/hm, format/width)
  -> attachment sama = satu key vision, skip re-download+re-vision

Spec: .hermes/plans/2026-08-24-ai-analysis-cache-optimization.md
Tests: +33 (cacheGuards, discordImageKeyNormalize, cacheBatchLookup)
2026-08-24 18:51:23 +07:00

15 KiB
Raw Blame History

GMW FE Rombak — "Constellation Ops" Implementation Plan

For Hermes: Use subagent-driven-development skill to implement this plan task-by-task. Setiap task = edit → lint → build/test → smoke → commit (author asepharyana, tanpa Co-Authored-By).

Goal: Rombak total FE GMW dari template dashboard klasik menjadi Constellation Node Graph — graf node interaktif (three.js force layout) di mana channel/event/moderasi adalah node bintang dan navigasi adalah terbang antar node — untuk semua 9 route sekaligus.

Architecture: Hapus total shell template (TopBar + NavRail + MobileNav + main scroll container). Ganti dengan satu ConstellationStage: canvas full-bleed fixed di belakang seluruh app yang me-render force-directed graph per-route (scene), plus overlay HTML mengambang (tanpa card box standar) untuk konten detail. Router tetap Next App Router; perpindahan route = kamera "fly-to" ke scene baru. Data tetap lewat pola SSR seed (page.tsx server fetch → view.tsx client + SWR fallbackData) — tidak ada endpoint baru yang diarankan.

Tech Stack: Next.js 16 App Router · React 19 · TypeScript strict · Tailwind v4 (token oklch existing) · three r180 (+ @types/three) · d3-force (+ @types/d3-force) untuk simulasi layout deterministik · motion v12 (transisi antar-scene) · biome (0 error dan 0 warning) · bun:test untuk modul murni.


Keputusan Terkunci (2026-08-24, user MythEclipse)

Keputusan Pilihan user
Cakupan Semua 9 route sekali jalan (dashboard, voice, media, recordings, moderation, messages, analysis, channels, glossary)
Arah struktural Constellation Node Graph — navigasi = terbang antar node
Tema Pertahankan toggle light/dark (jangan rebuild sistem tema — harden saja)

Kondisi Saat Ini (fakta repo, 2026-08-24)

  • Repo: /home/code/GMW/services/frontend (monorepo GMW, deploy Nix-first via GHA "Build & Deploy (Nix)" ke imphnen.asepharyana.my.id; nginx gmw-proxy :4009 → Next standalone :4017).
  • Shell aktif: src/components/shell/ambient-app.tsxAppFrame = NavRail + TopBar + <main> scroll + MobileNav + MiniPlayer, dipakai SEMUA route via (dashboard)/layout.tsx. AmbientCanvas (233 l) masih ada sebagai background di belakang chrome template.
  • 9 route di src/app/(dashboard)/: dashboard (368 l), voice (311), media (293), moderation (424), messages (611), analysis (196), recordings (201), channels (23), glossary (15).
  • next.config.ts: output: "standalone" + trailingSlash: truenav via router.push/Link bisa no-op; pakai <a href> polos (pitfall terverifikasi).
  • Token desain ada di globals.css @theme: --color-canvas/-2, --color-ink/-soft/-faint, --color-signal(+glow), amber, vermilion, hairline; font Bricolage Grotesque/JetBrains Mono; .light class override + next-themes sudah jalan — JANGAN dibangun ulang.
  • Sudah ada & dipertahankan: CommandPalette (⌘K), Chatbot, MiniPlayer, primitives (GlassPanel/GlassCard/Badge/…), shared states+skeletons, lib/format.ts, lib/ai-status.ts, WS typed events (message_created/updated/deleted/analyzed/snapshot*, voice_state, dll).
  • Tooling lokal: pnpm lint|build|format, pnpm exec biome check --write --unsafe . buat import order; bun 1.3.14 tersedia untuk unit test modul murni.
  • Smoke test SELALU di port non-prod (mis. 4024), cek ss -ltnp | grep <port> dulu; JANGAN pernah bind 4017.

Struktur Target

src/components/shell/
  constellation-frame.tsx    # pengganti AppFrame: tanpa topbar/rail/bottom-bar
  constellation-stage.tsx    # canvas three.js full-bleed + hit-test + kamera
  route-scenes.ts            # map pathname → scene config (nodes/edges/focus)
  floating-chrome.tsx        # brand mark + status dot + route switcher minim + palette hint
  (hapus setelah migrasi): topbar.tsx, nav-rail.tsx, mobile-nav.tsx, ambient-app.tsx*
src/lib/constellation/
  graph.ts                   # tipe GraphNode/GraphEdge + builder dari data API (murni)
  layout.ts                  # wrapper d3-force deterministik (seeded) + fallback radial (murni)
  camera.ts                  # interpolasi kamera fly-to (murni, testable)
  *.test.ts                  # bun:test utk modul murni di atas

*ambient-canvas/context dievaluasi: bisa di-refactor jadi bagian dari stage atau dihapus.

Scene per route (bahasa visual satu kesatuan)

Route Scene
/dashboard/ Guild = bintang pusat; channel = node orbit; event WS = pulse edge; metric cluster floating (tanpa box)
/channels/ Semua channel sebagai konstelasi; klik channel = fly-to + panel detail mengambang
/moderation/ Pesan flagged = node merah (vermilion) mengelilingi hub AI-verdict; LiveModerationFeed jadi ribbon ticker
/messages/ Stream pesan = sabuk orbital; node baru masuk lewat animasi dari tepi
/voice/ Stage node di tengah; speaker aktif = node mengorbit dengan glow intensitas
/media/ Galeri spiral node (thumbnail via div bg-image); klik = MiniPlayer handoff
/recordings/ Variasi spiral media, timeline density sebagai cincin
/analysis/ Hub analitik; chart existing dirender sebagai panel translusen mengambang ter-anchor ke node
/glossary/ Term KB = cincin satelit; search memfilter node real-time

Checklist anti-default (wajib lolos sebelum commit akhir)

  • Tidak ada top bar / nav rail / side panel / bottom prompt bar
  • Tidak ada card grid standar sebagai struktur utama
  • Layout beda SPASIAL dari versi lama (bukan ganti warna)
  • Verifikasi visual sungguhan: browser_navigate + browser_vision → "bukan template dashboard"

Tasks

Phase 0 — Fondasi

Task 1: Dependencies + scaffold direktori

Files: package.json, create src/lib/constellation/

  1. cd /home/code/GMW/services/frontend && pnpm add three @types/three d3-force @types/d3-force && pnpm add -d @types/bun
  2. Buat 4 file kosong bertipe sesuai struktur target (ekspor placeholder bertipe agar tsc lolos).
  3. Run: pnpm exec tsc --noEmit → expected PASS.
  4. Commit: chore(frontend): scaffold constellation lib + deps.

Catatan: jika @types/bun bentrok dengan tsconfig Next (duplikat globals), fallback: exclude "**/*.test.ts" dari tsconfig.json dan jalankan test hanya via bun test (tanpa typecheck). Putuskan saat eksekusi, dokumentasikan di commit body.

Task 2 (TDD): Modul murni graph + layout + camera

Files: src/lib/constellation/{graph,layout,camera}.ts + *.test.ts

  1. Tulis test dulu (bun:test):
    • graph.test.ts: builder dashboardToGraph() menghasilkan node guild pusat + N channel + edges benar dari fixture /api/dashboard/stats|channels shape (lihat AGENTS.md; nama channel di message.metadata.channelName).
    • layout.test.ts: computeLayout(nodes, edges, {seed:42}) DETERMINISTIK (dua pemanggilan = posisi identik), semua posisi finite, radius dalam bound; radialLayout() fallback untuk reduced-motion.
    • camera.test.ts: flyTo(from,to,t) easing monotonic, t=0→from, t=1→to.
  2. Run: bun test src/lib/constellation → expected FAIL (belum diimplementasi).
  3. Implementasi minimal sampai PASS.
  4. Run: bun test src/lib/constellation && pnpm exec tsc --noEmit → PASS.
  5. Commit: feat(frontend): constellation graph/layout/camera pure modules (tested).

Phase 1 — Shell Baru

Task 3: ConstellationStage (canvas renderer)

Files: src/components/shell/constellation-stage.tsx

  • <canvas> fixed inset-0 -z-10; three.js orthographic 2D-ish render node+edge (sprite/glow shader sederhana — jangan over-engineer; titik + garis + glow cukup).
  • Interaksi: drag = pan, wheel/pinch = zoom, hover = highlight node + tooltip title, click node ber-href = navigasi via <a> semantics (window.location assign — hindari router.push no-op).
  • DPR-aware resize; pause render loop saat document.hidden; prefers-reduced-motion → render statis tanpa animasi.
  • Sampling warna dari CSS var (getComputedStyle) + MutationObserver pada documentElement.classList agar ikut toggle dark/light.
  • Verify: pnpm lint && pnpm build PASS → commit feat(frontend): constellation stage canvas renderer.

Task 4: route-scenes.ts + ConstellationFrame

Files: src/components/shell/{route-scenes,constellation-frame,floating-chrome}.tsx

  • route-scenes.ts: usePathname() → config scene (builder mana, focus node, overlay slots).
  • ConstellationFrame: render ConstellationStage + children (overlay HTML absolute, BUKAN flex column bertingkat) + floating-chrome (brand mark kiri-atas dgn status dot WS, switcher route minimal kanan-bawah, hint ⌘K). MiniPlayer + Chatbot + CommandPalette tetap termounting.
  • Switcher & semua nav internal pakai <a href="/<route>/"> polos (trailingSlash!). Verifikasi klik di browser nanti, bukan cuma baca kode.
  • Wire (dashboard)/layout.tsx: ganti AppFrameConstellationFrame (provider Ambient/WS tetap).
  • Smoke: ss -ltnp | grep 4024 kosong → PORT=4024 pnpm start → curl semua 9 route = 200 → kill server.
  • Commit: feat(frontend): replace classic shell with constellation frame.

Task 5: Hapus chrome lama + bersih-bersih

Files: hapus shell/topbar.tsx, shell/nav-rail.tsx, shell/mobile-nav.tsx, update shell/index.ts; eval ambient-* (refactor jadi layer stage ATAU hapus).

  • grep -rn "TopBar\|NavRail\|MobileNav\|AppFrame" src/ → 0 referensi tersisa.
  • pnpm exec biome check --write --unsafe . → import order rapi.
  • Commit: refactor(frontend): remove classic dashboard chrome.

Phase 2 — Migrasi 9 Route (batch, tiap batch ship hijau)

Urutan sengaja dari yang paling graph-native ke paling padat konten:

Task 6: /dashboard/ + /channels/

  • Dashboard view: guild-star + channel orbit + WS pulse; metric cluster floating (reuse MetricTile tapi tanpa card-box — ubah jadi teks besar + hairline).
  • Channels: konstelasi channel, klik = fly-to + panel detail (data dari hook use-channels/server fetch existing — jangan karang endpoint).
  • Lint+build+smoke 2 route → commit feat(frontend): dashboard & channels constellation scenes.

Task 7: /glossary/ + /analysis/

  • Glossary: cincin satelit term + search filter node (client-side filter pada node label).
  • Analysis: hub node + panel chart translusen mengambang (reuse komponen charts/* existing, anchor posisi ke node).
  • Commit: feat(frontend): glossary & analysis scenes.

Task 8: /messages/ + /moderation/

  • Messages: sabuk orbital stream (reuse sortMessages/logika WS use-messages.ts — jangan duplikasi); pesan baru animate-in dari tepi.
  • Moderation: flagged nodes vermilion + hub verdict; LiveModerationFeed jadi ticker ribbon bawah (bukan panel).
  • Commit: feat(frontend): messages & moderation scenes.

Task 9: /voice/ + /media/ + /recordings/

  • Voice: speaker aktif orbit dgn glow (seed dari snapshot activeSpeakers server-authoritative — pertahankan perilaku useSpeakers).
  • Media/Recordings: spiral galeri; thumbnail pakai div background-image (hindari noImgElement; kalau terpaksa <img>// biome-ignore lint/performance/noImgElement: <alasan>); MiniPlayer handoff tidak boleh regress.
  • Commit: feat(frontend): voice, media & recordings scenes.

Phase 3 — Polish, A11y, Tema

Task 10: Motion & micro-interaction

  • Fly-to antar scene pakai motion v12 (interpolasi kamera dari lib/constellation/camera.ts).
  • Overlay: stagger masuk (pattern animate-stagger + staggerDelay(i) existing); tambah semua animate-* baru ke kill-list prefers-reduced-motion di globals.css.
  • Commit: feat(frontend): scene transitions + motion polish.

Task 11: A11y & fallback semantik

  • Setiap scene punya fallback semantik: <nav aria-label="Routes"> visually-hidden berisi link semua route + <ul> node (label + href) yang ter-sync dgn graph state.
  • Keyboard: Tab ke daftar route; panah memindahkan fokus antar node; Enter aktivasi; focus-visible ring pakai --color-ring.
  • Kontras ink-on-canvas dicek (WCAG AA utk teks overlay).
  • Hooks-after-early-return pitfall: compute flags dulu, guard di dalam useEffect.
  • Commit: feat(frontend): a11y semantic fallback for constellation.

Task 12: Hardening tema light/dark

  • Pastikan canvas sampling var .light benar saat toggle (MutationObserver dari Task 3); harden .light: color-scheme: light, scrollbar/selection, glow opacity turun.
  • JANGAN menyentuh sistem next-themes.
  • Commit: fix(frontend): light theme parity for constellation stage.

Phase 4 — Gerbang Ship (non-negotiable)

Task 13: Verifikasi penuh + deploy

  1. pnpm lintFound 0 errors. Found 0 warnings (warning pun harus bersih).
  2. bun test src/lib/constellation → all PASS; pnpm exec tsc --noEmit PASS; pnpm build sukses.
  3. Smoke: port 4024 bersih → start → curl 9 route (dgn trailing slash) semua 200 → kill server.
  4. git status audit: hanya file scope yang ter-commit (git checkout -- file liar hasil auto-format).
  5. Push origin/maingh run watch "Build & Deploy (Nix)" → hijau.
  6. Live: curl https://imphnen.asepharyana.my.id/<route>/ × 9 → 200.
  7. Verifikasi visual sungguhan: browser_navigate ke live URL → browser_vision: "Apakah ini masih template dashboard?" — jawaban HARUS bukan; screenshot dikirim ke user (MEDIA:<path>).
  8. Checklist anti-default dicentang satu per satu di PR/commit message akhir.

Files Likely to Change

package.json, pnpm-lock.yaml
next.config.ts                        # hanya jika perlu (tidak diharapkan)
src/app/(dashboard)/layout.tsx        # wire frame baru
src/app/(dashboard)/{9 route}/page.tsx|view.tsx   # scene migration
src/components/shell/**               # frame baru + hapus lama
src/lib/constellation/**              # baru (murni + test)
src/app/globals.css                   # tokens tambahan + reduced-motion kill list
biome.json                            # hanya jika rule intentional baru perlu "off"

Risks / Tradeoffs

Risiko Mitigasi
Perf GPU di device lemah (full-page WebGL) Node count kecil (<200/route), pause saat tab hidden, fallback radial statis utk reduced-motion; jika tetap berat → downgrade ke Canvas2D renderer dgn API sama
router.push no-op (standalone+trailingSlash) Semua nav pakai <a href>; verifikasi klik nyata di browser
Konten padat (messages 611 l) tak muat di metafora graf Prinsip: graf = struktur/navigasi; DETAIL tetap lewat overlay panel mengambang — konten tidak dikorbankan, hanya wadahnya yang berubah
Bun test + Next tsconfig konflik types Exclude *.test.ts dari tsconfig (keputusan Task 1)
Regress fitur existing (theme toggle, palette, chatbot, mini-player, WS sync) Dipertahankan apa adanya; smoke + klik verifikasi per phase; sortMessages & snapshot voice TIDAK disentuh logikanya

Open Questions

  • Tidak ada blocker. Satu preferensi opsional: apakah brand mark perlu jam/uptime seperti TopBar lama — default: tidak (minimal). Keputusan bisa diambil saat review Task 4.