From 6f138ebd45c5ed146ac4b611d0a4023c933d516c Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Thu, 16 Jul 2026 10:13:04 +0800 Subject: [PATCH] docs: record production deployment and maintenance --- AGENTS.md | 21 ++++++ README.md | 31 ++++++--- deploy/README.md | 166 +++++++++++++++++++++++++++++++++++---------- frontend/README.md | 8 ++- 4 files changed, 178 insertions(+), 48 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d0c04f66..2840ba4c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,27 @@ 本文件是当前项目给协作代理、自动化助手与派生工作流的硬约束补充。它不替代 `SKILL.md`,而是把最容易被偷懒、省略、或在多窗口工作时遗失的高严谨规则单独钉死。 +## 0. Production Maintenance Truth + +任何部署、线上故障、域名、登录或环境变量任务,先读取 `deploy/README.md`,不要重新猜测架构。 + +- Production domain: `https://jyotisha.chat` +- Source: `https://github.com/jesse-ux/Jyotisha.git` +- Server: Hong Kong Ubuntu 22.04 VPS, `103.117.123.53`, SSH port `22000` +- Runtime: `/opt/jyotisha-app`, Docker Compose file `deploy/docker-compose.server.yml` +- Secrets: `/opt/jyotisha-app/.env.production`; never print, copy into chat, or commit +- Public edge: Caddy only; Next.js `3000` and Python API `5200` stay Docker-private +- Managed services: Spaceship DNS, Supabase project `vtvnfqmonbfuxmqkqdlc`, external model API +- Capacity boundary: 1 vCPU / 2 GB RAM / 40 GB disk / 5 Mbps; demo and low concurrency only + +Deployment safety rules: + +1. Run `git status --short --branch` before packaging; do not overwrite unrelated dirty files. +2. Verify `dig +short @launch1.spaceship.net A jyotisha.chat` returns `103.117.123.53` before troubleshooting Caddy certificate issuance. +3. Keep Supabase Auth Site URL and redirect URLs aligned with `https://jyotisha.chat`. +4. After deployment, verify `/login`, logged-out `/api/account` = `401`, internal `/api/health` = `200`, and `swisseph_available = true`. +5. Never expose port `5200`, `SUPABASE_SERVICE_ROLE_KEY`, model keys, user JWTs, passwords, or SSH private keys. + ## 1. High-Rigor Override 当用户明确要求以下任一项时,必须进入高严谨模式: diff --git a/README.md b/README.md index f4b47d57..8f91960a 100644 --- a/README.md +++ b/README.md @@ -11,23 +11,32 @@ --- -## Product service layout +## Production service layout ```text -frontend/ Next.js + Mastra chat product -scripts/jyotish_api_server.py Python API entrypoint -jyotish_vedic/ Python calculation package -skills/ + references/ + assets/ Agent skill and calculation evidence -supabase/ Auth, profile, session, credits migrations -deploy/ Railway web/api Dockerfiles +jyotisha.chat + -> Spaceship DNS + -> Caddy on Hong Kong VPS (80/443) + -> Next.js + Mastra web container (3000, private) + -> Python Jyotish API container (5200, private) + -> Swiss Ephemeris / local calculation engine + -> VedAstro gateway with local fallback + -> Supabase Cloud (Auth, Postgres, profiles, sessions, credits) + -> external OpenAI-compatible model API ``` -Railway runs two services from the same repository: +Current production infrastructure: -- `web`: `deploy/railway-web.Dockerfile` -- `api`: `deploy/railway-api.Dockerfile` +- Domain: `https://jyotisha.chat` +- Server: Hong Kong, Ubuntu 22.04, `103.117.123.53`, SSH port `22000` +- Capacity: 1 vCPU, 2 GB RAM, 40 GB disk, 5 Mbps; intended for demos and low concurrency +- Runtime directory: `/opt/jyotisha-app` +- Compose file: `deploy/docker-compose.server.yml` +- Production environment: `/opt/jyotisha-app/.env.production` (`0600`, never commit) +- Supabase project: `vtvnfqmonbfuxmqkqdlc` +- Source repository: `https://github.com/jesse-ux/Jyotisha.git` -Deployment variables and private-network wiring are documented in `deploy/README.md`. +Deployment, recovery, DNS, HTTPS, update and verification commands are documented in [`deploy/README.md`](deploy/README.md). Railway/Vercel remain optional alternatives, not the current production topology. ## Table of Contents diff --git a/deploy/README.md b/deploy/README.md index fe21dcc6..a9f6e656 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,62 +1,156 @@ -# Railway deployment +# Production deployment and maintenance -Create services named `web` and `api` from this repository. Leave both **Root Directory** and **Start Command** empty; the Dockerfiles bind `0.0.0.0` and read `$PORT`. +This file is the operational source of truth for the current Jyotisha demo deployment. -| Service | Required variable | Healthcheck Path | -| --- | --- | --- | -| `web` | `RAILWAY_DOCKERFILE_PATH=/deploy/railway-web.Dockerfile` | `/login` | -| `api` | `RAILWAY_DOCKERFILE_PATH=/deploy/railway-api.Dockerfile` | `/api/health` | +## Current production -## `api` variables +| Item | Value | +| --- | --- | +| Public domain | `https://jyotisha.chat` | +| DNS | Spaceship nameservers (`launch1.spaceship.net`, `launch2.spaceship.net`) | +| Server | Hong Kong VPS, Ubuntu 22.04 x86_64 | +| Public host | `103.117.123.53` | +| SSH | port `22000`, public-key authentication only | +| Capacity | 1 vCPU / 2 GB RAM / 40 GB disk / 5 Mbps | +| App directory | `/opt/jyotisha-app` | +| Environment file | `/opt/jyotisha-app/.env.production` (`0600`) | +| Source repository | `https://github.com/jesse-ux/Jyotisha.git` | +| Supabase project | `vtvnfqmonbfuxmqkqdlc` | -```dotenv -PORT=5200 +This machine is suitable for a client demo and low concurrency. Supabase and the model provider stay managed externally; do not self-host them on this VPS. + +## Architecture + +```text +Spaceship DNS + -> Caddy :80/:443 + -> web:3000 (Next.js + Mastra, Docker-private) + -> api:5200 (Python Jyotish API, Docker-private) + -> Swiss Ephemeris / local engine + -> VedAstro gateway with local fallback + -> Supabase Cloud + -> external OpenAI-compatible model API ``` -`PORT` is set explicitly so the web service can reference the private API port. Railway healthchecks and the container command use the same value. No public API domain or legacy `jyotish-app/` service is needed. +Only Caddy publishes host ports. Ports `3000` and `5200` must remain private. -## `web` variables +## DNS and Supabase Auth -Required: +Spaceship resource records: + +```text +A @ 103.117.123.53 +CNAME www jyotisha.chat +``` + +Supabase Authentication URL Configuration: + +```text +Site URL: https://jyotisha.chat +Redirect URLs: https://jyotisha.chat/** + https://www.jyotisha.chat/** +``` + +Before changing Caddy to the domain, verify the authoritative DNS result: + +```bash +dig +short @launch1.spaceship.net A jyotisha.chat +``` + +It must return `103.117.123.53`. Caddy provisions and renews HTTPS automatically after DNS resolves. + +## Production environment + +`.env.production` combines the backend and frontend server variables. Required groups: ```dotenv -JYOTISH_API_BASE=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}} +SITE_ADDRESS=https://jyotisha.chat +JYOTISH_API_BASE=http://api:5200 + NEXT_PUBLIC_SUPABASE_URL=... NEXT_PUBLIC_SUPABASE_ANON_KEY=... SUPABASE_SERVICE_ROLE_KEY=... -``` +ADMIN_EMAILS=... -For AI responses, configure either: - -```dotenv +# Either OpenAI: OPENAI_API_KEY=... -MASTRA_MODEL=openai/gpt-5-mini -``` +MASTRA_MODEL=... -or an OpenAI-compatible provider: - -```dotenv +# Or an OpenAI-compatible provider: LLM_BASE_URL=... LLM_API_KEY=... LLM_MODEL=... -# LLM_PROVIDER_ID=third-party + +# Optional VedAstro official upstream; local fallback remains available: +VEDASTRO_API_ENDPOINT=... +VEDASTRO_API_KEY=... ``` -`ADMIN_EMAILS=admin@example.com,ops@example.com` is required to use `/admin/codes`. Generate a public domain only for `web`. +Never commit `.env.production`, `SUPABASE_SERVICE_ROLE_KEY`, model keys, user JWTs, SSH private keys or passwords. `NEXT_PUBLIC_SUPABASE_ANON_KEY` is intentionally public; authorization is enforced by Supabase RLS and server-side checks. - -## After the first deploy - -1. Add the generated `web` domain to Supabase Auth **Site URL** and **Redirect URLs**. -2. Open `/login`, sign in with an address listed in `ADMIN_EMAILS`, then verify `/admin/codes`. -3. Keep `api` private; verify its `/api/health` from Railway logs or the `web` service. - -## Small VPS deployment - -For a single low-traffic server, keep Supabase managed and run only the Web and API services: +## Connect and inspect ```bash -docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build +ssh -p 22000 root@103.117.123.53 +cd /opt/jyotisha-app +COMPOSE='docker compose --env-file .env.production -f deploy/docker-compose.server.yml' +$COMPOSE ps +$COMPOSE logs --tail=100 api web caddy +free -h +docker stats --no-stream ``` -Set `SITE_ADDRESS=http://SERVER_IP` for initial HTTP testing. Replace it with the production domain after DNS resolves; Caddy will then provision HTTPS automatically. +The server has a persistent 2 GB `/swapfile`. UFW permits only SSH `22000/tcp`, HTTP `80/tcp`, HTTPS `443/tcp`, and the pre-existing WireGuard `51820/udp` rule. + +## Deploy an update from the maintainer Mac + +The GitHub repository is private and the VPS does not currently have a GitHub deploy key. Deploy the tracked tree without copying local secrets: + +```bash +cd /Users/jesse/Downloads/Copse/astrology/yinduzhanxing +git status --short --branch +git archive --format=tar.gz --output=/tmp/jyotisha.tar.gz HEAD +scp -P 22000 /tmp/jyotisha.tar.gz root@103.117.123.53:/tmp/jyotisha.tar.gz +ssh -p 22000 root@103.117.123.53 \ + 'cd /opt/jyotisha-app && tar -xzf /tmp/jyotisha.tar.gz && rm -f /tmp/jyotisha.tar.gz && docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build' +``` + +`git archive` does not include ignored `.env` files. Extraction preserves `/opt/jyotisha-app/.env.production`. + +## Verification + +```bash +curl -fsS https://jyotisha.chat/login >/dev/null +curl -fsS -o /dev/null -w '%{http_code}\n' https://jyotisha.chat/api/account +``` + +The second command should return `401` while logged out. Verify the private Python API from inside the web container: + +```bash +ssh -p 22000 root@103.117.123.53 \ + 'cd /opt/jyotisha-app && docker compose --env-file .env.production -f deploy/docker-compose.server.yml exec -T web node -e "fetch(\"http://api:5200/api/health\").then(async r=>{console.log(r.status); console.log(await r.text())})"' +``` + +Expected: HTTP `200`, `"status": "ok"`, and `"swisseph_available": true`. Public access to `103.117.123.53:5200` must fail. + +Then manually verify: OTP login, onboarding/profile persistence, chat-session persistence, code redemption, admin code generation, streaming response, one-credit charge, and refund on failure before the first output chunk. + +## Common operations + +```bash +# Restart without rebuilding +docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d + +# Rebuild only the web container +docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build web caddy + +# Rebuild only the Python API +docker compose --env-file .env.production -f deploy/docker-compose.server.yml up -d --build api + +# Follow logs +docker compose --env-file .env.production -f deploy/docker-compose.server.yml logs -f --tail=100 api web caddy +``` + +## Optional Railway deployment + +Railway is not the current production target. If needed, create `web` and `api` services from the same repository using `deploy/railway-web.Dockerfile` and `deploy/railway-api.Dockerfile`; keep `api` private and set the web service's `JYOTISH_API_BASE` to Railway's private API hostname. diff --git a/frontend/README.md b/frontend/README.md index 9d86ac1e..847867a4 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -216,7 +216,13 @@ supabase/migrations/20260715040000_agent_onboarding_cache.sql 相同兑换码只能兑换一次;首次兑换后会永久记录兑换账户、邮箱和时间。新注册用户默认 0 点,因此即使 demo URL 被转发,也不能在没有兑换码的情况下调用 Agent。 -## Vercel + Supabase Demo 部署 +## 当前线上部署 + +当前生产 Demo 使用 `https://jyotisha.chat`,Next.js、Mastra 和 Python API 通过 Docker Compose 部署在香港 VPS,Supabase 与模型 API 继续使用云服务。服务器、DNS、环境变量、更新和验收命令统一以 [`../deploy/README.md`](../deploy/README.md) 为准。 + +## Vercel + Supabase 备选部署 + +以下方案只作为无服务器备选,不是当前线上拓扑。 ### Web 部署到 Vercel