chore: sync port references and docs to 4000s infra
This commit is contained in:
+4
-4
@@ -1,13 +1,13 @@
|
|||||||
BOT_TOKENS=isi_token_bot_1,isi_token_bot_2,isi_token_bot_3
|
BOT_TOKENS=isi_token_bot_1,isi_token_bot_2,isi_token_bot_3
|
||||||
STORAGE_CHANNEL_ID=-1001234567890
|
STORAGE_CHANNEL_ID=-1001234567890
|
||||||
BASE_URL=https://tele.asepharyana.my.id
|
BASE_URL=https://upload.asepharyana.my.id
|
||||||
DATABASE_URL=postgresql://user:password@localhost:5432/telegram_uploader
|
DATABASE_URL=postgresql://asephs:***@100.121.180.82:6432/uploader
|
||||||
PORT=3000
|
PORT=4000
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
RATE_LIMIT_WINDOW_MS=60000
|
RATE_LIMIT_WINDOW_MS=60000
|
||||||
RATE_LIMIT_MAX_REQUESTS=30
|
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-compatible API credentials
|
||||||
# S3_ACCESS_KEY=filedrop-admin
|
# S3_ACCESS_KEY=filedrop-admin
|
||||||
|
|||||||
+6
-2
@@ -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
|
# Stage 1: Builder
|
||||||
FROM oven/bun:alpine AS builder
|
FROM oven/bun:alpine AS builder
|
||||||
|
|
||||||
@@ -26,7 +30,7 @@ COPY schema.sql ./
|
|||||||
COPY package.json ./
|
COPY package.json ./
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
EXPOSE 3000
|
EXPOSE 4000
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
CMD ["bun", "dist/index.js"]
|
CMD ["bun", "dist/index.js"]
|
||||||
@@ -4,12 +4,11 @@ Backend production-ready untuk upload file ke Telegram yang tersimpan di private
|
|||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. Install PostgreSQL database
|
1. Siapkan PostgreSQL database (produksi: database `uploader` via PgBouncer pool di `100.121.180.82:6432`)
|
||||||
2. Buat database: `createdb telegram_uploader`
|
2. Setup environment: `cp .env.example .env`
|
||||||
3. Setup environment: `cp .env.example .env`
|
3. Edit `.env` dengan nilai yang sesuai (lihat `DATABASE_URL`, `PORT=4000`)
|
||||||
4. Edit `.env` dengan nilai yang sesuai
|
4. Create table: `bun run db:migrate`
|
||||||
5. Create table: `bun run db:migrate`
|
5. Install dependencies: `bun install`
|
||||||
6. Install dependencies: `bun install`
|
|
||||||
|
|
||||||
## Telegram Private Channel Setup
|
## Telegram Private Channel Setup
|
||||||
|
|
||||||
@@ -24,6 +23,20 @@ bun run dev # Development mode
|
|||||||
bun run start # Production 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
|
## API Endpoints
|
||||||
|
|
||||||
- `POST /api/upload` - Upload file
|
- `POST /api/upload` - Upload file
|
||||||
@@ -34,7 +47,7 @@ bun run start # Production mode
|
|||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
**URL permanen maksudnya apa?**
|
**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.
|
Ini berarti URL service Anda fix, bukan jaminan file Telegram abadi.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/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 ──────────────────────────────────────────────────
|
# ─── FileDrop Deploy Script ──────────────────────────────────────────────────
|
||||||
# Builds the Bun app locally and deploys to the VPS via Docker.
|
# Builds the Bun app locally and deploys to the VPS via Docker.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -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:
|
services:
|
||||||
app:
|
app:
|
||||||
build: .
|
build: .
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# Telegram Bot Uploader Backend Implementation Plan
|
# 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.
|
> **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.
|
**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
|
```bash
|
||||||
BOT_TOKEN=isi_token_bot_telegram
|
BOT_TOKEN=isi_token_bot_telegram
|
||||||
STORAGE_CHANNEL_ID=-1001234567890
|
STORAGE_CHANNEL_ID=-1001234567890
|
||||||
BASE_URL=https://tele.asepharyana.my.id
|
BASE_URL=https://upload.asepharyana.my.id
|
||||||
DATABASE_URL=postgresql://user:password@localhost:5432/telegram_uploader
|
DATABASE_URL=postgresql://asephs:***@100.121.180.82:6432/uploader
|
||||||
PORT=3000
|
PORT=4000
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
RATE_LIMIT_WINDOW_MS=60000
|
RATE_LIMIT_WINDOW_MS=60000
|
||||||
@@ -148,7 +153,7 @@ bun run start # Production mode
|
|||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
**URL permanen maksudnya apa?**
|
**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.
|
Ini berarti URL service Anda fix, bukan jaminan file Telegram abadi.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
@@ -250,7 +255,7 @@ export const config = {
|
|||||||
storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID, 10),
|
storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID, 10),
|
||||||
baseUrl: process.env.BASE_URL,
|
baseUrl: process.env.BASE_URL,
|
||||||
databaseUrl: process.env.DATABASE_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',
|
nodeEnv: process.env.NODE_ENV || 'development',
|
||||||
logLevel: process.env.LOG_LEVEL || 'info',
|
logLevel: process.env.LOG_LEVEL || 'info',
|
||||||
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS, 10) || 60000,
|
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS, 10) || 60000,
|
||||||
@@ -1009,14 +1014,14 @@ bun run dev
|
|||||||
- [ ] **Step 2: Test health endpoint**
|
- [ ] **Step 2: Test health endpoint**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://localhost:3000/health
|
curl http://localhost:4000/health
|
||||||
# Expected: {"status":"ok"}
|
# Expected: {"status":"ok"}
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 3: Upload test file via HTTP API (multipart)**
|
- [ ] **Step 3: Upload test file via HTTP API (multipart)**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://localhost:3000/api/upload \
|
curl -X POST http://localhost:4000/api/upload \
|
||||||
-F "file=@/path/to/testfile.txt" \
|
-F "file=@/path/to/testfile.txt" \
|
||||||
-F "fileName=test.txt"
|
-F "fileName=test.txt"
|
||||||
```
|
```
|
||||||
@@ -1024,14 +1029,14 @@ curl -X POST http://localhost:3000/api/upload \
|
|||||||
- [ ] **Step 4: Check file info endpoint**
|
- [ ] **Step 4: Check file info endpoint**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://localhost:3000/file/{public_id}/info
|
curl http://localhost:4000/file/{public_id}/info
|
||||||
# Expected: JSON with file metadata
|
# Expected: JSON with file metadata
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 5: Download redirect**
|
- [ ] **Step 5: Download redirect**
|
||||||
|
|
||||||
```bash
|
```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
|
# 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)**
|
- [ ] **Step 7: Test error handling (file too large)**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://localhost:3000/api/upload \
|
curl -X POST http://localhost:4000/api/upload \
|
||||||
-F "file=@/dev/null" \
|
-F "file=@/dev/null" \
|
||||||
-H "Content-Length: 10000000000"
|
-H "Content-Length: 10000000000"
|
||||||
# Expected: HTTP 400 with error message
|
# Expected: HTTP 400 with error message
|
||||||
@@ -1057,7 +1062,7 @@ curl -X POST http://localhost:3000/api/upload \
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Send 31 requests within 1 minute
|
# 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
|
wait
|
||||||
# Expected: First 30 succeed, last one returns 429
|
# Expected: First 30 succeed, last one returns 429
|
||||||
```
|
```
|
||||||
@@ -1066,7 +1071,7 @@ wait
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In terminal 1: bun run dev
|
# 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)
|
# Send SIGINT to server (Ctrl+C in terminal 1)
|
||||||
# Check if server stops cleanly, logs show shutdown sequence
|
# Check if server stops cleanly, logs show shutdown sequence
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# Docker, Traefik, and GitHub Actions Deployment Plan
|
# 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.
|
> **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`.
|
**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
|
# Set production environment variables
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV PORT=3000
|
ENV PORT=4000
|
||||||
|
|
||||||
# Copy necessary files from builder and repo
|
# Copy necessary files from builder and repo
|
||||||
COPY --from=builder /usr/src/app/dist/index.js ./dist/index.js
|
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
|
COPY schema.sql ./schema.sql
|
||||||
|
|
||||||
# Expose server port
|
# Expose server port
|
||||||
EXPOSE 3000
|
EXPOSE 4000
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
CMD ["bun", "dist/index.js"]
|
CMD ["bun", "dist/index.js"]
|
||||||
@@ -104,7 +110,7 @@ services:
|
|||||||
- STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID}
|
- STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID}
|
||||||
- BASE_URL=${BASE_URL}
|
- BASE_URL=${BASE_URL}
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
- PORT=3000
|
- PORT=4000
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- LOG_LEVEL=info
|
- LOG_LEVEL=info
|
||||||
networks:
|
networks:
|
||||||
@@ -115,7 +121,7 @@ services:
|
|||||||
- "traefik.http.routers.teleuploader.entrypoints=websecure"
|
- "traefik.http.routers.teleuploader.entrypoints=websecure"
|
||||||
- "traefik.http.routers.teleuploader.tls=true"
|
- "traefik.http.routers.teleuploader.tls=true"
|
||||||
- "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.services.teleuploader.loadbalancer.server.port=3000"
|
- "traefik.http.services.teleuploader.loadbalancer.server.port=4000"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
app-shared-net:
|
app-shared-net:
|
||||||
@@ -166,9 +172,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
BOT_TOKEN: "mock_token"
|
BOT_TOKEN: "mock_token"
|
||||||
STORAGE_CHANNEL_ID: "123456"
|
STORAGE_CHANNEL_ID: "123456"
|
||||||
BASE_URL: "http://localhost:3000"
|
BASE_URL: "http://localhost:4000"
|
||||||
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/postgres"
|
DATABASE_URL: "postgresql://asephs:***@100.121.180.82:6432/postgres"
|
||||||
PORT: "3000"
|
PORT: "4000"
|
||||||
run: bun run test
|
run: bun run test
|
||||||
|
|
||||||
build-and-push:
|
build-and-push:
|
||||||
@@ -223,7 +229,7 @@ jobs:
|
|||||||
- STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID}
|
- STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID}
|
||||||
- BASE_URL=${BASE_URL}
|
- BASE_URL=${BASE_URL}
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
- PORT=3000
|
- PORT=4000
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- LOG_LEVEL=info
|
- LOG_LEVEL=info
|
||||||
networks:
|
networks:
|
||||||
@@ -234,7 +240,7 @@ jobs:
|
|||||||
- "traefik.http.routers.teleuploader.entrypoints=websecure"
|
- "traefik.http.routers.teleuploader.entrypoints=websecure"
|
||||||
- "traefik.http.routers.teleuploader.tls=true"
|
- "traefik.http.routers.teleuploader.tls=true"
|
||||||
- "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.services.teleuploader.loadbalancer.server.port=3000"
|
- "traefik.http.services.teleuploader.loadbalancer.server.port=4000"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
app-shared-net:
|
app-shared-net:
|
||||||
@@ -248,7 +254,7 @@ jobs:
|
|||||||
STORAGE_CHANNEL_ID=${{ secrets.STORAGE_CHANNEL_ID }}
|
STORAGE_CHANNEL_ID=${{ secrets.STORAGE_CHANNEL_ID }}
|
||||||
BASE_URL=${{ secrets.BASE_URL }}
|
BASE_URL=${{ secrets.BASE_URL }}
|
||||||
DATABASE_URL=${{ secrets.DATABASE_URL }}
|
DATABASE_URL=${{ secrets.DATABASE_URL }}
|
||||||
PORT=3000
|
PORT=4000
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Pull latest docker image
|
# Pull latest docker image
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# S3-Compatible TeleUploader Implementation Plan
|
# 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.
|
> **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.
|
**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.S3_DEFAULT_REGION = 'us-east-1';
|
||||||
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
||||||
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
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';
|
process.env.DATABASE_URL = 'postgresql://localhost/test';
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2684,7 +2690,7 @@ describe('S3 Bucket Operations', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return 403 for unauthorized requests', async () => {
|
it('should return 403 for unauthorized requests', async () => {
|
||||||
const req = new Request('http://localhost:3000/', {
|
const req = new Request('http://localhost:4000/', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { authorization: 'Invalid' },
|
headers: { authorization: 'Invalid' },
|
||||||
});
|
});
|
||||||
@@ -2849,7 +2855,7 @@ describe('Web API v1', () => {
|
|||||||
mockDbExecute.mockClear();
|
mockDbExecute.mockClear();
|
||||||
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
||||||
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
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';
|
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 () => {
|
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);
|
const res = await handleWebApiV1(req);
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -2867,7 +2873,7 @@ describe('Web API v1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return 404 for unknown API path', async () => {
|
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);
|
const res = await handleWebApiV1(req);
|
||||||
expect(res.status).toBe(404);
|
expect(res.status).toBe(404);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -2875,7 +2881,7 @@ describe('Web API v1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return bucket object listing', async () => {
|
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);
|
const res = await handleWebApiV1(req);
|
||||||
// Should return 200 even with empty results
|
// Should return 200 even with empty results
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
@@ -2885,7 +2891,7 @@ describe('Web API v1', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should reject invalid bucket name on create', async () => {
|
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',
|
method: 'POST',
|
||||||
headers: { 'content-type': 'application/json' },
|
headers: { 'content-type': 'application/json' },
|
||||||
body: JSON.stringify({ name: 'INVALID_NAME!' }),
|
body: JSON.stringify({ name: 'INVALID_NAME!' }),
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# Telegram Bot Uploader Backend Design
|
# 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
|
**Date:** 2026-05-17
|
||||||
**Status:** Approved
|
**Status:** Approved
|
||||||
**Stack:** Bun, Telegraf, PostgreSQL, Drizzle ORM, Winston, nanoid
|
**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`
|
4. Bot extracts `telegram_file_id`, `telegram_file_unique_id`, `storage_message_id`
|
||||||
5. Bot generates `public_id` using nanoid
|
5. Bot generates `public_id` using nanoid
|
||||||
6. Bot saves metadata to PostgreSQL
|
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
|
#### Upload via HTTP API
|
||||||
1. Client POSTs to `/api/upload` with file (multipart or base64)
|
1. Client POSTs to `/api/upload` with file (multipart or base64)
|
||||||
@@ -115,7 +120,7 @@ fileName: optional_filename.ext
|
|||||||
"size_bytes": 1024000,
|
"size_bytes": 1024000,
|
||||||
"file_type": "document",
|
"file_type": "document",
|
||||||
"created_at": "2026-05-17T23:42:19Z",
|
"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=<telegram_bot_token>
|
BOT_TOKEN=<telegram_bot_token>
|
||||||
STORAGE_CHANNEL_ID=<private_channel_id>
|
STORAGE_CHANNEL_ID=<private_channel_id>
|
||||||
BASE_URL=https://tele.asepharyana.my.id
|
BASE_URL=https://upload.asepharyana.my.id
|
||||||
DATABASE_URL=postgresql://user:password@localhost:5432/telegram_uploader
|
DATABASE_URL=postgresql://asephs:***@100.121.180.82:6432/uploader
|
||||||
PORT=3000
|
PORT=4000
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
RATE_LIMIT_WINDOW_MS=60000
|
RATE_LIMIT_WINDOW_MS=60000
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ metadata:
|
|||||||
|
|
||||||
# Design: TeleUploader Deployment & CI/CD Setup
|
# 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.
|
We are setting up production deployment for TeleUploader on VPS `45.127.35.244` behind Traefik utilizing GitHub Actions.
|
||||||
|
|
||||||
## 1. System Architecture
|
## 1. System Architecture
|
||||||
@@ -22,7 +28,7 @@ TeleUploader is a Bun-based service.
|
|||||||
### `Dockerfile`
|
### `Dockerfile`
|
||||||
- Multi-stage build.
|
- 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 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`
|
### `docker-compose.yml`
|
||||||
```yaml
|
```yaml
|
||||||
@@ -38,7 +44,7 @@ services:
|
|||||||
- STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID}
|
- STORAGE_CHANNEL_ID=${STORAGE_CHANNEL_ID}
|
||||||
- BASE_URL=${BASE_URL}
|
- BASE_URL=${BASE_URL}
|
||||||
- DATABASE_URL=${DATABASE_URL}
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
- PORT=3000
|
- PORT=4000
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- LOG_LEVEL=info
|
- LOG_LEVEL=info
|
||||||
networks:
|
networks:
|
||||||
@@ -49,7 +55,7 @@ services:
|
|||||||
- "traefik.http.routers.teleuploader.entrypoints=websecure"
|
- "traefik.http.routers.teleuploader.entrypoints=websecure"
|
||||||
- "traefik.http.routers.teleuploader.tls=true"
|
- "traefik.http.routers.teleuploader.tls=true"
|
||||||
- "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.teleuploader.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.services.teleuploader.loadbalancer.server.port=3000"
|
- "traefik.http.services.teleuploader.loadbalancer.server.port=4000"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
app-shared-net:
|
app-shared-net:
|
||||||
|
|||||||
+1
-1
@@ -137,7 +137,7 @@ export const config: AppConfig = {
|
|||||||
storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID!, 10),
|
storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID!, 10),
|
||||||
baseUrl: process.env.BASE_URL!,
|
baseUrl: process.env.BASE_URL!,
|
||||||
databaseUrl: process.env.DATABASE_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',
|
nodeEnv: process.env.NODE_ENV || 'development',
|
||||||
logLevel: process.env.LOG_LEVEL || 'info',
|
logLevel: process.env.LOG_LEVEL || 'info',
|
||||||
rateLimitWindowMs: parseNumber(process.env.RATE_LIMIT_WINDOW_MS, 60000),
|
rateLimitWindowMs: parseNumber(process.env.RATE_LIMIT_WINDOW_MS, 60000),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const stripPort = (host: string): string => {
|
const stripPort = (host: string): string => {
|
||||||
// Handle IPv6: [::1]:8080 -> [::1]
|
// Handle IPv6: [::1]:4321 -> [::1]
|
||||||
if (host.startsWith('[')) {
|
if (host.startsWith('[')) {
|
||||||
const closeBracket = host.indexOf(']');
|
const closeBracket = host.indexOf(']');
|
||||||
return host.slice(0, closeBracket + 1).toLowerCase();
|
return host.slice(0, closeBracket + 1).toLowerCase();
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ const setEnv = (key: string, value: string) => {
|
|||||||
defaultEnv('BOT_TOKEN', '123456:ABC-DEF');
|
defaultEnv('BOT_TOKEN', '123456:ABC-DEF');
|
||||||
defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890');
|
defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890');
|
||||||
defaultEnv('BASE_URL', 'https://example.com');
|
defaultEnv('BASE_URL', 'https://example.com');
|
||||||
defaultEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/test');
|
defaultEnv('DATABASE_URL', 'postgresql://asephs:***@100.121.180.82:6432/test');
|
||||||
defaultEnv('PORT', '3000');
|
defaultEnv('PORT', '4000');
|
||||||
defaultEnv('NODE_ENV', 'test');
|
defaultEnv('NODE_ENV', 'test');
|
||||||
setEnv('ADMIN_API_TOKEN', 'route-secret-token');
|
setEnv('ADMIN_API_TOKEN', 'route-secret-token');
|
||||||
setEnv('SESSION_COOKIE_NAME', 'route_session');
|
setEnv('SESSION_COOKIE_NAME', 'route_session');
|
||||||
|
|||||||
+2
-2
@@ -10,8 +10,8 @@ const setEnv = (key: string, value: string) => {
|
|||||||
defaultEnv('BOT_TOKEN', '123456:ABC-DEF');
|
defaultEnv('BOT_TOKEN', '123456:ABC-DEF');
|
||||||
defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890');
|
defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890');
|
||||||
defaultEnv('BASE_URL', 'https://example.com');
|
defaultEnv('BASE_URL', 'https://example.com');
|
||||||
defaultEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/test');
|
defaultEnv('DATABASE_URL', 'postgresql://asephs:***@100.121.180.82:6432/test');
|
||||||
defaultEnv('PORT', '3000');
|
defaultEnv('PORT', '4000');
|
||||||
defaultEnv('NODE_ENV', 'test');
|
defaultEnv('NODE_ENV', 'test');
|
||||||
setEnv('ADMIN_API_TOKEN', 'route-secret-token');
|
setEnv('ADMIN_API_TOKEN', 'route-secret-token');
|
||||||
setEnv('SESSION_COOKIE_NAME', 'route_session');
|
setEnv('SESSION_COOKIE_NAME', 'route_session');
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ process.env.BOT_TOKENS = 'bot1:token,bot2:token,bot3:token';
|
|||||||
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
||||||
process.env.BASE_URL = 'https://example.com';
|
process.env.BASE_URL = 'https://example.com';
|
||||||
process.env.DATABASE_URL = 'sqlite://test.db';
|
process.env.DATABASE_URL = 'sqlite://test.db';
|
||||||
process.env.PORT = '3000';
|
process.env.PORT = '4000';
|
||||||
|
|
||||||
// Track mock queue instances for per-bot assertions
|
// Track mock queue instances for per-bot assertions
|
||||||
const queueInstances: Array<{
|
const queueInstances: Array<{
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import type { TelegramMediaMessage } from '../src/shared/utils/file';
|
|||||||
// Mock environment
|
// Mock environment
|
||||||
process.env.BOT_TOKEN = process.env.BOT_TOKEN || '123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ';
|
process.env.BOT_TOKEN = process.env.BOT_TOKEN || '123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ';
|
||||||
process.env.STORAGE_CHANNEL_ID = process.env.STORAGE_CHANNEL_ID || '-1001234567890';
|
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 = {
|
type BotTestContext = {
|
||||||
message: TelegramMediaMessage;
|
message: TelegramMediaMessage;
|
||||||
|
|||||||
+5
-5
@@ -28,7 +28,7 @@ describe('Environment Variables Validation', () => {
|
|||||||
expect(config.storageChatId).toBe(parseInt(process.env.STORAGE_CHANNEL_ID || '0', 10));
|
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');
|
expect(typeof config.port).toBe('number');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@ describe('Telegram chunk size validation', () => {
|
|||||||
BOT_TOKENS: '123456:ABC-DEF',
|
BOT_TOKENS: '123456:ABC-DEF',
|
||||||
STORAGE_CHANNEL_ID: '-1001234567890',
|
STORAGE_CHANNEL_ID: '-1001234567890',
|
||||||
BASE_URL: 'https://example.com',
|
BASE_URL: 'https://example.com',
|
||||||
DATABASE_URL: 'postgresql://user:***@localhost:5432/test',
|
DATABASE_URL: 'postgresql://asephs:***@100.121.180.82:6432/test',
|
||||||
PORT: '3000',
|
PORT: '4000',
|
||||||
TELEGRAM_CHUNK_SIZE_BYTES: String(48 * 1024 * 1024),
|
TELEGRAM_CHUNK_SIZE_BYTES: String(48 * 1024 * 1024),
|
||||||
},
|
},
|
||||||
stdout: 'pipe',
|
stdout: 'pipe',
|
||||||
@@ -131,8 +131,8 @@ describe('Telegram chunk size validation', () => {
|
|||||||
BOT_TOKENS: '123456:ABC-DEF',
|
BOT_TOKENS: '123456:ABC-DEF',
|
||||||
STORAGE_CHANNEL_ID: '-1001234567890',
|
STORAGE_CHANNEL_ID: '-1001234567890',
|
||||||
BASE_URL: 'https://example.com',
|
BASE_URL: 'https://example.com',
|
||||||
DATABASE_URL: 'postgresql://user:***@localhost:5432/test',
|
DATABASE_URL: 'postgresql://asephs:***@100.121.180.82:6432/test',
|
||||||
PORT: '3000',
|
PORT: '4000',
|
||||||
TELEGRAM_CHUNK_SIZE_BYTES: String(TELEGRAM_CHUNK_SIZE_MAX_BYTES),
|
TELEGRAM_CHUNK_SIZE_BYTES: String(TELEGRAM_CHUNK_SIZE_MAX_BYTES),
|
||||||
},
|
},
|
||||||
stdout: 'pipe',
|
stdout: 'pipe',
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
process.env.BOT_TOKENS ||= '123456:ABC-DEF,789012:GHI-JKL,345678:MNO-PQR';
|
process.env.BOT_TOKENS ||= '123456:ABC-DEF,789012:GHI-JKL,345678:MNO-PQR';
|
||||||
process.env.STORAGE_CHANNEL_ID ||= '-1001234567890';
|
process.env.STORAGE_CHANNEL_ID ||= '-1001234567890';
|
||||||
process.env.BASE_URL ||= 'https://example.com';
|
process.env.BASE_URL ||= 'https://example.com';
|
||||||
process.env.DATABASE_URL ||= 'postgresql://user:pass@localhost:5432/test';
|
process.env.DATABASE_URL ||= 'postgresql://asephs:***@100.121.180.82:6432/test';
|
||||||
process.env.PORT ||= '3000';
|
process.env.PORT ||= '4000';
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
// Pin the chunk size to the safe 19 MB value UNCONDITIONALLY. Bun auto-loads
|
// Pin the chunk size to the safe 19 MB value UNCONDITIONALLY. Bun auto-loads
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ const setEnv = (key: string, value: string) => {
|
|||||||
defaultEnv('BOT_TOKENS', '123456:ABC-DEF');
|
defaultEnv('BOT_TOKENS', '123456:ABC-DEF');
|
||||||
defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890');
|
defaultEnv('STORAGE_CHANNEL_ID', '-1001234567890');
|
||||||
defaultEnv('BASE_URL', 'https://example.com');
|
defaultEnv('BASE_URL', 'https://example.com');
|
||||||
defaultEnv('DATABASE_URL', 'postgresql://user:***@localhost:5432/test');
|
defaultEnv('DATABASE_URL', 'postgresql://asephs:***@100.121.180.82:6432/test');
|
||||||
defaultEnv('PORT', '3000');
|
defaultEnv('PORT', '4000');
|
||||||
defaultEnv('NODE_ENV', 'test');
|
defaultEnv('NODE_ENV', 'test');
|
||||||
setEnv('ADMIN_API_TOKEN', 'route-secret-token');
|
setEnv('ADMIN_API_TOKEN', 'route-secret-token');
|
||||||
setEnv('SESSION_COOKIE_NAME', 'route_session');
|
setEnv('SESSION_COOKIE_NAME', 'route_session');
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ process.env.NODE_ENV = 'test';
|
|||||||
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
||||||
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
||||||
process.env.BASE_URL = 'http://localhost:4000';
|
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';
|
||||||
process.env.PORT = '3000';
|
process.env.PORT = '4000';
|
||||||
process.env.S3_ACCESS_KEY = 'filedrop-admin';
|
process.env.S3_ACCESS_KEY = 'filedrop-admin';
|
||||||
process.env.S3_SECRET_KEY = 'unit-test-secret';
|
process.env.S3_SECRET_KEY = 'unit-test-secret';
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ describe('Web API v1', () => {
|
|||||||
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
process.env.BOT_TOKEN = '123456:ABC-DEF';
|
||||||
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
process.env.STORAGE_CHANNEL_ID = '-1001234567890';
|
||||||
process.env.BASE_URL = 'http://localhost:4000';
|
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');
|
const webApi = await import('../src/interfaces/http/controllers/web-api-controller');
|
||||||
handleWebApiV1 = webApi.handleWebApiV1;
|
handleWebApiV1 = webApi.handleWebApiV1;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user