feat: initialize wheelofnames API

This commit is contained in:
tiennm99 committed 2026-07-06 22:20:48 +07:00
1 parent 194caf17eb
commit 3f5ed700bb
41 files changed
+5031

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
# Deployment
## Recommendation
Use a self-hosted/container runtime for v1. Static-only hosts are not enough
because `/api/gif` must render GIF bytes on the server with Remotion.
Good first targets:
- Coolify Docker app
- Fly.io
- Railway
- Render
- VPS with Docker
- Google Cloud Run generic container
Avoid for v1:
- Cloudflare Workers/Pages
- pure static Vercel/Netlify deploys
## Runtime
Required env vars:
```sh
PORT=3000
HOST=0.0.0.0
MAX_CONCURRENT_RENDERS=1
RENDER_TIMEOUT_MS=15000
MAX_OPTIONS=32
MAX_OPTION_CHARS=40
API_TOKEN=change-me
```
Start with 1-2 vCPU and 1-2 GB RAM. Increase only after render benchmarks show
the service is CPU-bound or concurrency-limited.
Local non-Docker render smoke requires Chrome Headless Shell shared libraries,
including `libnspr4` and `libnss3`. Prefer Docker for consistent verification.
The Docker image runs `pnpm browser:ensure` during build so production requests
do not need to download Chrome Headless Shell on first render.
`RENDER_TIMEOUT_MS` is a total render timeout. Values below `7000` are raised to
`7000` because Remotion's browser timeout has that minimum.
Set `API_TOKEN` for every production deployment. The server refuses to start
with `NODE_ENV=production` unless the token is configured.
## Health
```sh
curl http://localhost:3000/api/healthz
```
## Render Test
```sh
curl -X POST http://localhost:3000/api/gif \
-H 'content-type: application/json' \
-H 'authorization: Bearer change-me' \
--output wheel.gif \
--data '{"options":["alice","bob","carol"],"winnerIndex":1}'
```
+39
View File
@@ -0,0 +1,39 @@
# miti99bot Integration
Future bot integration should keep winner handling explicit.
## Recommended Flow
1. Bot parses `/wheelofnamesbeta` options.
2. Bot chooses `winnerIndex` locally.
3. Bot calls `POST /api/gif`.
4. Bot sends response bytes with Telegram `sendAnimation`.
5. Bot caption uses local winner as source of truth.
6. If the service fails, bot falls back to existing local GIF renderer.
## Request
Send `Authorization: Bearer <API_TOKEN>` with the JSON body.
```json
{
"options": ["alice", "bob", "carol"],
"winnerIndex": 1,
"durationMs": 6500,
"holdMs": 1200,
"fps": 15,
"size": 512,
"theme": "classic"
}
```
## Response
- Body: `image/gif`
- Headers:
- `X-Wheel-Winner-Index`
- `X-Wheel-Winner`
- `X-Render-Duration-Ms`
`X-Wheel-Winner` is URL-encoded. Decode it before displaying if service-side
winner selection is used.
+14
View File
@@ -0,0 +1,14 @@
# Render Benchmarks
Fill this after running:
```sh
pnpm render:fixtures
```
| Fixture | Size | FPS | Duration | Bytes | Render Time | Notes |
|---|---:|---:|---:|---:|---:|---|
| smoke | 384 | 12 | 3.5s | 315661 | 13917ms | Docker `pnpm render:smoke` on 2026-07-06 |
| api-smoke | 384 | 12 | 3.5s | 298374 | 4100ms | Docker `pnpm api:smoke`, after startup bundle warm-up |
| vietnamese | 512 | 15 | 7.7s | TBD | TBD | label readability |
| sixteen-options | 512 | 15 | 7.7s | TBD | TBD | dense wheel |