状态:
kira-auth 服务代码已实现,fly.toml / Dockerfile / GitHub Actions 已就绪。是否已实际 deploy 以及 kira-web 端切到薄 auth client 的 cutover,是独立的、进行中的工作。本页按代码与配置文件描述部署形态。部署形态
| 项 | 值 |
|---|---|
| 平台 | Fly.io |
| Fly app | kira-auth |
primary_region | sjc |
| 区域分布 | fra / nrt / sjc(对齐 web/be/cdn 三区) |
| 每机资源 | shared-cpu-4x / 4gb([[vm]] cpu_kind=shared, cpus=4) |
| 内部端口 | 8095(force_https = true) |
| 弹性 | auto_stop_machines = "stop",auto_start_machines = true,min_machines_running = 3 |
| 公网域名 | https://authapi.kira.art |
| 入口 | bun /app/src/bootstrap.ts(先 startTelemetry() 再 import index) |
机器数 + 区域分布是 runtime scale 状态(
fly scale count --region),不在 fly.toml;但 [[vm]] 尺寸会被 deploy 重新套用,所以必须和实际一致,否则 deploy 会把机器打回小尺寸。无状态 = 可水平扩
完全无进程内存、无 DB。会话权威是 Supabase;refresh token 封印在客户端.kira.art cookie,每请求自带 → 任意机器可处理。封印密钥 AUTH_REFRESH_SECRET 由 Fly secret 注入、所有机器同值 → 多机安全。auto_stop 缩到 min 3 台热机,有量 auto_start 拉到上限。
环境变量
非密配置走fly.toml [env];密钥走 fly secrets set(不入代码、不进本文件)。src/env.ts 是 fail-fast(无 zod),必填缺失直接抛。
必填
| 变量 | 来源 | 说明 |
|---|---|---|
PUBLIC_BASE_URL | [env] | authapi 自身入口;redirectTo = ${PUBLIC_BASE_URL}/callback。prod https://authapi.kira.art,dev http://localhost:8095 |
SUPABASE_URL | [env] | Supabase 项目 URL(https://base.kira.art),必须和 kira-web 的 NEXT_PUBLIC_SUPABASE_URL 同 host |
SUPABASE_ANON_KEY | secret | OAuth 两段 + GoTrue 转发 |
SUPABASE_KEY | secret | service-role key,onboarding 写库(claim_referral / user_profiles) |
AUTH_REFRESH_SECRET | secret | 封印 ka_session 的密钥,≥32 字符。所有机器同值 |
COOKIE_DOMAIN | [env] | 会话 cookie 作用域。prod .kira.art(prod+creator 子域无感共享);dev 留空 → host-only |
ALLOWED_REDIRECT_ORIGINS | [env] | CSV origin。既是 /login?next= 回跳白名单(防开放重定向),也是 /refresh、/logout 的 CORS 允许 origin。第一个 = 非法 next 的兜底默认。prod https://kira.art,https://creator.kira.art,https://poisson.art |
OTEL_EXPORTER_OTLP_ENDPOINT | [env] | http://kira-otel-collector.internal:4318。OTel opt-in:prod + 此项都在才开,dev 留空 = no-op(只 stdout) |
NODE_ENV | [env] | production(prod);决定 IS_PROD(cookie Secure / telemetry 开关) |
可选
| 变量 | 默认 | 说明 |
|---|---|---|
PORT | 8095 | 监听端口 |
OTEL_LOG_LEVEL | — | debug 时把 OTel/exporter 诊断打到 console |
fly.toml [env](非密,已签入)
设置 secrets
Supabase Auth 回调注册
Supabase Auth → URL Configuration → Redirect URLs 必须包含${PUBLIC_BASE_URL}/callback:
- prod:
https://authapi.kira.art/callback - dev:
http://localhost:8095/callback
/callback 时 exchangeCodeForSession 会被 Supabase 拒。
Observability
OTel 接法对齐kira-agent / kira-be,导出到 kira-otel-collector.internal:4318 → Dash0。版本钉死 stable 2.7.1 / exp 0.218.0(见 memory: OTel pin transitive deps)。dev(非 production)完全 no-op,只 stdout。
| 信号 | 实现 | 备注 |
|---|---|---|
| 入站 trace | @hono/otel httpInstrumentationMiddleware | SERVER span + http.server.request.duration histogram + active_requests |
| 出站 trace | installFetchTracing() —— 手写 globalThis.fetch wrapper | CLIENT span(http.host/method/url/status_code,≥400 标 ERROR),覆盖所有 Supabase GoTrue 调用 |
| metrics | 全局 MeterProvider,PeriodicExportingMetricReader(30s) | RED 信号 |
| logs | appLog(telemetry/logger.ts) | 4 级 + per-call report opt |
| errors | captureException(telemetry/errors.ts) | ERROR log 带 exception.*(Dash0 分组源)+ span.recordException |
Trace 采样 & propagation
- 100% 采样(
AlwaysOnSampler);tail-sampling(error/慢 100% + 正常 10%)在kira-otel-collector做。 - W3C 只注自家:
traceparent只注入到*.kira.art与*.internal服务,不外泄给 Google / Supabase。
日志上报规则
appLog per-level 默认 report:debug/info=false,warn/error=true,可 per-call 用 opts.report 覆盖。stdout 永远写(dev TTY 彩色 / prod JSON);Dash0 仅 prod 且 report=true。
appLog.info("kira-auth.listening", …, { report: true })—— 启动确认,显式上 Dash0。appLog.info("callback.login_success", …)——report=false(默认),避免和 PostHog 登录事件重复。refresh.upstream_unavailable用warn(真异常,上 Dash0);refresh.expired、refresh.no_session用debug(常见会话到期,只 stdout)。
4xx 不标 ERROR span
@hono/otel 默认按 c.error 把 4xx HTTPException 标 ERROR。按 OTel HTTP 语义,4xx SERVER 不该是 ERROR —— src/index.ts 在 @hono/otel 内侧吃掉 <500 的 HTTPException,只 5xx + 未捕获错误才 captureException(见 API 的错误 span 语义)。
无 user/thread context propagator
authapi 自身是登录服务,请求里没有已验证用户上下文(用户身份在/callback exchange 后才有,按需在那条 log 手动带 user.id)。
CI/CD
.github/workflows/fly-deploy.yml:push 到 main → bun install --frozen-lockfile → bun run typecheck → bun test → flyctl deploy --remote-only → Slack 通知。Fly token 用 secret POISSON_ART_DEPLOY_FLYIO。
上线前 checklist
Fly app + secrets
kira-auth app 已建;fly secrets 含 AUTH_REFRESH_SECRET(新生成)、SUPABASE_ANON_KEY、SUPABASE_KEY。[env] 含 COOKIE_DOMAIN=.kira.art、ALLOWED_REDIRECT_ORIGINS、OTEL_EXPORTER_OTLP_ENDPOINT、NODE_ENV=production、PUBLIC_BASE_URL、SUPABASE_URL。Supabase 回调注册
Supabase Auth → URL Configuration → Redirect URLs 含
https://authapi.kira.art/callback(dev 另加 http://localhost:8095/callback)。Dash0 dashboard + no-data alert
建 authapi overview dashboard + no-data alert:
absent_over_time(dash0.spans SERVER[5m])(rate/threshold alert 在 0 流量时全静默,服务挂反而不报警,必须有 no-data 兜底)。本地开发
COOKIE_DOMAIN 留空 → host-only cookie(localhost:3000 ↔ :8095 同 site,可用)。dev 无 OTEL_EXPORTER_OTLP_ENDPOINT → telemetry no-op,只 stdout。
poisson.art 跨注册域:走同一个
authapi.kira.art,但 SameSite=Lax 的 .kira.art cookie 不会在 poisson 的跨站 /refresh fetch 被带上 → 静默刷新失败、需重登(测试环境可接受)。把 poisson origin 加进 ALLOWED_REDIRECT_ORIGINS(同时管 redirect 白名单 + CORS)。要 poisson 也无感,需把会话 cookie 改 SameSite=None; Secure(见 lib/session.ts 注释,待决策)。