deploy.sh now writes to host directories bind-mounted into containers
instead of docker exec tar-pipes (volatile). Added bind mounts to
docker-compose.yml for all 3 services (frontend, backend, gateway).
Memory: hotpatch-volatile-container.md
Deploy now pulls images pinned to $CI_COMMIT_SHA instead of :latest,
eliminating race-condition deployments where a concurrent pipeline
overwrites the mutable latest tag before deploy runs.
Changes:
- docker-compose.yml: image tags use ${IMAGE_TAG:-latest} env var
- deploy step: IMAGE_TAG=$CI_COMMIT_SHA docker compose pull + up
- scp docker-compose.yml to VPS before running deploy commands
- Replace upstream blocks with variable-based proxy_pass + Docker DNS
resolver (127.0.0.11) so nginx resolves hostnames dynamically on
each request instead of caching at startup only.
- Add explicit 'docker compose restart proxy' in CI deploy step
(belt-and-suspenders: also forces nginx restart after deploy).
- Remove no-op sed commands from CI (docker-compose.yml already uses
GitLab registry, no ghcr.io replacements needed).
Root cause: docker compose up -d only recreates containers whose image
changed. When backend container is recreated (new Docker IP), nginx
still caches the old IP → 502 Bad Gateway on /api/*
@discordjs/opus requires Python and C++ build tools for native
compilation. The discord-gateway Dockerfile already had these but
the backend Dockerfile was missing them, causing CI build failure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refactor the voice recording and playback systems to improve efficiency, reduce latency, and enhance Docker build performance.
- **Infrastructure**: Optimize Dockerfiles using build mounts for pnpm cache and reorder layers for better caching of dependencies and build tools.
- **Backend/Gateway**:
- Refactor `broadcast` module to use a generic event-based system instead of hardcoded functions.
- Simplify voice recording logic by merging metadata and segment management into a unified `segment.ts`.
- Optimize audio downsampling in `streamSetup.ts` using `Int16Array` views for better performance.
- Implement `withFallback` utility for more robust Redis/Database command execution.
- **Frontend**:
- Optimize audio playback visualization using pre-computed level shapes and efficient RMS calculation.
- Reduce latency in voice commands by prioritizing WebSocket communication over HTTP.
- Improve base64 encoding efficiency in audio transmission.
- **General**:
- Add default value for `ADMIN_PASSWORD` in shared config.
- Fix Docker healthcheck to use `127.0.0.1` instead of `localhost`.
TypeScript compilation in the frontend Docker build fails with TS2307:
Cannot find module '@bete/shared' because the shared package's .d.ts
files in dist/ were never generated. The backend and discord-gateway
Dockerfiles already have this build step — frontend was missing it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Voice transmitter requires FFmpeg to encode PCM to OggOpus.
Previously missing from Alpine image, causing:
spawn ffmpeg ENOENT
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add recordings directory structure with .gitkeep, .gitignore, and README
- Update deployment script to set chmod 777 on recordings directory
- Fixes ENOENT/EACCES errors when discord-gateway tries to create user subdirectories
- Ensures container app user (UID 100) can write recording files
This resolves the crash on voice channel connection where the service
failed to create user-specific recording directories like:
- recordings/<user-id>/
- recordings/sessions/
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bete/shared emits dist/ artifact; imports resolve via
package.json "main"/"exports" pointing to dist/. Both
services need the shared package built before `tsc` sees it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both services import from @bete/shared but Dockerfiles were missing the
packages/shared/ copy step, causing tsc errors on build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pnpm install --frozen-lockfile fails in Docker with ENOENT when
pnpm-lock.yaml references patched dependencies (jsdoc@3.6.11.patch)
but the patches/ directory is not copied into the container.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
- 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>
- 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>
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>
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>
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>
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>
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>
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>
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>
- Extract services into services/{frontend,backend,discord-gateway}
- Create packages/shared/ for shared logger, errors, utils, types
- Setup Modular MVC pattern in backend (controller→service→repository)
- Setup event-driven architecture in discord-gateway with Redis pub/sub
- Move Docker files to infra/docker/ with per-service Dockerfiles
- Update docker-compose.yml to use Traefik-only routing (no port exposes)
- Update GitHub Actions deploy workflow for multi-service matrix build
- Fix all import paths and resolve type errors across all services
- All 3 services pass tsc --noEmit clean
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>