From cd0dd91ab93653631904f2ea0e574ccde6d60339 Mon Sep 17 00:00:00 2001 From: Chia Date: Wed, 5 Aug 2026 14:48:00 +1200 Subject: add passkey, totp. --- docs/architecture.md | 6 +-- docs/commercial-readiness.md | 87 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 docs/commercial-readiness.md (limited to 'docs') diff --git a/docs/architecture.md b/docs/architecture.md index 1193151..c17c65e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -42,7 +42,7 @@ flowchart LR | 边界 | 当前实现 | 下一阶段替换 | | --- | --- | --- | | 客户身份 | PostgreSQL 快照、内存 SHA-256 索引 | SSO/OIDC、SCIM、模型 allowlist | -| 控制台权限 | 注册/密码登录、数据库会话、CSRF、六角色 RBAC、租户 SQL scope、审计日志 | SSO/OIDC、MFA、细粒度自定义角色、审批流 | +| 控制台权限 | 邮箱验证/邀请/重置、登录限流、设备会话、TOTP/恢复码、Passkey、CSRF、六角色 RBAC、租户 SQL scope、审计日志 | SSO/OIDC、SCIM、组织级 MFA 策略、自定义角色、审批流 | | 权限 | `Principal.Scopes` 中的 `inference` + 控制台 RBAC | ABAC、IP 与模型策略 | | 模型目录 | PostgreSQL 快照 + 可选 Redis generation 广播 + PG 轮询兜底 | 版本化控制面、热更新、灰度发布 | | 路由 | priority + weighted selection + failover | 健康评分、延迟 EWMA、成本/质量策略、熔断 | @@ -69,13 +69,13 @@ Stripe 充值使用 Checkout Session:本地先创建 top-up order,Stripe 请 ## 管理面安全 -bootstrap token 只映射为 `platform_admin`,用于首次建号和故障恢复,不是日常用户凭证。租户注册在同一 PostgreSQL 事务内创建租户、默认项目、钱包和 `tenant_admin` 账号;密码使用 PBKDF2-HMAC-SHA-256 哈希,服务端只保存盐和摘要。登录创建 HttpOnly、SameSite 会话 Cookie,并为所有写请求校验独立 CSRF Cookie/header;改密和撤销成员会话会立即失效旧会话。平台角色没有 `tenant_id`,租户角色必须绑定一个 tenant。所有管理 API 在 handler 执行前校验 permission,租户过滤在 SQL 查询或资源所有权检查中完成,前端隐藏菜单不承担安全职责。 +bootstrap token 只映射为 `platform_admin`,用于首次建号和故障恢复,不是日常用户凭证。租户注册在同一 PostgreSQL 事务内创建租户、默认项目、钱包和待验证的 `tenant_admin` 账号;邮件动作使用仅保存摘要的一次性 token,邮件正文在 outbox 中加密。密码使用 PBKDF2-HMAC-SHA-256 哈希,TOTP secret、Passkey credential 和 WebAuthn challenge 使用 AES-256-GCM 加密。登录创建 HttpOnly、SameSite 会话 Cookie,并为所有写请求校验独立 CSRF Cookie/header;改密、密码重置和撤销成员会立即失效旧会话。平台角色没有 `tenant_id`,租户角色必须绑定一个 tenant。所有管理 API 在 handler 执行前校验 permission,租户过滤在 SQL 查询或资源所有权检查中完成,前端隐藏菜单不承担安全职责。 每个通过认证的管理请求都写入 `audit_logs`,包含 actor、角色、tenant、action、状态码、请求 ID、IP 和 User-Agent。审计写入失败不会回滚已成功的资源事务,但会输出结构化告警。 ## 建议的后续顺序 -1. 将管理监听端口与公网推理端口分离,并接入 OIDC/SSO、MFA 与短期会话。 +1. 将管理监听端口与公网推理端口分离,并为企业客户接入 OIDC/SAML、SCIM 与组织级强制 MFA 策略。 2. 增加价格版本、退款/冲正、Stripe dispute 处理和供应商日账单对账。 3. 为不返回 usage 的上游增加可靠 token 计算器,并监控 `uncollected_micros`。 4. 把 UsageEvent 做时间分区和归档,增加 CSV 导出与对账作业。 diff --git a/docs/commercial-readiness.md b/docs/commercial-readiness.md new file mode 100644 index 0000000..b78ae2d --- /dev/null +++ b/docs/commercial-readiness.md @@ -0,0 +1,87 @@ +# Commercial readiness gap analysis + +This document compares the current gateway and console with the customer-facing +model catalog at `https://zenmux.ai/models?sort=newest`. It separates working +capabilities from product gaps so an unfinished control is never presented as a +commercial feature. + +## What works now + +- OpenAI Chat Completions and Anthropic Messages proxying, streaming, routing, + retry, authentication, persistent usage, prepaid billing, quotas, rate limits, + concurrent request limits, RBAC, audit logs, and a PostgreSQL-backed console. +- Stripe-hosted Checkout with signed, idempotent Webhook crediting. The gateway + never accepts card details and never credits a success redirect. +- PostgreSQL is the source of truth. Redis accelerates invalidation and shared + counters but is not required for startup, control-plane writes, billing, or + balance correctness. +- Verified self-service registration, invitation acceptance, password reset, + persistent login throttles, per-device session revocation, encrypted email + outbox delivery, TOTP with recovery codes, and WebAuthn Passkeys. + +## Customer product gaps + +### P0 before a public commercial launch + +- Production transactional-email provider selection, domain authentication, + bounce/complaint handling, low-balance notifications, and monitoring for the + durable mail outbox. Local development currently uses Mailpit. +- A public model catalog and detail page containing provider/developer, release + and retirement dates, input/output modalities, context and maximum output, + supported parameters and protocols, regional availability, and versioned price + dimensions. +- Tenant and API-key model allowlists, budget alerts, low-balance notifications, + downloadable invoices/receipts, payment history, refunds/disputes operations, + and explicit tax handling after registrations are confirmed. +- Operational separation of the public inference listener from the management + listener, HTTPS-only cookies behind a trusted proxy, backup/restore drills, + migration rollback policy, secret rotation, and alerting for usage settlement + or Webhook backlogs. +- A durable settlement retry/outbox and reconciliation worker. Persistence and + balance settlement currently use bounded synchronous database calls after the + response; a database timeout is logged but is not queued for retry, so a long + outage can leave reservations pending or usage unbilled. + +### P1 for ZenMux-like breadth + +- OpenAI Responses, Embeddings, Images, Speech and Transcriptions; Gemini native + APIs; rerank and other media endpoints. The existing protocol field does not + make these APIs implemented. +- Provider health measurements per model and route: availability, first-token + latency, throughput, error history, health-aware routing, and customer-visible + status history. +- Provider comparison and price ranges, cache/search/image/audio pricing units, + lifecycle aliases and deprecation notices, searchable filters, release sorting, + SDK examples, and copyable endpoint snippets. +- Usage exports, cost attribution, budgets, scheduled reports, organization + invites, custom roles, OIDC/SAML SSO, SCIM, and support impersonation with + approval and full audit evidence. + +## Environment boundary + +Versioned JSON configuration stores only environment variable names for external +services. Local values live in `.env.debug`, which is ignored by Git and created +with mode `0600`. + +| Integration value | Environment variable | +| --- | --- | +| HTTP listen address | `AIGW_SERVER_ADDRESS` | +| PostgreSQL URLs | `AIGW_DATABASE_URL`, `AIGW_DATABASE_URL_DOCKER` | +| Redis URLs | `AIGW_REDIS_URL`, `AIGW_REDIS_URL_DOCKER` | +| Provider credential encryption | `AIGW_CREDENTIAL_KEY` | +| Bootstrap administrator | `AIGW_ADMIN_TOKEN` | +| Stripe application key | `AIGW_STRIPE_API_KEY` | +| Stripe CLI development key | `AIGW_STRIPE_CLI_API_KEY` | +| Stripe Webhook signing secret | `AIGW_STRIPE_WEBHOOK_SECRET` | +| Stripe result URLs | `AIGW_STRIPE_SUCCESS_URL`, `AIGW_STRIPE_CANCEL_URL` | +| Console public URL | `AIGW_PUBLIC_URL` | +| SMTP endpoint/sender | `AIGW_SMTP_ADDRESS`, `AIGW_SMTP_FROM_ADDRESS` | +| SMTP credentials | `AIGW_SMTP_USERNAME`, `AIGW_SMTP_PASSWORD` | +| WebAuthn RP/origins | `AIGW_WEBAUTHN_RP_ID`, `AIGW_WEBAUTHN_ORIGINS` | +| Static upstream endpoint/key | provider `base_url_env`, `api_key_env` | + +External service values are never embedded in versioned JSON. When mail is +enabled, startup validates the sender and SMTP endpoint; username/password must +either both be provided or both be empty. Production should use authenticated +`starttls` or implicit `tls`; the checked-in local example uses unauthenticated +Mailpit with `tls_mode: none`. -- cgit v1.2.3