docs: record production deployment and maintenance

This commit is contained in:
Jesse_Chen
2026-07-16 10:13:04 +08:00
parent 66bc420edb
commit 6f138ebd45
4 changed files with 178 additions and 48 deletions
+21
View File
@@ -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
当用户明确要求以下任一项时,必须进入高严谨模式:
+20 -11
View File
@@ -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
+130 -36
View File
@@ -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.
+7 -1
View File
@@ -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 部署在香港 VPSSupabase 与模型 API 继续使用云服务。服务器、DNS、环境变量、更新和验收命令统一以 [`../deploy/README.md`](../deploy/README.md) 为准。
## Vercel + Supabase 备选部署
以下方案只作为无服务器备选,不是当前线上拓扑。
### Web 部署到 Vercel