Commit Graph
452 Commits
Author SHA1 Message Date
MythEclipse b23ccf0837 chore: session auto-commit 2026-06-02 17:12:42 +07:00
MythEclipse 498ab73d62 chore: auto-commit task - 2026-06-02 17:08:42 +07:00
MythEclipse 406a6cbf79 refactor: migrate sticker cache to PostgreSQL, remove versioning
- Replace file-based sticker cache (.dat + index.json) with PostgreSQL sticker_cache table
- Remove model_version column and all versioning logic (git branch detection, GitHub API, CACHE_MODEL_VERSION)
- Strip VISION_MODEL_VERSION, logCacheEvent calls, and version filtering from SQL queries
- Remove STICKER_CACHE_DIR and STICKER_CACHE_MAX_SIZE_MB config variables
- Delete dead migration add_model_version_to_cache.sql

textCacheStore.ts reduced 482→204 lines (-57%)
stickerCache.ts reduced 210→144 lines (-31%)
Total: 11 files changed, 233 insertions, 591 deletions
2026-06-02 14:05:51 +07:00
MythEclipseandClaude Opus 4.8 e584a7941e fix(text-cache): apply model version migration on existing dbs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 13:05:05 +07:00
MythEclipseandClaude Opus 4.8 e5673c2bbd feat(text-cache): resolve cache version from real GitHub API, no static env or dummy
- Add fetchRemoteBranchFromGitHub() to query https://api.github.com/repos/MythEclipse/bete for actual default_branch
- Add resolveBranch() tiered resolver: git CLI → GitHub API → env → error
- Async post-startup branch resolution upgrades version from emergency fallback to real remote branch
- normalizeBranchName() for consistent version key formatting
- Emergency fallback 'v1' logged as ERROR with repo context — not a silent dummy
- Removed static env-first approach; env is now tier 3 override, not tier 1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 12:52:56 +07:00
MythEclipseandClaude Opus 4.8 682fb31deb fix(text-cache): add missing model_version column to migration + strict git detection
- Create new migration 0001_add_model_version_to_cache.sql to add model_version column to text_analysis_cache table (default 'v1')
- Add composite index on source + model_version for efficient cache lookups
- Improve git branch detection in textCacheStore.ts:
  * Check CACHE_MODEL_VERSION env var first (required in Docker)
  * Suppress stderr with stdio pipes to eliminate spurious warnings
  * Log ERROR (not warning) when git unavailable AND no env var set
  * Only fall back to 'v1' as last resort, preventing silent dummy usage
- Remove unused imports (logModelVersionChange, logCacheInvalidation) and previousVersion variable
- Fixes repeated 'column model_version does not exist' errors on bot startup

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 12:46:37 +07:00
MythEclipse 505c30f124 chore(discord-gateway): remove unused imports from response logger
- aiAnalyzer.ts: removed unused logAnalysisSummary and logFalsePositiveDetected
- llmModerationClient.ts: removed unused logVisionAnalysis, logVisionError, logRetryAttempt

These functions are not called in the codebase.
2026-06-02 12:36:05 +07:00
MythEclipse 1acd452a2c fix(discord-gateway): resolve type errors in error logging - cast unknown error types to Error | string for logModerationError calls
- aiAnalyzer.ts: cast error to Error | string in individual fallback phase
- llmModerationClient.ts: cast parseError to Error | string in parse response phase

Fixes GitHub Actions build failure (exit code 2)
2026-06-02 12:30:59 +07:00
Asep Haryana SaputraandGitHub e4302c22b4 feat: add response logger for moderation/vision audit trail + cache model versioning
feat: add response logger for moderation/vision audit trail + cache model versioning
2026-06-02 12:25:12 +07:00
MythEclipse 385fc0bbbf feat: add response logger for moderation/vision audit trail + cache model versioning
- Add responseLogger.ts with comprehensive logging: vision analysis, moderation
  analysis batches, cache hit/miss events, errors, retries, false positives,
  model version changes, cache invalidation
- Integrate responseLogger calls into llmModerationClient.ts (cache events,
  moderation results, errors, retries)
- Add model_version column to text_analysis_cache schema with composite
  index for efficient filtering
- Add migration SQL for model_version column
- Document CACHE_MODEL_VERSION in .env.example
2026-06-02 12:23:52 +07:00
Asep Haryana SaputraandGitHub f4db42e11c Merge pull request #8 from MythEclipse/feat/ux-improvements-messages-analysis
feat: comprehensive UX improvements — messages, analysis, moderation
2026-06-02 12:19:20 +07:00
MythEclipseandClaude Opus 4.8 c5c667b147 feat: comprehensive UX improvements — messages, analysis, moderation
Fix #1 (CRITICAL): Wire message_analyzed through Redis EventBroadcaster
- DG aiAnalyzer.ts: Add broadcastAnalysisCompleted() helper that publishes
  to both in-memory WS broadcaster AND Redis EventBroadcaster
- DG bootstrap.ts: Pass eventBroadcaster to startPendingAIAnalysisWorker()
- Fixes broken real-time chain so analysis results appear instantly

Fix #2: Collapsible AI Analysis with Rich Formatting
- MessageCard: AI analysis now collapsible with color-coded severity border
  (red/yellow/blue), summary line showing categories + confidence + severity
- Default collapsed for clean, expanded for warn/flagged

Fix #3: Toast Notifications for Flagged Content
- Wrap app in ToastProvider; ModerationAlertListener component listens for
  moderation_alert custom events and shows toast with emoji + details

Fix #4: Discord-style Message Grouping
- MessageFeed: Group consecutive messages from same user within 5 min
- MessageCard: Compact variant hides avatar, reduces padding for non-first

Fix #5: Moderation Action Buttons in UI
- BE: POST /api/messages/:id/moderate endpoint + publishCommand() for Redis
- FE: Delete/Warn buttons on flagged/warned cards with confirmation dialog

Fix #6: Search Results Include Full Data
- BE analysis.service.ts: SELECT all 26 message columns instead of just 11
- Search results now render with full MessageCard including images/analysis

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 12:17:51 +07:00
MythEclipseandClaude Opus 4.8 74400376a0 fix: vision analysis retry + fallback jelas saat gagal
Vision API call sekarang pakai retryWithBackoff (2 retries instant).
Fallback message tegas: 'GAGAL DIANALISIS — JANGAN mengasumsikan aman'.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:41:18 +07:00
MythEclipseandClaude Opus 4.8 64643bb066 perf: hapus semua cooldown/backoff delay — retry tanpa bottleneck
Semua retry sekarang instant (retries=0, minTimeout=0, maxTimeout=0):
- retry.ts (kedua) — default minTimeout/maxTimeout 0, factor 1
- config.ts (kedua) — DECODER_COOLDOWN_MS=0, AI_ANALYSIS_ERROR_COOLDOWN_MS=0
- llmModerationClient.ts (kedua) — retries 0 tanpa delay
- aiAnalyzer.ts (kedua) — retries 0, AI_ANALYSIS_ERROR_COOLDOWN jadi 0
- indonesianTextNormalizer.ts (kedua) — semua rate limit cooldown 0
- recorder.ts (kedua), teleUpload (3 files), uploader (2 files) — retry instant
- attachmentUploader (kedua) — retries 0
- syncRoutes.ts — BACKLOG_SYNC_COOLDOWN 0

20 files changed. Semua cooldown bottleneck dihapus.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:29:52 +07:00
MythEclipseandClaude Opus 4.8 62d7d19b53 fix: analysis output wajib deskriptif — bukan generic placeholder
Sebelumnya: 'Pesan hanya berisi attachment tanpa teks yang melanggar'
Sekarang: harus deskriptif berdasarkan tipe konten:
- Text only: '[user] membahas tentang <topik>. <konteks>.'
- Image only: 'Gambar berupa <jenis>. Terlihat <isi>.'
- Text+Image: '[user] mengirim <gambar> sambil membahas <topik>.'

Tambahkan contoh baik vs buruk di OUTPUT_INSTRUCTIONS sebagai format wajib.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:24:21 +07:00
MythEclipseandClaude Opus 4.8 a69de85564 fix: prompt dua mode — gambar+teks vs gambar saja
Sebelumnya aturan 'percaya teks terlebih dahulu' membuat model abaikan
deskripsi gambar saat teks kosong. Semua image-only message di-clean.

Fix:
- SYSTEM_RULES: pisah Mode 1 (teks+gambar) dan Mode 2 (hanya gambar)
- Mode 2: deskripsi gambar jadi bukti utama, WAJIB dibaca
- Gambar terminal/chat/editor kode/casual → clean
- Gambar dengan elemen judi NYATA (chip, roulette, odds) → flag
- 2 contoh few-shot baru: terminal clean, situs judi flag

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:15:53 +07:00
MythEclipseandClaude Opus 4.8 55ee8ade16 fix: vision model hanya deskripsi, tidak memutuskan moderasi
Root cause: vision model diminta untuk 'flag' dan 'menilai' gambar,
sehingga screenshot terminal/chat biasa diklaim sebagai 'situs perjudian'.

Fix:
- vision prompt: HANYA deskripsi objektif (objek, teks, layout, jenis gambar)
- larang tegas kata 'gambling', 'judi', 'pelanggaran', 'harus dihapus'
- tambah buildGeneralImageVisionPrompt di discord-gateway stickerPrompt
- MEDIA_INSTRUCTIONS: tegaskan batch LLM adalah hakim, vision hanya saksi mata
- deskripsi netral (terminal, chat, editor kode) tidak boleh jadi dasar flag

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:08:41 +07:00
MythEclipseandClaude Opus 4.8 5f419a6f0f feat: real guild/channel names from Discord + remove selectors in Messages/Analytics
- discord-gateway: add redis command handlers for guilds:list, guilds:text-channels, voice:channels
- backend: replace postgres synthetic names with redis commands to gateway (with fallback)
- frontend: remove guild/channel dropdowns from messages and analytics tabs
- frontend: auto-load all channels from monitor guild via guildId query param
- frontend: show guild name in messages/analytics headers instead of selector
- live tab: keeps guild/channel selectors with real discord names

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:02:54 +07:00
MythEclipseandClaude Opus 4.8 f1ddca5eee fix: false positive gambling detection + route collision + WS events (#1)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:44:27 +07:00
MythEclipseandClaude Opus 4.8 34719d3366 fix(ci): force remove stale containers before up to avoid name conflict
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:09:04 +07:00
MythEclipseandClaude Opus 4.8 1a794f35fb fix(ci): write .env and recordings to infra/docker/ relative to compose
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:00:40 +07:00
MythEclipseandClaude Opus 4.8 5fdf951435 fix(ci): proper git clone/pull pattern like ZeaVis-Edu
- Check if origin mismatch → rm and re-clone fresh
- Public repo — no auth needed for clone
- docker-compose.yml from repo source of truth

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:54:57 +07:00
MythEclipseandClaude Opus 4.8 e142bd5ad2 fix(ci): drop git clone, generate docker-compose inline instead
GITHUB_TOKEN can't auth git over HTTPS on VPS, so revert to inline
compose generation. nginx.conf already baked into proxy image.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:50:28 +07:00
MythEclipseandClaude Opus 4.8 53d16dc9cd fix(ci): use x-access-token for git clone/pull on private repo
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:47:30 +07:00
MythEclipseandClaude Opus 4.8 3d62477a68 fix(ci): update git remote URL before fetch on VPS
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:45:10 +07:00
MythEclipseandClaude Opus 4.8 5ae6b73c1f fix(ci): update repo URL to new location MythEclipse/GMW
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:42:14 +07:00
MythEclipseandClaude Opus 4.8 73efc716a5 fix(ci): use git-pull pattern like ZeaVis-Edu, all images from GHCR
- Replace build: blocks with image: from ghcr.io
- Simplify deploy: git clone/pull on VPS, then docker compose pull/up
- Remove SCP step entirely — nginx.conf baked into proxy image
- Rename containers to imphenbot-* to match existing VPS setup
- Fix backend port to 3000 for production

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:41:38 +07:00
MythEclipseandClaude Opus 4.8 8c4b32f5e1 fix(ci): correct nginx conf path in Dockerfile.proxy
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:26:47 +07:00
MythEclipseandClaude Opus 4.8 6010319486 fix(ci): rename Dockerfile.nginx to Dockerfile.proxy to match workflow matrix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:09:52 +07:00
MythEclipseandClaude Opus 4.8 bf0d0090c9 fix(ci): use SCP to copy docker-compose and nginx from repo instead of hardcoded cat
- Add proxy to build matrix
- Replace heredoc docker-compose generation with appleboy/scp-action
- Fix nginx upstream backend port to 3000 (matches prod WEBSERVER_PORT)
- Copy docker-compose.yml and nginx.conf from repo via SCP staging

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:03:13 +07:00
MythEclipseandClaude Opus 4.8 cbe63809dd fix(infra): use ^~ prefix location for /api and /ws to match without trailing slash
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:51:57 +07:00
MythEclipseandClaude Opus 4.8 2b8d1ac703 feat(infra): replace traefik path routing with nginx reverse proxy
- Add nginx service with /api, /ws, and / location routing
- Move traefik labels to proxy service only (port 80)
- Remove traefik labels from backend and frontend services
- Backend routes to :3001 via nginx upstream
- WebSocket upgrade enabled for /ws path

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:36:34 +07:00
MythEclipseandClaude Opus 4.8 3b2709455e feat: implement all real backend endpoints, Redis pub/sub bridge, and gateway command handler
Backend (real implementations, no more stubs):
- Redis pub/sub bridge: subscribes to discord-gateway events (message/attachment/voice) and broadcasts to WS clients
- Redis command channel: backend publishes voice/media commands, discord-gateway executes and replies
- Voice service: connectVoice/disconnectVoice/getVoiceStatus via Redis commands with graceful fallback
- Media service: queue/skip/stop/volume via Redis commands, reads status from Redis cache
- Messages repository: ALL 7 methods now use real PostgreSQL queries (findMany, findById, findByChannel, create, update, delete, getAttachmentsByChannel)
- Analytics: period returns {start,end} epoch millis, overview includes hourly/topics/top_users, worst_flags as string[]
- Health check: actually queries SELECT 1 against database
- VoiceStatus type fixed: {connected, activeGuildId, activeChannelId, activeChannelName}
- Guild type: includes icon: string | null
- asyncHandler: accepts Promise<unknown> instead of Promise<void>

Discord Gateway:
- CommandHandler: subscribes to 'backend:command' Redis channel, executes voice/media commands, publishes replies
- Publishes voice:status and media:status to Redis for backend caching
- Shutdown handler updated to close command handler

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:32:38 +07:00
MythEclipseandClaude Opus 4.8 9b41eb9c12 feat(backend): implement all missing endpoints, real analytics queries, and WebSocket server
- Replace stub analytics.repository.ts with real PostgreSQL queries using pg.Pool
- Add /api/guilds, /api/config, /api/auth/login, /api/ui-state (GET/POST)
- Add /api/review, /api/recordings, /api/analysis/search
- Add /api/messages/:id/reanalyze endpoint
- Add /api/analytics/heatmap and /api/analytics/topics
- Implement media routes (stub responses, backend has no Discord voice client)
- Add WebSocket server at /ws with heartbeat and broadcast functions
- Fix analytics route paths to match frontend contract (dual paths for backward compat)
- Export getPool() from database module for raw SQL queries
- Register all new routers in app.ts

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 00:11:29 +07:00
MythEclipseandClaude Opus 4.8 5a094c926a fix(frontend): pass VITE_BE_API_URL and VITE_BE_WS_URL as Docker build args
Vite embeds env vars at build time, not runtime. The frontend code uses
VITE_BE_API_URL/VITE_BE_WS_URL but the workflow was setting wrong names
(VITE_API_URL/VITE_WS_URL). Now Dockerfile accepts build args and
workflow passes production URLs during docker build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 23:31:20 +07:00
MythEclipseandClaude Opus 4.6 ccd3ccd556 fix(frontend): add vite preview allowedHosts and port config
Vite preview blocks unknown hosts by default. Added allowedHosts for
imphnen.asepharyana.my.id and set port/host in preview config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 23:22:14 +07:00
MythEclipseandClaude Opus 4.6 0f6cdff8ee fix(frontend): set preview port to 3000 to match traefik loadbalancer
Vite preview defaults to port 4173 but traefik routes to port 3000.
Added --port 3000 to the preview script in package.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 23:11:47 +07:00
MythEclipseandClaude Opus 4.6 58afa98132 fix(discord-gateway): skip migration if schema tables already exist
Instead of failing on CREATE TABLE when tables already exist, check
information_schema for all 10 schema tables. If all exist, skip
migration gracefully. This handles deployments where DB was created
by a previous deployment with different migration files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 23:09:04 +07:00
MythEclipseandClaude Opus 4.6 02564e1302 fix(ci): remove --force-recreate from docker compose up
'up --force-recreate' after 'down' causes 'No such container' race.
After down, up creates fresh containers automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 23:00:10 +07:00
MythEclipseandClaude Opus 4.6 5e3c2dddb9 fix(discord-gateway): add missing dependencies (axios, ws, @types/pg, @types/ws)
After removing root package deps, discord-gateway service was missing:
- axios (used in indonesianTextNormalizer.ts)
- ws (used in broadcaster.ts)
- @types/pg (needed for TypeScript pg declarations)
- @types/ws (needed for ws types)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:55:30 +07:00
MythEclipseandClaude Opus 4.6 e2c1197caf fix(discord-gateway): generate Drizzle migrations and copy to Docker image
Container crashed with 'Can't find meta/_journal.json file' because
Drizzle ORM migration files were never generated. Generated migrations
for all 10 schema tables and updated Dockerfile to copy drizzle/ to
/app/drizzle/ where the migrator expects them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:52:03 +07:00
MythEclipse baa652ffeb chore: regenerate pnpm-lock.yaml after removing root package dependencies 2026-06-01 22:49:25 +07:00
MythEclipseandClaude Opus 4.6 3afa6298e3 refactor(monorepo): remove root package deps, simplify Dockerfiles
Root package.json no longer a workspace member — no src/, no 38 shared
dependencies. Root is now workspace config with dev tooling only (biome,
drizzle-kit, tsx, typescript).

This means Dockerfiles only need:
- pnpm-workspace.yaml + pnpm-lock.yaml + package.json (workspace config)
- The specific service being built
- Only vendor/ packages that service actually depends on (discord-gateway → discord.js-selfbot-v13)

Before: each Dockerfile copied src/, vendor/*, packages/*, all services/
After: each Dockerfile copies only its service + needed vendor deps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:47:47 +07:00
MythEclipseandClaude Opus 4.6 a9fa22262e fix(docker): correct CMD paths for service builds
- backend: node services/backend/dist/index.js (not dist/index.js)
- discord-gateway: node services/discord-gateway/dist/index.js
- frontend: pnpm --filter preview instead of root dev:web (missing frontend/ dir)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:42:45 +07:00
MythEclipseandClaude Opus 4.6 bf5849f235 fix(ci): add docker compose down before up to resolve container name conflict
The VPS has orphan containers from previous deployments that conflict with
new compose up. Running compose down --remove-orphans first cleans them up.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:19:08 +07:00
MythEclipseandClaude Opus 4.8 31c4a077d2 fix(docker): remove non-existent frontend/ and public/ COPY from frontend Dockerfile
These directories don't exist at root level; frontend assets are in services/frontend/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 22:11:40 +07:00
MythEclipseandClaude Opus 4.6 30b03c68b1 fix(docker): copy all workspace packages and root src to Dockerfiles
pnpm install --frozen-lockfile at workspace root requires ALL workspace
members to be present. Previously vendor/ packages and root src/ were
missing, causing TS2307 'Cannot find module' errors during build.

- Copy vendor/ (discord.js-selfbot-v13, discord-video-stream, better-sqlite3, drizzle-orm)
- Copy root src/ and vite.backend.config.ts
- Copy all services/ to each Dockerfile
- Copy frontend/ and public/ assets to frontend Dockerfile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:09:51 +07:00
MythEclipseandClaude Opus 4.6 e6668ffe51 fix(docker): use pnpm --filter to build each service in Dockerfiles
Root scripts point to old paths (src/, frontend/) that don't exist in the
services/ monorepo layout. Use pnpm --filter to invoke each service's
own build script (tsc) instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:05:00 +07:00
MythEclipseandClaude Opus 4.6 37ab92e7ea fix(docker): upgrade all Dockerfiles to node:22-alpine for pnpm v10 compatibility
pnpm v10+ requires the built-in `node:sqlite` module which is only available
in Node 22+. All services now use node:22-alpine.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 22:01:35 +07:00
MythEclipseandClaude Opus 4.6 ee540d11f6 fix(ci): lowercase GHCR owner name to fix 'repository name must be lowercase' error
`github.repository_owner` returns 'MythEclipse' (mixed case) which GHCR rejects.
Hardcode lowercase 'mytheclipse' to match GHCR requirements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-01 21:59:06 +07:00