summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--docs/architecture.md6
-rw-r--r--docs/commercial-readiness.md87
2 files changed, 90 insertions, 3 deletions
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`.