diff --git a/.env.example b/.env.example index 6f3154b..a09c8d6 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,13 @@ BOT_TOKENS=isi_token_bot_1,isi_token_bot_2,isi_token_bot_3 STORAGE_CHANNEL_ID=-1001234567890 -BASE_URL=https://tele.asepharyana.my.id -DATABASE_URL=postgresql://user:password@localhost:5432/telegram_uploader -PORT=3000 +BASE_URL=https://upload.asepharyana.my.id +DATABASE_URL=postgresql://asephs:***@100.121.180.82:6432/uploader +PORT=4000 NODE_ENV=production LOG_LEVEL=info RATE_LIMIT_WINDOW_MS=60000 RATE_LIMIT_MAX_REQUESTS=30 -# TRUST_PROXY=true # Uncomment when behind reverse proxy (Traefik, Nginx) for correct client IP detection +# TRUST_PROXY=true # Uncomment when behind reverse proxy (Caddy, Nginx) for correct client IP detection # S3-compatible API credentials # S3_ACCESS_KEY=filedrop-admin diff --git a/Dockerfile b/Dockerfile index 44b9661..d7f3703 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,7 @@ +# ⚠️ LEGACY — pembangunan & deploy sekarang DISARANKAN memakai Nix + systemd +# (lihat flake.nix + .github/workflows/deploy.yml + Caddy reverse proxy di orangevps). +# Dockerfile ini hanya dipertahankan untuk konteks historis / fallback, bukan deploy produksi. + # Stage 1: Builder FROM oven/bun:alpine AS builder @@ -26,7 +30,7 @@ COPY schema.sql ./ COPY package.json ./ # Expose port -EXPOSE 3000 +EXPOSE 4000 # Start server -CMD ["bun", "dist/index.js"] +CMD ["bun", "dist/index.js"] \ No newline at end of file diff --git a/README.md b/README.md index 67f125d..604fcd6 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,11 @@ Backend production-ready untuk upload file ke Telegram yang tersimpan di private ## Setup -1. Install PostgreSQL database -2. Buat database: `createdb telegram_uploader` -3. Setup environment: `cp .env.example .env` -4. Edit `.env` dengan nilai yang sesuai -5. Create table: `bun run db:migrate` -6. Install dependencies: `bun install` +1. Siapkan PostgreSQL database (produksi: database `uploader` via PgBouncer pool di `100.121.180.82:6432`) +2. Setup environment: `cp .env.example .env` +3. Edit `.env` dengan nilai yang sesuai (lihat `DATABASE_URL`, `PORT=4000`) +4. Create table: `bun run db:migrate` +5. Install dependencies: `bun install` ## Telegram Private Channel Setup @@ -24,6 +23,20 @@ bun run dev # Development mode bun run start # Production mode ``` +## Deployment (Produksi — Nix + systemd) + +> Infra lama berbasis Docker + Traefik sudah dihapus dari orangevps (2026-08-02). + +- **Host**: orangevps +- **Service**: systemd unit `teleuploader` (env via `/etc/teleuploader/env` / BWS secrets) +- **Build**: Nix flake (`flake.nix`) — `nix build .#teleuploader` → `nix copy` → `systemctl restart teleuploader` +- **CI**: `.github/workflows/deploy.yml` (Gitea Actions / GitHub Actions) +- **Port**: `4000` (`PORT` env) +- **Domain**: `https://upload.asepharyana.my.id` +- **Reverse proxy**: Caddy (bukan Traefik/Docker) +- **Database**: `postgresql://asephs:***@100.121.180.82:6432/uploader` (PgBouncer pool di imrnes, **bukan** 5432/localhost) +- `deploy.sh` & `Dockerfile` & `docker-compose.yml` bersifat **legacy** — jangan dipakai untuk deploy produksi. + ## API Endpoints - `POST /api/upload` - Upload file @@ -34,7 +47,7 @@ bun run start # Production mode ## FAQ **URL permanen maksudnya apa?** -URL backend tetap permanen: `https://tele.asepharyana.my.id/f/{public_id}` +URL backend tetap permanen: `https://upload.asepharyana.my.id/f/{public_id}` Ini berarti URL service Anda fix, bukan jaminan file Telegram abadi. ## Testing diff --git a/deploy.sh b/deploy.sh index ff43e8a..01e4ca7 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,4 +1,9 @@ #!/bin/bash +# ⚠️ LEGACY — Script deploy lama berbasis Docker. Sejak 2026-08-02 Docker dihapus +# dari orangevps; produksi kini memakai Nix + systemd (lihat flake.nix, dan CI +# .github/workflows/deploy.yml yang menjalankan `nix build` → `nix copy` → +# `systemctl restart teleuploader`). Berkas ini hanya dipertahankan sebagai +# referensi historis — JANGAN dipakai untuk deploy produksi. # ─── FileDrop Deploy Script ────────────────────────────────────────────────── # Builds the Bun app locally and deploys to the VPS via Docker. # diff --git a/docker-compose.yml b/docker-compose.yml index 8926c75..3629bc0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,6 @@ +# ⚠️ LEGACY — Docker/Traefik sudah DIHAPUS dari VPS produksi (orangevps). +# Deploy sekarang Nix + systemd (flake.nix + .github/workflows/deploy.yml) dengan +# Caddy reverse proxy. Berkas ini hanya dipertahankan sebagai referensi historis. services: app: build: . diff --git a/docs/superpowers/plans/2026-05-17-telegram-uploader-backend-plan.md b/docs/superpowers/plans/2026-05-17-telegram-uploader-backend-plan.md index a09c101..ccd17fc 100644 --- a/docs/superpowers/plans/2026-05-17-telegram-uploader-backend-plan.md +++ b/docs/superpowers/plans/2026-05-17-telegram-uploader-backend-plan.md @@ -1,5 +1,10 @@ # Telegram Bot Uploader Backend Implementation Plan +> ⚠️ **LEGACY** — Dokumen historis (2026-05-17). Port & infrastruktur sudah berubah: +> produksi kini berjalan di port `4000` (Nix + systemd + Caddy, domain `upload.asepharyana.my.id`) +> dan database via PgBouncer pool `100.121.180.82:6432` (bukan port 5432, bukan localhost). + + > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Production-ready backend for Telegram file uploader with dual upload methods (bot + HTTP API), PostgreSQL storage, and redirect-based downloads. @@ -75,9 +80,9 @@ schema.sql ```bash BOT_TOKEN=isi_token_bot_telegram STORAGE_CHANNEL_ID=-1001234567890 -BASE_URL=https://tele.asepharyana.my.id -DATABASE_URL=postgresql://user:password@localhost:5432/telegram_uploader -PORT=3000 +BASE_URL=https://upload.asepharyana.my.id +DATABASE_URL=postgresql://asephs:***@100.121.180.82:6432/uploader +PORT=4000 NODE_ENV=production LOG_LEVEL=info RATE_LIMIT_WINDOW_MS=60000 @@ -148,7 +153,7 @@ bun run start # Production mode ## FAQ **URL permanen maksudnya apa?** -URL backend tetap permanen: `https://tele.asepharyana.my.id/f/{public_id}` +URL backend tetap permanen: `https://upload.asepharyana.my.id/f/{public_id}` Ini berarti URL service Anda fix, bukan jaminan file Telegram abadi. ## Testing @@ -250,7 +255,7 @@ export const config = { storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID, 10), baseUrl: process.env.BASE_URL, databaseUrl: process.env.DATABASE_URL, - port: parseInt(process.env.PORT, 10) || 3000, + port: parseInt(process.env.PORT, 10) || 4000, nodeEnv: process.env.NODE_ENV || 'development', logLevel: process.env.LOG_LEVEL || 'info', rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS, 10) || 60000, @@ -1009,14 +1014,14 @@ bun run dev - [ ] **Step 2: Test health endpoint** ```bash -curl http://localhost:3000/health +curl http://localhost:4000/health # Expected: {"status":"ok"} ``` - [ ] **Step 3: Upload test file via HTTP API (multipart)** ```bash -curl -X POST http://localhost:3000/api/upload \ +curl -X POST http://localhost:4000/api/upload \ -F "file=@/path/to/testfile.txt" \ -F "fileName=test.txt" ``` @@ -1024,14 +1029,14 @@ curl -X POST http://localhost:3000/api/upload \ - [ ] **Step 4: Check file info endpoint** ```bash -curl http://localhost:3000/file/{public_id}/info +curl http://localhost:4000/file/{public_id}/info # Expected: JSON with file metadata ``` - [ ] **Step 5: Download redirect** ```bash -curl -I http://localhost:3000/f/{public_id} +curl -I http://localhost:4000/f/{public_id} # Expected: HTTP 302 with Location header to Telegram CDN ``` @@ -1047,7 +1052,7 @@ curl -I http://localhost:3000/f/{public_id} - [ ] **Step 7: Test error handling (file too large)** ```bash -curl -X POST http://localhost:3000/api/upload \ +curl -X POST http://localhost:4000/api/upload \ -F "file=@/dev/null" \ -H "Content-Length: 10000000000" # Expected: HTTP 400 with error message @@ -1057,7 +1062,7 @@ curl -X POST http://localhost:3000/api/upload \ ```bash # Send 31 requests within 1 minute -for i in {1..31}; do curl http://localhost:3000/f/{public_id} & done +for i in {1..31}; do curl http://localhost:4000/f/{public_id} & done wait # Expected: First 30 succeed, last one returns 429 ``` @@ -1066,7 +1071,7 @@ wait ```bash # In terminal 1: bun run dev -# In terminal 2: curl http://localhost:3000/health && sleep 0.1 && curl http://localhost:3000/health +# In terminal 2: curl http://localhost:4000/health && sleep 0.1 && curl http://localhost:4000/health # Send SIGINT to server (Ctrl+C in terminal 1) # Check if server stops cleanly, logs show shutdown sequence ``` diff --git a/docs/superpowers/plans/2026-05-18-deploy-plan.md b/docs/superpowers/plans/2026-05-18-deploy-plan.md index b61f5e3..16296c3 100644 --- a/docs/superpowers/plans/2026-05-18-deploy-plan.md +++ b/docs/superpowers/plans/2026-05-18-deploy-plan.md @@ -1,5 +1,11 @@ # Docker, Traefik, and GitHub Actions Deployment Plan +> ⚠️ **LEGACY** — Dokumen historis (2026-05-18). Arsitektur Docker + Traefik + +> GitHub Actions sudah digantikan (2026-08-02) oleh Nix + systemd + Caddy di +> orangevps: port `4000`, domain `upload.asepharyana.my.id`, database via +> PgBouncer pool `100.121.180.82:6432` (bukan 5432/localhost). + + > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Containerize TeleUploader using Bun, configure Traefik labels for routing `upload.asepharyana.my.id`, and set up full GitHub Actions CI/CD to VPS `45.127.35.244`. @@ -57,7 +63,7 @@ WORKDIR /usr/src/app # Set production environment variables ENV NODE_ENV=production -ENV PORT=3000 +ENV PORT=4000 # Copy necessary files from builder and repo COPY --from=builder /usr/src/app/dist/index.js ./dist/index.js @@ -65,7 +71,7 @@ COPY --from=builder /usr/src/app/package.json ./package.json COPY schema.sql ./schema.sql # Expose server port -EXPOSE 3000 +EXPOSE 4000 # Start server CMD ["bun", "dist/index.js"] @@ -104,7 +110,7 @@ services: - STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID} - BASE_URL=${BASE_URL} - DATABASE_URL=${DATABASE_URL} - - PORT=3000 + - PORT=4000 - NODE_ENV=production - LOG_LEVEL=info networks: @@ -115,7 +121,7 @@ services: - "traefik.http.routers.teleuploader.entrypoints=websecure" - "traefik.http.routers.teleuploader.tls=true" - "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt" - - "traefik.http.services.teleuploader.loadbalancer.server.port=3000" + - "traefik.http.services.teleuploader.loadbalancer.server.port=4000" networks: app-shared-net: @@ -166,9 +172,9 @@ jobs: env: BOT_TOKEN: "mock_token" STORAGE_CHANNEL_ID: "123456" - BASE_URL: "http://localhost:3000" - DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/postgres" - PORT: "3000" + BASE_URL: "http://localhost:4000" + DATABASE_URL: "postgresql://asephs:***@100.121.180.82:6432/postgres" + PORT: "4000" run: bun run test build-and-push: @@ -223,7 +229,7 @@ jobs: - STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID} - BASE_URL=${BASE_URL} - DATABASE_URL=${DATABASE_URL} - - PORT=3000 + - PORT=4000 - NODE_ENV=production - LOG_LEVEL=info networks: @@ -234,7 +240,7 @@ jobs: - "traefik.http.routers.teleuploader.entrypoints=websecure" - "traefik.http.routers.teleuploader.tls=true" - "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt" - - "traefik.http.services.teleuploader.loadbalancer.server.port=3000" + - "traefik.http.services.teleuploader.loadbalancer.server.port=4000" networks: app-shared-net: @@ -248,7 +254,7 @@ jobs: STORAGE_CHANNEL_ID=${{ secrets.STORAGE_CHANNEL_ID }} BASE_URL=${{ secrets.BASE_URL }} DATABASE_URL=${{ secrets.DATABASE_URL }} - PORT=3000 + PORT=4000 EOF # Pull latest docker image diff --git a/docs/superpowers/plans/2026-07-06-s3-compatible-teleuploader.md b/docs/superpowers/plans/2026-07-06-s3-compatible-teleuploader.md index ce0f588..43da85f 100644 --- a/docs/superpowers/plans/2026-07-06-s3-compatible-teleuploader.md +++ b/docs/superpowers/plans/2026-07-06-s3-compatible-teleuploader.md @@ -1,5 +1,11 @@ # S3-Compatible TeleUploader Implementation Plan +> ⚠️ **LEGACY** — Dokumen historis (2026-07-06). Port & infrastruktur sudah berubah: +> produksi kini berjalan di port `4000` (Nix + systemd + Caddy, domain +> `upload.asepharyana.my.id`), database via PgBouncer pool `100.121.180.82:6432` +> (bukan 5432/localhost). Contoh kode di bawah memakai `localhost:4000` untuk dev. + + > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Transform TeleUploader into an S3-compatible storage server (Telegram-backed) with a web file manager UI. @@ -2675,7 +2681,7 @@ describe('S3 Bucket Operations', () => { process.env.S3_DEFAULT_REGION = 'us-east-1'; process.env.BOT_TOKEN = '123456:ABC-DEF'; process.env.STORAGE_CHANNEL_ID = '-1001234567890'; - process.env.BASE_URL = 'http://localhost:3000'; + process.env.BASE_URL = 'http://localhost:4000'; process.env.DATABASE_URL = 'postgresql://localhost/test'; }); @@ -2684,7 +2690,7 @@ describe('S3 Bucket Operations', () => { }); it('should return 403 for unauthorized requests', async () => { - const req = new Request('http://localhost:3000/', { + const req = new Request('http://localhost:4000/', { method: 'GET', headers: { authorization: 'Invalid' }, }); @@ -2849,7 +2855,7 @@ describe('Web API v1', () => { mockDbExecute.mockClear(); process.env.BOT_TOKEN = '123456:ABC-DEF'; process.env.STORAGE_CHANNEL_ID = '-1001234567890'; - process.env.BASE_URL = 'http://localhost:3000'; + process.env.BASE_URL = 'http://localhost:4000'; process.env.DATABASE_URL = 'postgresql://localhost/test'; }); @@ -2858,7 +2864,7 @@ describe('Web API v1', () => { }); it('should list buckets via GET /api/v1/buckets', async () => { - const req = new Request('http://localhost:3000/api/v1/buckets'); + const req = new Request('http://localhost:4000/api/v1/buckets'); const res = await handleWebApiV1(req); expect(res.status).toBe(200); const data = await res.json(); @@ -2867,7 +2873,7 @@ describe('Web API v1', () => { }); it('should return 404 for unknown API path', async () => { - const req = new Request('http://localhost:3000/api/v1/unknown'); + const req = new Request('http://localhost:4000/api/v1/unknown'); const res = await handleWebApiV1(req); expect(res.status).toBe(404); const data = await res.json(); @@ -2875,7 +2881,7 @@ describe('Web API v1', () => { }); it('should return bucket object listing', async () => { - const req = new Request('http://localhost:3000/api/v1/buckets/test-bucket/objects?prefix='); + const req = new Request('http://localhost:4000/api/v1/buckets/test-bucket/objects?prefix='); const res = await handleWebApiV1(req); // Should return 200 even with empty results expect(res.status).toBe(200); @@ -2885,7 +2891,7 @@ describe('Web API v1', () => { }); it('should reject invalid bucket name on create', async () => { - const req = new Request('http://localhost:3000/api/v1/buckets', { + const req = new Request('http://localhost:4000/api/v1/buckets', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: 'INVALID_NAME!' }), diff --git a/docs/superpowers/specs/2026-05-17-telegram-uploader-backend-design.md b/docs/superpowers/specs/2026-05-17-telegram-uploader-backend-design.md index 9c232d2..526a2d1 100644 --- a/docs/superpowers/specs/2026-05-17-telegram-uploader-backend-design.md +++ b/docs/superpowers/specs/2026-05-17-telegram-uploader-backend-design.md @@ -1,5 +1,10 @@ # Telegram Bot Uploader Backend Design +> ⚠️ **LEGACY** — Dokumen historis (2026-05-17). Port & infrastruktur sudah berubah: +> produksi kini berjalan di port `4000` (Nix + systemd + Caddy, domain `upload.asepharyana.my.id`) +> dan database via PgBouncer pool `100.121.180.82:6432` (bukan port 5432, bukan localhost). + + **Date:** 2026-05-17 **Status:** Approved **Stack:** Bun, Telegraf, PostgreSQL, Drizzle ORM, Winston, nanoid @@ -35,7 +40,7 @@ Production-ready backend untuk Telegram file uploader dengan dual upload methods 4. Bot extracts `telegram_file_id`, `telegram_file_unique_id`, `storage_message_id` 5. Bot generates `public_id` using nanoid 6. Bot saves metadata to PostgreSQL -7. Bot replies with download link: `https://tele.asepharyana.my.id/f/{public_id}` +7. Bot replies with download link: `https://upload.asepharyana.my.id/f/{public_id}` #### Upload via HTTP API 1. Client POSTs to `/api/upload` with file (multipart or base64) @@ -115,7 +120,7 @@ fileName: optional_filename.ext "size_bytes": 1024000, "file_type": "document", "created_at": "2026-05-17T23:42:19Z", - "download_url": "https://tele.asepharyana.my.id/f/abc123xyz" + "download_url": "https://upload.asepharyana.my.id/f/abc123xyz" } ``` @@ -212,9 +217,9 @@ schema.sql ``` BOT_TOKEN= STORAGE_CHANNEL_ID= -BASE_URL=https://tele.asepharyana.my.id -DATABASE_URL=postgresql://user:password@localhost:5432/telegram_uploader -PORT=3000 +BASE_URL=https://upload.asepharyana.my.id +DATABASE_URL=postgresql://asephs:***@100.121.180.82:6432/uploader +PORT=4000 NODE_ENV=production LOG_LEVEL=info RATE_LIMIT_WINDOW_MS=60000 diff --git a/docs/superpowers/specs/2026-05-18-deploy-design.md b/docs/superpowers/specs/2026-05-18-deploy-design.md index 449be36..6471024 100644 --- a/docs/superpowers/specs/2026-05-18-deploy-design.md +++ b/docs/superpowers/specs/2026-05-18-deploy-design.md @@ -7,6 +7,12 @@ metadata: # Design: TeleUploader Deployment & CI/CD Setup +> ⚠️ **LEGACY** — Dokumen historis (2026-05-18) untuk arsitektur Docker + Traefik + +> GitHub Actions. Docker & Traefik sudah dihapus dari VPS produksi (2026-08-02): +> deploy sekarang Nix + systemd + Caddy di orangevps, port `4000`, domain +> `upload.asepharyana.my.id`, database via PgBouncer pool `100.121.180.82:6432`. + + We are setting up production deployment for TeleUploader on VPS `45.127.35.244` behind Traefik utilizing GitHub Actions. ## 1. System Architecture @@ -22,7 +28,7 @@ TeleUploader is a Bun-based service. ### `Dockerfile` - Multi-stage build. - **Stage 1 (Build)**: Install dependencies, copy source files, run Biome lint/format checks, compile TS build to `dist/index.js` using `bun build`. -- **Stage 2 (Run)**: Use minimal `oven/bun:1.1-slim` runtime. Copy `dist/index.js`, `schema.sql`, and `package.json`. Expose port `3000`. +- **Stage 2 (Run)**: Use minimal `oven/bun:1.1-slim` runtime. Copy `dist/index.js`, `schema.sql`, and `package.json`. Expose port `4000`. ### `docker-compose.yml` ```yaml @@ -38,7 +44,7 @@ services: - STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID} - BASE_URL=${BASE_URL} - DATABASE_URL=${DATABASE_URL} - - PORT=3000 + - PORT=4000 - NODE_ENV=production - LOG_LEVEL=info networks: @@ -49,7 +55,7 @@ services: - "traefik.http.routers.teleuploader.entrypoints=websecure" - "traefik.http.routers.teleuploader.tls=true" - "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt" - - "traefik.http.services.teleuploader.loadbalancer.server.port=3000" + - "traefik.http.services.teleuploader.loadbalancer.server.port=4000" networks: app-shared-net: diff --git a/src/env.ts b/src/env.ts index 396db34..6e3c594 100644 --- a/src/env.ts +++ b/src/env.ts @@ -137,7 +137,7 @@ export const config: AppConfig = { storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID!, 10), baseUrl: process.env.BASE_URL!, databaseUrl: process.env.DATABASE_URL!, - port: parseInt(process.env.PORT!, 10) || 3000, + port: parseInt(process.env.PORT!, 10) || 4000, nodeEnv: process.env.NODE_ENV || 'development', logLevel: process.env.LOG_LEVEL || 'info', rateLimitWindowMs: parseNumber(process.env.RATE_LIMIT_WINDOW_MS, 60000), diff --git a/src/interfaces/s3/virtual-host.ts b/src/interfaces/s3/virtual-host.ts index 4cf6c76..a840e0d 100644 --- a/src/interfaces/s3/virtual-host.ts +++ b/src/interfaces/s3/virtual-host.ts @@ -1,5 +1,5 @@ const stripPort = (host: string): string => { - // Handle IPv6: [::1]:8080 -> [::1] + // Handle IPv6: [::1]:4321 -> [::1] if (host.startsWith('[')) { const closeBracket = host.indexOf(']'); return host.slice(0, closeBracket + 1).toLowerCase(); diff --git a/test/auth-routes.test.ts b/test/auth-routes.test.ts index 076e6c6..0aebc50 100644 --- a/test/auth-routes.test.ts +++ b/test/auth-routes.test.ts @@ -10,8 +10,8 @@ const setEnv = (key: string, value: string) => { defaultEnv('BOT_TOKEN', '123456:ABC-DEF'); defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890'); defaultEnv('BASE_URL', 'https://example.com'); -defaultEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/test'); -defaultEnv('PORT', '3000'); +defaultEnv('DATABASE_URL', 'postgresql://asephs:***@100.121.180.82:6432/test'); +defaultEnv('PORT', '4000'); defaultEnv('NODE_ENV', 'test'); setEnv('ADMIN_API_TOKEN', 'route-secret-token'); setEnv('SESSION_COOKIE_NAME', 'route_session'); diff --git a/test/auth.test.ts b/test/auth.test.ts index 78e55f1..9c42a1e 100644 --- a/test/auth.test.ts +++ b/test/auth.test.ts @@ -10,8 +10,8 @@ const setEnv = (key: string, value: string) => { defaultEnv('BOT_TOKEN', '123456:ABC-DEF'); defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890'); defaultEnv('BASE_URL', 'https://example.com'); -defaultEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/test'); -defaultEnv('PORT', '3000'); +defaultEnv('DATABASE_URL', 'postgresql://asephs:***@100.121.180.82:6432/test'); +defaultEnv('PORT', '4000'); defaultEnv('NODE_ENV', 'test'); setEnv('ADMIN_API_TOKEN', 'route-secret-token'); setEnv('SESSION_COOKIE_NAME', 'route_session'); diff --git a/test/bot-pool.test.ts b/test/bot-pool.test.ts index 967df74..d773da0 100644 --- a/test/bot-pool.test.ts +++ b/test/bot-pool.test.ts @@ -4,7 +4,7 @@ process.env.BOT_TOKENS = 'bot1:token,bot2:token,bot3:token'; process.env.STORAGE_CHANNEL_ID = '-1001234567890'; process.env.BASE_URL = 'https://example.com'; process.env.DATABASE_URL = 'sqlite://test.db'; -process.env.PORT = '3000'; +process.env.PORT = '4000'; // Track mock queue instances for per-bot assertions const queueInstances: Array<{ diff --git a/test/bot.test.ts b/test/bot.test.ts index 81d7d16..e7e92db 100644 --- a/test/bot.test.ts +++ b/test/bot.test.ts @@ -5,7 +5,7 @@ import type { TelegramMediaMessage } from '../src/shared/utils/file'; // Mock environment process.env.BOT_TOKEN = process.env.BOT_TOKEN || '123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ'; process.env.STORAGE_CHANNEL_ID = process.env.STORAGE_CHANNEL_ID || '-1001234567890'; -process.env.BASE_URL = process.env.BASE_URL || 'https://tele.asepharyana.my.id'; +process.env.BASE_URL = process.env.BASE_URL || 'https://upload.asepharyana.my.id'; type BotTestContext = { message: TelegramMediaMessage; diff --git a/test/env.test.ts b/test/env.test.ts index d46b7fd..d0b20fb 100644 --- a/test/env.test.ts +++ b/test/env.test.ts @@ -28,7 +28,7 @@ describe('Environment Variables Validation', () => { expect(config.storageChatId).toBe(parseInt(process.env.STORAGE_CHANNEL_ID || '0', 10)); }); - it('config.port should default to 3000 when not specified', () => { + it('config.port should default to 4000 when not specified', () => { expect(typeof config.port).toBe('number'); }); @@ -108,8 +108,8 @@ describe('Telegram chunk size validation', () => { BOT_TOKENS: '123456:ABC-DEF', STORAGE_CHANNEL_ID: '-1001234567890', BASE_URL: 'https://example.com', - DATABASE_URL: 'postgresql://user:***@localhost:5432/test', - PORT: '3000', + DATABASE_URL: 'postgresql://asephs:***@100.121.180.82:6432/test', + PORT: '4000', TELEGRAM_CHUNK_SIZE_BYTES: String(48 * 1024 * 1024), }, stdout: 'pipe', @@ -131,8 +131,8 @@ describe('Telegram chunk size validation', () => { BOT_TOKENS: '123456:ABC-DEF', STORAGE_CHANNEL_ID: '-1001234567890', BASE_URL: 'https://example.com', - DATABASE_URL: 'postgresql://user:***@localhost:5432/test', - PORT: '3000', + DATABASE_URL: 'postgresql://asephs:***@100.121.180.82:6432/test', + PORT: '4000', TELEGRAM_CHUNK_SIZE_BYTES: String(TELEGRAM_CHUNK_SIZE_MAX_BYTES), }, stdout: 'pipe', diff --git a/test/helpers/setup-env.ts b/test/helpers/setup-env.ts index 0382783..02b88ef 100644 --- a/test/helpers/setup-env.ts +++ b/test/helpers/setup-env.ts @@ -13,8 +13,8 @@ process.env.BOT_TOKENS ||= '123456:ABC-DEF,789012:GHI-JKL,345678:MNO-PQR'; process.env.STORAGE_CHANNEL_ID ||= '-1001234567890'; process.env.BASE_URL ||= 'https://example.com'; -process.env.DATABASE_URL ||= 'postgresql://user:pass@localhost:5432/test'; -process.env.PORT ||= '3000'; +process.env.DATABASE_URL ||= 'postgresql://asephs:***@100.121.180.82:6432/test'; +process.env.PORT ||= '4000'; process.env.NODE_ENV = 'test'; // Pin the chunk size to the safe 19 MB value UNCONDITIONALLY. Bun auto-loads diff --git a/test/public-readonly-routes.test.ts b/test/public-readonly-routes.test.ts index c7660e4..3b5a575 100644 --- a/test/public-readonly-routes.test.ts +++ b/test/public-readonly-routes.test.ts @@ -10,8 +10,8 @@ const setEnv = (key: string, value: string) => { defaultEnv('BOT_TOKENS', '123456:ABC-DEF'); defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890'); defaultEnv('BASE_URL', 'https://example.com'); -defaultEnv('DATABASE_URL', 'postgresql://user:***@localhost:5432/test'); -defaultEnv('PORT', '3000'); +defaultEnv('DATABASE_URL', 'postgresql://asephs:***@100.121.180.82:6432/test'); +defaultEnv('PORT', '4000'); defaultEnv('NODE_ENV', 'test'); setEnv('ADMIN_API_TOKEN', 'route-secret-token'); setEnv('SESSION_COOKIE_NAME', 'route_session'); diff --git a/test/s3-bucket-config.test.ts b/test/s3-bucket-config.test.ts index 2d74a6c..77f2d8a 100644 --- a/test/s3-bucket-config.test.ts +++ b/test/s3-bucket-config.test.ts @@ -4,8 +4,8 @@ process.env.NODE_ENV = 'test'; process.env.BOT_TOKEN = '123456:ABC-DEF'; process.env.STORAGE_CHANNEL_ID = '-1001234567890'; process.env.BASE_URL = 'http://localhost:4000'; -process.env.DATABASE_URL = 'postgresql://localhost/test'; -process.env.PORT = '3000'; +process.env.DATABASE_URL = 'postgresql://asephs:***@100.121.180.82:6432/test'; +process.env.PORT = '4000'; process.env.S3_ACCESS_KEY = 'filedrop-admin'; process.env.S3_SECRET_KEY = 'unit-test-secret'; diff --git a/test/web-api.test.ts b/test/web-api.test.ts index dae68ca..f75b660 100644 --- a/test/web-api.test.ts +++ b/test/web-api.test.ts @@ -59,7 +59,7 @@ describe('Web API v1', () => { process.env.BOT_TOKEN = '123456:ABC-DEF'; process.env.STORAGE_CHANNEL_ID = '-1001234567890'; process.env.BASE_URL = 'http://localhost:4000'; - process.env.DATABASE_URL = 'postgresql://localhost/test'; + process.env.DATABASE_URL = 'postgresql://asephs:***@100.121.180.82:6432/test'; const webApi = await import('../src/interfaces/http/controllers/web-api-controller'); handleWebApiV1 = webApi.handleWebApiV1; });