docs: update deployment env and runtime docs for convex qwen minio

This commit is contained in:
Codex
2026-02-18 13:59:11 +00:00
parent b1eed7fa2c
commit e056d38ec7
4 changed files with 69 additions and 46 deletions

View File

@@ -1,10 +1,20 @@
# Runtime # Runtime
NODE_ENV=production NODE_ENV=production
PORT=3000 PORT=3000
STATE_FILE_PATH=/data/state.json
LOG_LEVEL=info LOG_LEVEL=info
APP_BASE_URL=https://xartaudio.example.com APP_BASE_URL=https://xartaudio.example.com
# Better Auth
BETTER_AUTH_SECRET=replace-me
BETTER_AUTH_BASE_PATH=/api/auth
BETTER_AUTH_DEV_PASSWORD=replace-me
# Convex
CONVEX_DEPLOYMENT_URL=https://your-deployment.convex.cloud
CONVEX_AUTH_TOKEN=
CONVEX_STATE_QUERY=state:getLatestSnapshot
CONVEX_STATE_MUTATION=state:saveSnapshot
# Webhook secrets # Webhook secrets
X_WEBHOOK_SECRET=replace-me X_WEBHOOK_SECRET=replace-me
POLAR_WEBHOOK_SECRET=replace-me POLAR_WEBHOOK_SECRET=replace-me
@@ -18,19 +28,22 @@ POLAR_ACCESS_TOKEN=replace-me
POLAR_SERVER=production POLAR_SERVER=production
POLAR_PRODUCT_IDS=prod_123 POLAR_PRODUCT_IDS=prod_123
# TTS (OpenAI-compatible) # Qwen3 TTS
TTS_API_KEY=replace-me QWEN_TTS_API_KEY=replace-me
TTS_BASE_URL= QWEN_TTS_BASE_URL=https://dashscope-intl.aliyuncs.com/compatible-mode/v1
TTS_MODEL=gpt-4o-mini-tts QWEN_TTS_MODEL=qwen-tts-latest
TTS_VOICE=alloy QWEN_TTS_VOICE=Cherry
QWEN_TTS_FORMAT=mp3
# S3-compatible object storage # MinIO object storage
S3_BUCKET=replace-me MINIO_ENDPOINT=minio.example.com
S3_REGION=us-east-1 MINIO_PORT=443
S3_ENDPOINT= MINIO_USE_SSL=true
S3_ACCESS_KEY_ID=replace-me MINIO_BUCKET=replace-me
S3_SECRET_ACCESS_KEY=replace-me MINIO_REGION=us-east-1
S3_SIGNED_URL_TTL_SEC=3600 MINIO_ACCESS_KEY=replace-me
MINIO_SECRET_KEY=replace-me
MINIO_SIGNED_URL_TTL_SEC=3600
# Credit policy # Credit policy
BASE_CREDITS=1 BASE_CREDITS=1

View File

@@ -4,7 +4,7 @@ WORKDIR /app
ENV NODE_ENV=production ENV NODE_ENV=production
ENV PORT=3000 ENV PORT=3000
ENV STATE_FILE_PATH=/data/state.json ENV CONVEX_DEPLOYMENT_URL=
COPY package.json bun.lock ./ COPY package.json bun.lock ./
RUN bun install --frozen-lockfile RUN bun install --frozen-lockfile
@@ -15,7 +15,6 @@ COPY spec.md ./spec.md
RUN bun run build:css RUN bun run build:css
EXPOSE 3000 EXPOSE 3000
VOLUME ["/data"]
HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD bun -e "fetch('http://127.0.0.1:'+process.env.PORT+'/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD bun -e "fetch('http://127.0.0.1:'+process.env.PORT+'/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"

View File

@@ -330,10 +330,10 @@ This repository now contains a deployable production-style app (single container
5. Real integration adapters implemented: 5. Real integration adapters implemented:
- X API (`twitter-api-v2`) - X API (`twitter-api-v2`)
- Polar SDK checkout/webhook handling (`@polar-sh/sdk`) - Polar SDK checkout/webhook handling (`@polar-sh/sdk`)
- TTS (`openai`) - TTS (`Qwen3 TTS`, OpenAI-compatible endpoint via `fetch`)
- Object storage + signed URLs (`@aws-sdk/client-s3`, `@aws-sdk/s3-request-presigner`) - Object storage + signed URLs (`minio`)
6. Persistent state across restarts: 6. Persistent state across restarts:
- all wallet/job/asset/access state is snapshotted and stored to `STATE_FILE_PATH` - all wallet/job/asset/access state is snapshotted through Convex query/mutation functions
7. Abuse protection: 7. Abuse protection:
- fixed-window rate limiting for webhook, auth, and action routes - fixed-window rate limiting for webhook, auth, and action routes
8. PWA support: 8. PWA support:
@@ -344,9 +344,9 @@ This repository now contains a deployable production-style app (single container
- `bun run lint` - `bun run lint`
### Authentication model ### Authentication model
1. Browser flow uses secure-ish HTTP-only cookie session (`xartaudio_user`) via `/auth/dev-login`. 1. Browser flow is powered by Better Auth under `/api/auth/*`.
2. API calls also support `x-user-id` header for scripted usage/testing. 2. `/auth/dev-login` bootstraps a Better Auth session for local/dev testing.
3. This auth layer is intentionally replaceable with X OAuth in production rollout. 3. API calls also support `x-user-id` header for scripted usage/testing.
### Runtime endpoints ### Runtime endpoints
1. Public: 1. Public:
@@ -380,10 +380,17 @@ Use `.env.example` as the source of truth.
1. Runtime: 1. Runtime:
- `PORT` - `PORT`
- `STATE_FILE_PATH`
- `LOG_LEVEL` - `LOG_LEVEL`
- `APP_BASE_URL` - `APP_BASE_URL`
2. Secrets: 2. Auth + state:
- `BETTER_AUTH_SECRET`
- `BETTER_AUTH_BASE_PATH`
- `BETTER_AUTH_DEV_PASSWORD`
- `CONVEX_DEPLOYMENT_URL`
- `CONVEX_AUTH_TOKEN`
- `CONVEX_STATE_QUERY`
- `CONVEX_STATE_MUTATION`
3. Secrets:
- `X_WEBHOOK_SECRET` - `X_WEBHOOK_SECRET`
- `POLAR_WEBHOOK_SECRET` - `POLAR_WEBHOOK_SECRET`
- `X_BEARER_TOKEN` - `X_BEARER_TOKEN`
@@ -391,23 +398,26 @@ Use `.env.example` as the source of truth.
- `POLAR_ACCESS_TOKEN` - `POLAR_ACCESS_TOKEN`
- `POLAR_SERVER` - `POLAR_SERVER`
- `POLAR_PRODUCT_IDS` - `POLAR_PRODUCT_IDS`
- `TTS_API_KEY` - `QWEN_TTS_API_KEY`
- `TTS_BASE_URL` - `QWEN_TTS_BASE_URL`
- `TTS_MODEL` - `QWEN_TTS_MODEL`
- `TTS_VOICE` - `QWEN_TTS_VOICE`
- `S3_BUCKET` - `QWEN_TTS_FORMAT`
- `S3_REGION` - `MINIO_ENDPOINT`
- `S3_ENDPOINT` - `MINIO_PORT`
- `S3_ACCESS_KEY_ID` - `MINIO_USE_SSL`
- `S3_SECRET_ACCESS_KEY` - `MINIO_BUCKET`
- `S3_SIGNED_URL_TTL_SEC` - `MINIO_REGION`
3. Credit model: - `MINIO_ACCESS_KEY`
- `MINIO_SECRET_KEY`
- `MINIO_SIGNED_URL_TTL_SEC`
4. Credit model:
- `BASE_CREDITS` - `BASE_CREDITS`
- `INCLUDED_CHARS` - `INCLUDED_CHARS`
- `STEP_CHARS` - `STEP_CHARS`
- `STEP_CREDITS` - `STEP_CREDITS`
- `MAX_CHARS_PER_ARTICLE` - `MAX_CHARS_PER_ARTICLE`
4. Rate limits: 5. Rate limits:
- `WEBHOOK_RPM` - `WEBHOOK_RPM`
- `AUTH_RPM` - `AUTH_RPM`
- `ACTION_RPM` - `ACTION_RPM`
@@ -416,17 +426,16 @@ Use `.env.example` as the source of truth.
1. Create a new service from this repository and select `Dockerfile` build mode. 1. Create a new service from this repository and select `Dockerfile` build mode.
2. Set container port to `3000`. 2. Set container port to `3000`.
3. Add a persistent volume mounted at `/data`. 3. Configure all secrets and policy env vars from `.env.example`.
4. Set `STATE_FILE_PATH=/data/state.json`. 4. Ensure `CONVEX_DEPLOYMENT_URL` is reachable from the container network.
5. Configure all secrets and policy env vars from `.env.example`. 5. Expose HTTPS URL and point providers to:
6. Expose HTTPS URL and point providers to:
- `https://<your-domain>/api/webhooks/x` - `https://<your-domain>/api/webhooks/x`
- `https://<your-domain>/api/webhooks/polar` - `https://<your-domain>/api/webhooks/polar`
7. Verify deployment health with `GET /health`. 6. Verify deployment health with `GET /health`.
## Production Checklist ## Production Checklist
1. Replace dev-login cookie auth with X OAuth before public launch. 1. Replace `/auth/dev-login` with direct Better Auth UI/OAuth sign-in for public launch.
2. Populate integration keys in Coolify environment for X, Polar, TTS, and S3. 2. Populate integration keys in Coolify environment for X, Polar, Qwen3 TTS, MinIO, and Convex.
3. Replace local state file with managed database for multi-replica scaling. 3. Implement Convex functions named by `CONVEX_STATE_QUERY` and `CONVEX_STATE_MUTATION`.
4. Add tracing and external alerting. 4. Add tracing and external alerting.

View File

@@ -8,7 +8,7 @@ test("Dockerfile contains production container essentials", () => {
const dockerfile = fs.readFileSync("Dockerfile", "utf8"); const dockerfile = fs.readFileSync("Dockerfile", "utf8");
assert.match(dockerfile, /FROM oven\/bun:1\.3\.5-alpine/); assert.match(dockerfile, /FROM oven\/bun:1\.3\.5-alpine/);
assert.match(dockerfile, /EXPOSE 3000/); assert.match(dockerfile, /EXPOSE 3000/);
assert.match(dockerfile, /STATE_FILE_PATH=\/data\/state\.json/); assert.match(dockerfile, /CONVEX_DEPLOYMENT_URL=/);
assert.match(dockerfile, /bun install --frozen-lockfile/); assert.match(dockerfile, /bun install --frozen-lockfile/);
assert.match(dockerfile, /bun run build:css/); assert.match(dockerfile, /bun run build:css/);
assert.match(dockerfile, /HEALTHCHECK/); assert.match(dockerfile, /HEALTHCHECK/);
@@ -25,8 +25,10 @@ test("env example includes required webhook and credit settings", () => {
assert.match(envFile, /POLAR_WEBHOOK_SECRET=/); assert.match(envFile, /POLAR_WEBHOOK_SECRET=/);
assert.match(envFile, /POLAR_ACCESS_TOKEN=/); assert.match(envFile, /POLAR_ACCESS_TOKEN=/);
assert.match(envFile, /POLAR_PRODUCT_IDS=/); assert.match(envFile, /POLAR_PRODUCT_IDS=/);
assert.match(envFile, /TTS_API_KEY=/); assert.match(envFile, /QWEN_TTS_API_KEY=/);
assert.match(envFile, /S3_BUCKET=/); assert.match(envFile, /MINIO_ENDPOINT=/);
assert.match(envFile, /CONVEX_DEPLOYMENT_URL=/);
assert.match(envFile, /BETTER_AUTH_SECRET=/);
assert.match(envFile, /INCLUDED_CHARS=/); assert.match(envFile, /INCLUDED_CHARS=/);
assert.match(envFile, /WEBHOOK_RPM=/); assert.match(envFile, /WEBHOOK_RPM=/);
}); });