eve-fullstack-app-design
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFull-Stack App Design on Eve Horizon
在Eve Horizon上设计全栈应用
Architect applications where the manifest is the blueprint, the platform handles infrastructure, and every design decision is intentional.
构建以清单为蓝图、平台托管基础设施、所有设计决策皆经过深思熟虑的应用。
When to Use
适用场景
Load this skill when:
- Designing a new application from scratch on Eve
- Migrating an existing app onto the platform
- Evaluating whether your current architecture uses Eve's capabilities well
- Planning service topology, database strategy, or deployment pipelines
- Deciding between managed and external services
This skill teaches design thinking for Eve's PaaS layer. For CLI usage and operational detail, load the corresponding eve-se skills (, , , ).
eve-manifest-authoringeve-deploy-debuggingeve-auth-and-secretseve-pipelines-workflows在以下场景中使用本技能:
- 在Eve平台上从零设计新应用
- 将现有应用迁移至Eve平台
- 评估当前架构是否充分利用了Eve的能力
- 规划服务拓扑、数据库策略或部署流水线
- 在托管服务与外部服务之间做决策
本技能教授针对Eve PaaS层的设计思维。如需CLI用法和操作细节,请加载对应的eve-se技能(、、、)。
eve-manifest-authoringeve-deploy-debuggingeve-auth-and-secretseve-pipelines-workflowsThe Manifest as Blueprint
作为蓝图的清单
The manifest () is the single source of truth for your application's shape. Treat it as an architectural document, not just configuration.
.eve/manifest.yaml清单()是应用形态的唯一可信来源。请将其视为架构文档,而非单纯的配置文件。
.eve/manifest.yamlWhat the Manifest Declares
清单声明的内容
| Concern | Manifest Section | Design Decision |
|---|---|---|
| Service topology | | What processes run, how they connect |
| Infrastructure | | Managed DB, ingress, roles |
| Build strategy | | What gets built, where images live |
| Release pipeline | | How code flows from commit to production |
| Environment shape | | Which environments exist, what pipelines they use |
| Agent configuration | | Agent profiles, team dispatch, chat routing |
| Runtime defaults | | Harness, workspace, git policies |
Design principle: If an agent or operator can't understand your app's shape by reading the manifest, the manifest is incomplete.
| 关注点 | 清单章节 | 设计决策 |
|---|---|---|
| 服务拓扑 | | 运行哪些进程、进程间如何连接 |
| 基础设施 | | 托管数据库、入口规则、角色配置 |
| 构建策略 | | 构建内容、镜像存储位置 |
| 发布流水线 | | 代码从提交到生产环境的流转路径 |
| 环境形态 | | 存在哪些环境、各环境使用的流水线 |
| Agent配置 | | Agent配置文件、团队调度、聊天路由 |
| 运行时默认值 | | 资源调度、工作区、Git策略 |
设计原则:如果Agent或运维人员无法通过阅读清单理解应用的形态,说明清单不够完整。
Service Topology
服务拓扑
Choose Your Services
选择服务模式
Most Eve apps follow one of these patterns:
API + Database (simplest):
services:
api: # HTTP service with ingress
db: # managed PostgresAPI + Worker + Database:
services:
api: # HTTP service (user-facing)
worker: # Background processor (jobs, queues)
db: # managed PostgresMulti-Service:
services:
web: # Frontend/SSR
api: # Backend API
worker: # Background jobs
db: # managed Postgres
redis: # external cache (x-eve.external: true)大多数Eve应用遵循以下模式之一:
API + 数据库(最简模式):
services:
api: # 带Ingress的HTTP服务
db: # 托管PostgresAPI + Worker + 数据库:
services:
api: # 面向用户的HTTP服务
worker: # 后台处理器(任务、队列)
db: # 托管Postgres多服务模式:
services:
web: # 前端/SSR服务
api: # 后端API
worker: # 后台任务
db: # 托管Postgres
redis: # 外部缓存(设置`x-eve.external: true`)Service Design Rules
服务设计规则
- One concern per service. Separate HTTP serving from background processing. An API service should not also run scheduled jobs.
- Use managed DB for Postgres. Declare and let the platform provision, connect, and inject credentials. No manual connection strings.
x-eve.role: managed_db - Mark external services explicitly. Use with
x-eve.external: truefor services hosted outside Eve (Redis, third-party APIs).x-eve.connection_url - Use for one-off tasks. Migrations, seeds, and data backfills are job services, not persistent processes.
x-eve.role: job - Expose ingress intentionally. Only services that need external HTTP access get . Internal services communicate via cluster networking.
x-eve.ingress.public: true - Choose a hostname strategy early. Every public service gets a generated platform URL by default. Layer on for a friendlier platform-subdomain (
x-eve.ingress.alias), oringest.eve.example.comto bring your own domain. Custom domains are env-scoped and first-bind-wins — design which environment owns the apex (usuallyx-eve.ingress.domains: [limelee.com]) before declaring it. Seeproductionandeve-manifest-authoringfor declaration and DNS verification flow.eve-deploy-debugging
- 单一职责原则:将HTTP服务与后台处理分离。API服务不应同时运行定时任务。
- 使用托管Postgres数据库:声明,由平台负责数据库的部署、连接和凭证注入,无需手动配置连接字符串。
x-eve.role: managed_db - 显式标记外部服务:对于Eve平台外的服务(如Redis、第三方API),需设置并配置
x-eve.external: true。x-eve.connection_url - 用定义一次性任务:数据迁移、初始化填充等属于任务服务,而非持久运行进程。
x-eve.role: job - 谨慎配置Ingress:仅需对外提供HTTP访问的服务设置,内部服务通过集群网络通信。
x-eve.ingress.public: true - 提前确定主机名策略:默认情况下,每个公共服务会获得平台生成的URL。可通过设置更友好的平台子域名(如
x-eve.ingress.alias),或通过ingest.eve.example.com绑定自定义域名。自定义域名按环境划分,先绑定者生效——在声明前需确定哪个环境(通常是x-eve.ingress.domains: [limelee.com])拥有主域名。具体声明和DNS验证流程请参考production和eve-manifest-authoring。eve-deploy-debugging
Stable Outbound IPs (Egress)
稳定出口IP(Egress)
Most apps don't care about their outbound source IP — but if you integrate with vendors that allowlist source IPs (cameras, payment processors, partner APIs with strict source-IP rules), declare opt-in stable egress at the service level. The platform schedules the pod onto a public-egress node group with , giving the service a stable, predictable outbound path instead of a shared NAT mapping. Treat this as a deliberate architectural choice for the one or two services that need it — not a default.
hostNetwork: true大多数应用无需关注出口源IP,但如果您的应用需要与限制源IP的供应商集成(如摄像头、支付处理器、有严格源IP规则的合作API),可在服务级别声明启用稳定出口。平台会将Pod调度到启用的公共出口节点组,为服务提供稳定、可预测的出口路径,而非共享NAT映射。请将此视为针对特定服务的刻意架构选择,而非默认配置。
hostNetwork: trueApp Object Storage
应用对象存储
Apps that need to store files (uploads, avatars, exports) can declare object store buckets in the manifest:
yaml
services:
api:
x-eve:
object_store:
buckets:
- name: uploads
visibility: private
- name: avatars
visibility: publicNote: The database schema for app object stores exists, but automatic provisioning from the manifest is not yet wired. Seefor current status.references/object-store-filesystem.md
When wired, the platform injects , , , , and into the service container.
STORAGE_ENDPOINTSTORAGE_ACCESS_KEYSTORAGE_SECRET_KEYSTORAGE_BUCKETSTORAGE_FORCE_PATH_STYLECredential isolation: app pods receive app-scoped storage credentials, not platform-internal credentials. A compromised app service can't reach platform buckets or other tenants' data. Design with this boundary in mind — don't try to share credentials across apps; declare each app's buckets and let the platform issue scoped keys.
需要存储文件(上传内容、头像、导出文件)的应用可在清单中声明对象存储桶:
yaml
services:
api:
x-eve:
object_store:
buckets:
- name: uploads
visibility: private
- name: avatars
visibility: public注意:应用对象存储的数据库架构已存在,但目前尚未实现从清单自动创建存储桶的功能。请查看了解当前状态。references/object-store-filesystem.md
功能完善后,平台会将、、、和注入服务容器。
STORAGE_ENDPOINTSTORAGE_ACCESS_KEYSTORAGE_SECRET_KEYSTORAGE_BUCKETSTORAGE_FORCE_PATH_STYLE凭证隔离:应用Pod会收到应用级的存储凭证,而非平台内部凭证。即使应用服务被攻陷,也无法访问平台存储桶或其他租户的数据。设计时需注意此边界——不要尝试跨应用共享凭证,应为每个应用单独声明存储桶,由平台颁发范围限定的密钥。
Cloud FS / Google Drive Storage
云文件系统/Google Drive存储
For document-oriented storage, use cloud FS mounts. Each org connects its own Google Drive via BYOA OAuth credentials, then mounts folders into the org filesystem:
bash
eve integrations configure google-drive --client-id "..." --client-secret "..."
eve integrations connect google-drive
eve cloud-fs mount --org org_xxx --provider google-drive --folder-id <id> --label "Shared Drive"Apps can browse and search mounted Drive content through Eve's Cloud FS surface (, , and the per-mount Cloud FS API routes). This is complementary to object store buckets -- use cloud FS for shared documents and collaboration, use object store for app-managed binary assets.
eve cloud-fs lseve cloud-fs search对于面向文档的存储,可使用云文件系统挂载。每个组织可通过BYOA OAuth凭证连接自己的Google Drive,然后将文件夹挂载到组织文件系统:
bash
eve integrations configure google-drive --client-id "..." --client-secret "..."
eve integrations connect google-drive
eve cloud-fs mount --org org_xxx --provider google-drive --folder-id <id> --label "Shared Drive"应用可通过Eve的Cloud FS界面(、以及每个挂载点的Cloud FS API路由)浏览和搜索挂载的Drive内容。这与对象存储桶互为补充——使用云文件系统存储共享文档和协作内容,使用对象存储存储应用管理的二进制资产。
eve cloud-fs lseve cloud-fs searchPlatform-Injected Variables
平台注入的变量
Every deployed service receives , , , , and . Use for server-to-server calls. Use for browser-facing code. Design your app to read these rather than hardcoding URLs.
EVE_API_URLEVE_PUBLIC_API_URLEVE_PROJECT_IDEVE_ORG_IDEVE_ENV_NAMEEVE_API_URLEVE_PUBLIC_API_URL每个部署的服务都会收到、、、和。用于服务器间调用,用于浏览器端代码。设计应用时请读取这些变量,而非硬编码URL。
EVE_API_URLEVE_PUBLIC_API_URLEVE_PROJECT_IDEVE_ORG_IDEVE_ENV_NAMEEVE_API_URLEVE_PUBLIC_API_URLReference Architecture: SPA + API + Managed DB
参考架构:SPA + API + 托管数据库
Use a public nginx SPA to proxy to an internal Node service, backed by
managed Postgres and a one-off migration job. This keeps the API off public
ingress and gives the browser same-origin access.
/api/Load for the complete manifest, nginx
template, Dockerfiles, migration layout, managed TLS rules, and transaction-
scoped RLS implementation.
references/spa-api-managed-db.md使用公共Nginx SPA将请求代理到内部Node服务,后端使用托管Postgres和一次性迁移任务。这种架构可避免API暴露到公共Ingress,并为浏览器提供同源访问权限。
/api/加载获取完整清单、Nginx模板、Dockerfile、迁移目录结构、托管TLS规则以及事务范围的RLS实现细节。
references/spa-api-managed-db.mdDatabase Design
数据库设计
Declare Postgres with and consume
. Keep its managed ; the platform
injects the trust bundle and client environment. Never disable certificate
verification.
x-eve.role: managed_db${managed.db.url}sslmode=verify-fullUse timestamped plain-SQL migrations, design tenant-owned tables with
and RLS from the start, and set tenant context inside a
transaction before every query. Inspect before changing with
and . Keep product data separate from agent memory and
coordination storage.
org_id TEXT NOT NULLeve db schemaeve db sql --env <env>Load for the managed DB declaration,
transaction wrapper, RLS policy template, and access conventions.
references/spa-api-managed-db.md通过声明Postgres数据库,并使用连接。请保持默认的配置,平台会注入信任证书和客户端环境。切勿禁用证书验证。
x-eve.role: managed_db${managed.db.url}sslmode=verify-full使用带时间戳的纯SQL迁移脚本,从一开始就为租户所属表设计字段和RLS,并在每次查询前的事务中设置租户上下文。修改前可通过和检查数据库状态。请将产品数据与Agent内存和协调存储分开。
org_id TEXT NOT NULLeve db schemaeve db sql --env <env>加载获取托管数据库声明、事务包装器、RLS策略模板和访问约定。
references/spa-api-managed-db.mdBuild and Release Pipeline
构建与发布流水线
The Canonical Flow
标准流程
Every production app should follow :
build → release → deploy → migrate → smoke-testyaml
pipelines:
deploy:
steps:
- name: build
action:
type: build # Creates BuildSpec + BuildRun, produces image digests
- name: release
depends_on: [build]
action:
type: release # Creates immutable release from build artifacts
- name: deploy
depends_on: [release]
action:
type: deploy # Deploys release to target environment
- name: migrate
depends_on: [deploy]
action:
type: job
service: migrate # Runs eve-migrate against the managed DB
- name: smoke-test
depends_on: [migrate]
script:
run: ./scripts/smoke-test.sh
timeout: 300Why this order matters:
- produces SHA256 image digests.
buildpins those exact digests.releaseuses the pinned release. You deploy exactly what you built — no tag drift, no "latest" surprises.deploy - runs after deploy because the managed DB must be provisioned first. The eve-migrate job applies any pending SQL migrations.
migrate - validates the deployed services end-to-end before the pipeline reports success.
smoke-test
每个生产应用应遵循的流程:
构建 → 发布 → 部署 → 迁移 → 冒烟测试yaml
pipelines:
deploy:
steps:
- name: build
action:
type: build # 创建BuildSpec + BuildRun,生成镜像摘要
- name: release
depends_on: [build]
action:
type: release # 基于构建产物创建不可变的发布版本
- name: deploy
depends_on: [release]
action:
type: deploy # 将发布版本部署到目标环境
- name: migrate
depends_on: [deploy]
action:
type: job
service: migrate # 针对托管数据库运行eve-migrate
- name: smoke-test
depends_on: [migrate]
script:
run: ./scripts/smoke-test.sh
timeout: 300此顺序的重要性:
- 生成SHA256镜像摘要,
build固定这些摘要,release使用固定的发布版本。确保部署的内容与构建的内容完全一致,避免标签漂移或“latest”镜像带来的意外。deploy - 在
migrate之后运行,因为托管数据库必须先完成部署。eve-migrate任务会应用所有待处理的SQL迁移。deploy - 会在流水线报告成功前对部署的服务进行端到端验证。
smoke-test
Registry Decisions
镜像仓库选择
| Option | When to Use |
|---|---|
| Default. Internal registry with JWT auth. Simplest setup. |
| BYO registry (GHCR, ECR) | When you need images accessible outside Eve, or have existing CI. |
| Public base images only. No custom builds. |
For GHCR, add OCI labels to Dockerfiles for automatic repository linking:
dockerfile
LABEL org.opencontainers.image.source="https://github.com/YOUR_ORG/YOUR_REPO"| 选项 | 适用场景 |
|---|---|
| 默认选项。带JWT认证的内部仓库,设置最简单。 |
| 自定义仓库(GHCR、ECR) | 需要镜像可在Eve外部访问,或已有CI流程时使用。 |
| 仅使用公共基础镜像,无需自定义构建。 |
若使用GHCR,请在Dockerfile中添加OCI标签以实现自动仓库关联:
dockerfile
LABEL org.opencontainers.image.source="https://github.com/YOUR_ORG/YOUR_REPO"Build Configuration
构建配置
Every service with a custom image needs a section:
buildyaml
services:
api:
build:
context: ./apps/api
dockerfile: Dockerfile
image: ghcr.io/org/my-apiUse multi-stage Dockerfiles. BuildKit handles them natively. Place the OCI label on the final stage.
每个需要自定义镜像的服务都需要章节:
buildyaml
services:
api:
build:
context: ./apps/api
dockerfile: Dockerfile
image: ghcr.io/org/my-api使用多阶段Dockerfile,BuildKit原生支持该特性。请在最终阶段添加OCI标签。
Deployment and Environments
部署与环境
Environment Strategy
环境策略
| Environment | Type | Purpose | Pipeline |
|---|---|---|---|
| persistent | Integration testing, demos | |
| persistent | Live traffic | |
| temporary | PR previews, feature branches | |
Link each environment to a pipeline in the manifest:
yaml
environments:
staging:
pipeline: deploy
production:
pipeline: deploy| 环境 | 类型 | 用途 | 流水线 |
|---|---|---|---|
| 持久化 | 集成测试、演示 | |
| 持久化 | 生产流量 | |
| 临时 | PR预览、特性分支 | |
在清单中为每个环境关联流水线:
yaml
environments:
staging:
pipeline: deploy
production:
pipeline: deployDeployment Patterns
部署模式
Standard deploy: triggers the linked pipeline.
eve env deploy staging --ref main --repo-dir .Direct deploy (bypass pipeline): for emergencies or simple setups.
eve env deploy staging --ref <sha> --directPromotion: Build once in staging, then promote the same release artifacts to production. The build step's digests carry forward, guaranteeing identical images.
标准部署:触发关联的流水线。
eve env deploy staging --ref main --repo-dir .直接部署(跳过流水线):用于紧急情况或简单部署场景。
eve env deploy staging --ref <sha> --direct版本推广:在staging环境构建一次,然后将相同的发布产物推广到production环境。构建步骤的镜像摘要会被保留,确保镜像完全一致。
Recovery
故障恢复
When a deploy fails:
- Diagnose: — shows health, recent deploys, service status.
eve env diagnose <project> <env> - Logs: — container output.
eve env logs <project> <env> - Rollback: Redeploy the previous known-good release.
- Reset: — nuclear option, reprovisions from scratch.
eve env reset <project> <env>
Design your app to be rollback-safe: migrations should be forward-compatible, and services should handle schema version mismatches gracefully during rolling deploys.
部署失败时:
- 诊断:—— 查看健康状态、最近部署记录、服务状态。
eve env diagnose <project> <env> - 日志:—— 查看容器输出。
eve env logs <project> <env> - 回滚:重新部署上一个已知可用的版本。
- 重置:—— 终极方案,重新从零部署环境。
eve env reset <project> <env>
设计应用时需确保支持回滚:迁移脚本需向前兼容,服务需能在滚动部署期间优雅处理架构版本不匹配的情况。
The System App Pattern
系统应用模式
Platform-tier and admin apps deploy through the same Eve pipeline as customer apps — no special path. The Eve Dashboard is the canonical example: it ships through the standard build → release → deploy flow, sits in the CI publish matrix alongside other apps, and consumes the same SSO + analytics APIs any customer app would. If you're building an internal admin console, a control plane for your own platform, or a system-tier surface, adopt this pattern. The win is parity: one deployment story, one auth story, one observability story across all your apps. Avoid carving out bespoke "platform-only" deploy paths — they rot and diverge.
平台级和管理应用与客户应用通过相同的Eve流水线部署——无需特殊路径。Eve Dashboard就是典型示例:它通过标准的流程发布,与其他应用一起纳入CI发布矩阵,并使用所有客户应用都能访问的SSO + 分析API。如果您正在构建内部管理控制台、自有平台的控制平面或系统级界面,请采用此模式。优势在于一致性:所有应用使用相同的部署流程、认证流程和可观测性流程。避免定制“仅平台可用”的部署路径——这类路径会逐渐过时并与标准流程脱节。
构建 → 发布 → 部署Per-Org OAuth for App Integrations
应用集成的按组织OAuth
Apps that integrate with Google Drive, Slack, or other OAuth providers use per-org credentials (BYOA -- Bring Your Own App). Each org registers its own OAuth app, giving it control over branding, scopes, rate limits, and credential rotation.
bash
eve integrations configure google-drive --client-id "..." --client-secret "..."
eve integrations connect google-driveDesign implications: Apps that consume Google Drive data or Slack messages should reference integration tokens through the Eve API, not store OAuth credentials themselves. The platform handles token refresh using the org's registered OAuth app credentials.
与Google Drive、Slack或其他OAuth供应商集成的应用使用按组织划分的凭证(BYOA——Bring Your Own App)。每个组织注册自己的OAuth应用,从而控制品牌、权限范围、速率限制和凭证轮换。
bash
eve integrations configure google-drive --client-id "..." --client-secret "..."
eve integrations connect google-drive设计影响:使用Google Drive数据或Slack消息的应用应通过Eve API引用集成令牌,而非自行存储OAuth凭证。平台会使用组织注册的OAuth应用凭证处理令牌刷新。
Event Triggers for Workflows
工作流的事件触发
Workflows can be triggered by platform events, enabling reactive automation:
yaml
workflows:
on-deploy:
trigger:
system.event: environment.deployed
steps:
- name: smoke-test
script:
run: ./scripts/smoke-test.sh
on-ingest:
trigger:
system.event: doc.ingest.completed
steps:
- name: process
agent: doc-processorEvent sources include: GitHub webhooks, Slack events, system events (deploy, build, ingest), cron schedules, and manual triggers. See for trigger syntax and for the full event catalog.
eve-pipelines-workflowsreferences/events.md工作流可由平台事件触发,实现响应式自动化:
yaml
workflows:
on-deploy:
trigger:
system.event: environment.deployed
steps:
- name: smoke-test
script:
run: ./scripts/smoke-test.sh
on-ingest:
trigger:
system.event: doc.ingest.completed
steps:
- name: process
agent: doc-processor事件源包括:GitHub webhook、Slack事件、系统事件(部署、构建、导入)、定时任务和手动触发。请查看了解触发语法,查看获取完整事件目录。
eve-pipelines-workflowsreferences/events.mdApp CLI Framework — The Eve Way
应用CLI框架——Eve风格
Every app with an API should ship a CLI. This is the Eve way — agents interact with app data through CLI commands, not raw REST calls. A CLI gives agents discoverable, auth-transparent, type-safe access to your app's domain. It reduces LLM calls per operation from 3-5 (curl) to 1 (CLI command), eliminates URL construction and JSON quoting, and surfaces domain-specific error messages instead of HTTP status codes.
每个带API的应用都应提供CLI。这是Eve的标准做法——Agent通过CLI命令与应用数据交互,而非直接调用REST接口。CLI为Agent提供可发现、认证透明、类型安全的应用领域访问方式。它将每个操作的LLM调用次数从3-5次(curl方式)减少到1次(CLI命令),无需构造URL和转义JSON,并提供领域特定的错误信息而非HTTP状态码。
Why CLI-First Matters
CLI优先的重要性
When a coding agent needs to read or write app data, it faces a choice: construct a curl command with the right URL, auth header, and JSON body — or run . The CLI approach wins on every dimension:
eden projects list --json| Dimension | CLI | Raw REST |
|---|---|---|
| Auth | Invisible ( | Manual header construction |
| URL | None (CLI knows the service URL) | Build from |
| Discoverability | | Read OpenAPI spec or docs |
| Errors | Domain-specific messages | HTTP status codes |
| LLM cost | 1 call per operation | 3-5 calls per operation |
当编码Agent需要读写应用数据时,它有两种选择:构造包含正确URL、认证头和JSON体的curl命令,或运行。CLI方式在各维度都更具优势:
eden projects list --json| 维度 | CLI | 原生REST |
|---|---|---|
| 认证 | 自动处理(自动读取 | 手动构造请求头 |
| URL | 无需构造(CLI知晓服务URL) | 从 |
| 可发现性 | | 阅读OpenAPI规范或文档 |
| 错误处理 | 领域特定消息 | HTTP状态码 |
| LLM成本 | 每个操作1次调用 | 每个操作3-5次调用 |
Declare the CLI in the Manifest
在清单中声明CLI
yaml
services:
api:
x-eve:
api_spec:
type: openapi
cli:
name: myapp # Binary name on $PATH
bin: cli/bin/myapp # Pre-bundled executable (repo-bundled mode)The platform auto-discovers services with from the manifest and makes them available on for all agent jobs in the project — no explicit needed. Just declare the CLI in the manifest and every agent gets it. Agents run to discover capabilities. See for declaration details and for the full implementation pattern (bundling, env var contract, testing).
x-eve.cli$PATHwith_apismyapp --helpeve-manifest-authoringreferences/app-cli.mdyaml
services:
api:
x-eve:
api_spec:
type: openapi
cli:
name: myapp # $PATH中的二进制文件名
bin: cli/bin/myapp # 预打包的可执行文件(仓库打包模式)平台会自动从清单中发现带有的服务,并将其添加到项目中所有Agent任务的——无需显式配置。只需在清单中声明CLI,所有Agent即可使用。Agent可通过发现功能。请查看了解声明细节,查看获取完整实现模式(打包、环境变量约定、测试)。
x-eve.cli$PATHwith_apismyapp --helpeve-manifest-authoringreferences/app-cli.mdDesign Guidance
设计指南
- Build the CLI early. Don't wait until the API is "done." Start the CLI alongside the first API endpoints. Agents will use it immediately.
- Mirror the API surface. Every REST endpoint should have a CLI subcommand. →
GET /items,myapp items list→POST /items.myapp items create --file data.json - Support everywhere. Default output is human-readable tables;
--jsongives machine-readable output for agent pipelines.--json - Bundle as a single file. Use esbuild to produce a self-contained Node.js script committed to the repo. Zero startup latency.
- Point agent skills at the CLI. Skill instructions should say "Use ", never "curl the API at..."
myapp items list
- 尽早构建CLI:不要等到API“完成”才开始。在开发第一个API端点时就同步开发CLI,Agent会立即使用它。
- 镜像API界面:每个REST端点都应有对应的CLI子命令。例如对应
GET /items,myapp items list对应POST /items。myapp items create --file data.json - 全局支持参数:默认输出为人类可读的表格,
--json参数提供机器可读的输出以支持Agent流水线。--json - 打包为单文件:使用esbuild生成独立的Node.js脚本并提交到仓库,实现零启动延迟。
- 引导Agent技能使用CLI:技能说明应写“使用”,而非“调用API的...接口”。
myapp items list
Embedded Conversations
嵌入式对话
If your app has a chat surface — a sidebar pane, an inline assistant, an "ask about this object" button — use Eve's embedded conversation API and chat SDK. Don't hand-roll auth, dispatch, SSE, reconnect, or optimistic-send. The platform exposes find-or-create thread routing keyed by an app-supplied identifier (e.g. ), JWKS-verified browser tokens, and a replayable SSE stream — composed into and for ~50 lines of UI code.
myapp:{project_id}:{conversation_id}@eve-horizon/chat@eve-horizon/chat-reactDesign implications:
- Map your product objects (a document, a project, a ticket) to Eve threads by stable key. The platform owns thread state; your app owns product projections that reference .
thread_id - Route through , an agent, a team, or a workflow using the same primitives external gateways use. Chat is just another dispatch target.
chat.yaml - Phase 1 push uses SSE with snapshot + polling catch-up; design your UI to tolerate brief reconnects rather than assuming a persistent socket.
For SDK shape and routing patterns, see in the skill.
references/eve-sdk.mdeve-read-eve-docs如果您的应用包含聊天界面——侧边栏、内嵌助手、“询问此对象”按钮,请使用Eve的嵌入式对话API和聊天SDK。无需自行实现认证、调度、SSE、重连或乐观发送逻辑。平台提供基于应用提供的标识符(如)的查找或创建线程路由、JWKS验证的浏览器令牌,以及可重放的SSE流——这些功能已整合到和中,只需约50行UI代码即可实现。
myapp:{project_id}:{conversation_id}@eve-horizon/chat@eve-horizon/chat-react设计影响:
- 将产品对象(文档、项目、工单)通过稳定的键映射到Eve线程。平台负责线程状态,应用负责存储引用的产品投影。
thread_id - 使用与外部网关相同的原语,通过、Agent、团队或工作流进行路由。聊天只是另一个调度目标。
chat.yaml - 第一阶段推送使用SSE加快照+轮询补全机制;设计UI时需容忍短暂的重连,而非假设连接始终保持。
有关SDK形态和路由模式,请查看技能中的。
eve-read-eve-docsreferences/eve-sdk.mdApp Undeploy/Delete Lifecycle
应用卸载/删除生命周期
Manage the full lifecycle of environments and projects:
bash
undefined管理环境和项目的完整生命周期:
bash
undefinedUndeploy services (stops pods, keeps env record and history)
卸载服务(停止Pod,保留环境记录和历史)
eve env undeploy <project> <env>
eve env undeploy <project> <env>
Delete environment entirely (cascades to managed DB, secrets)
完全删除环境(级联删除托管数据库、密钥)
eve env delete <project> <env>
eve env delete <project> <env>
Delete project (cascades to all environments, artifacts, history)
删除项目(级联删除所有环境、产物、历史)
eve project delete <project-id>
Design your app for clean teardown: migrations should be idempotent, managed DB deletion is irreversible, and pipeline history is preserved in audit logs even after environment deletion.eve project delete <project-id>
设计应用时需支持干净的销毁:迁移脚本需具备幂等性,托管数据库删除不可恢复,流水线历史会保留在审计日志中即使环境已删除。Secrets and Configuration
密钥与配置
Scoping Model
作用域模型
Secrets resolve with cascading precedence: project > user > org > system. A project-level overrides an org-level .
API_KEYAPI_KEY密钥解析遵循级联优先级:项目 > 用户 > 组织 > 系统。项目级的会覆盖组织级的。
API_KEYAPI_KEYDesign Rules
设计规则
- Set secrets per-project. Use . Keep project secrets self-contained.
eve secrets set KEY "value" --project proj_xxx - Use interpolation in the manifest. Reference in service environment blocks. The platform resolves at deploy time.
${secret.KEY} - Validate before deploying. Run to catch missing secret references before they cause deploy failures.
eve manifest validate --validate-secrets - Use for local development. Mirror the production secret keys with local values. This file is gitignored.
.eve/dev-secrets.yaml - Never store secrets in environment variables directly. Always use interpolation. This ensures secrets flow through the platform's resolution and audit chain.
${secret.KEY}
- 按项目设置密钥:使用,保持项目密钥独立。
eve secrets set KEY "value" --project proj_xxx - 在清单中使用插值:在服务环境块中引用,平台会在部署时解析。
${secret.KEY} - 部署前验证:运行检查缺失的密钥引用,避免部署失败。
eve manifest validate --validate-secrets - 使用进行本地开发:镜像生产环境的密钥键名,设置本地值。此文件需加入git忽略。
.eve/dev-secrets.yaml - 切勿直接将密钥存储在环境变量中:始终使用插值,确保密钥通过平台的解析和审计流程流转。
${secret.KEY}
Service Tokens (Manifest-Declared, Read-Only by Default)
服务令牌(清单声明,默认只读)
Services that call the Eve API on their own behalf get an auto-injected . Permissions are declared explicitly per service in the manifest, and the default is read-only — services that need to write must opt in. Treat this as a least-privilege contract: a service shouldn't quietly gain write access by being deployed. Declare the minimum capabilities each service needs and let code review surface the deltas. See and in for declaration syntax.
EVE_SERVICE_TOKENreferences/secrets-auth.mdreferences/manifest.mdeve-read-eve-docs需要自行调用Eve API的服务会自动注入。权限需在清单中按服务显式声明,默认权限为只读——需要写入权限的服务需主动开启。请将此视为最小权限约定:服务不应因部署而自动获得写入权限。为每个服务声明所需的最小权限,代码评审时可关注权限变更。请查看中的和了解声明语法。
EVE_SERVICE_TOKENeve-read-eve-docsreferences/secrets-auth.mdreferences/manifest.mdScoped Job Tokens (Platform-Tier Least Privilege)
作用域限定的任务令牌(平台级最小权限)
For platform-tier apps that orchestrate jobs over multi-tenant resources, permission names alone are not enough — says nothing about which prefix. Declare resource scope on workflow steps to enforce least-privilege at the token level:
orgfs:readyaml
workflows:
scoped-review:
scope:
orgfs: { allow_prefixes: [/groups/projects/proj-a/**] }
steps:
- name: review
agent: { name: reviewer }
scope:
cloud_fs: { allow_mount_ids: [mount_a] }Scope axes match access bindings: , , , . Workflow, step, and invocation scopes are intersected (empty intersection fails closed) and persisted as . The orchestrator uses the same scope to build the workspace mount and mint the job token — the on-disk view and the API authority match. Design platform-tier workflows so each step only sees the resources it actually needs.
orgfsorgdocsenvdbcloud_fsjobs.token_scope.org对于在多租户资源上编排任务的平台级应用,仅靠权限名称不足以实现最小权限——并未指定哪个路径前缀。请在工作流步骤中声明资源作用域,在令牌层面强制执行最小权限:
orgfs:readyaml
workflows:
scoped-review:
scope:
orgfs: { allow_prefixes: [/groups/projects/proj-a/**] }
steps:
- name: review
agent: { name: reviewer }
scope:
cloud_fs: { allow_mount_ids: [mount_a] }作用域维度与访问绑定一致:、、、。工作流、步骤和调用的作用域会相交(空交集会导致失败),并以的形式持久化。编排器会使用相同的作用域构建工作区挂载并生成任务令牌——磁盘视图与API权限保持一致。设计平台级工作流时,应确保每个步骤仅能访问实际需要的资源。
orgfsorgdocsenvdbcloud_fsjobs.token_scope.orgGit Credentials
Git凭证
Agents need repository access. Set either (HTTPS) or (SSH) as project secrets. The worker injects these automatically during git operations.
github_tokenssh_keyAgent需要仓库访问权限。请将(HTTPS方式)或(SSH方式)设置为项目密钥。Worker会在Git操作期间自动注入这些凭证。
github_tokenssh_keySSO Authentication
SSO认证
Adding SSO to Your App
为应用添加SSO
Eve provides shared auth packages that eliminate boilerplate. Add Eve SSO login in ~25 lines of code.
Backend ():
@eve-horizon/authtypescript
import { eveUserAuth, eveAuthGuard, eveAuthConfig } from '@eve-horizon/auth';
app.use(eveUserAuth()); // Parse tokens (non-blocking)
app.get('/auth/config', eveAuthConfig()); // Serve SSO discovery
app.get('/auth/me', eveAuthGuard(), (req, res) => {
res.json(req.eveUser); // { id, email, orgId, role }
});
app.use('/api', eveAuthGuard()); // Protect all API routesFrontend ():
@eve-horizon/auth-reacttsx
import { EveAuthProvider, EveLoginGate } from '@eve-horizon/auth-react';
function App() {
return (
<EveAuthProvider apiUrl="/api">
<EveLoginGate>
<ProtectedApp />
</EveLoginGate>
</EveAuthProvider>
);
}For authenticated API calls from components, use :
createEveClienttypescript
import { createEveClient } from '@eve-horizon/auth-react';
const client = createEveClient('/api');
const res = await client.fetch('/data');Custom auth gate — When you need control over loading and login states (custom login page, richer loading UI), use directly instead of :
useEveAuth()EveLoginGatetsx
import { EveAuthProvider, useEveAuth } from '@eve-horizon/auth-react';
function AuthGate() {
const { user, loading, loginWithToken, loginWithSso, logout } = useEveAuth();
if (loading) return <Spinner />;
if (!user) return <LoginPage onSso={loginWithSso} onToken={loginWithToken} />;
return <AppShell user={user} onLogout={logout}><Routes /></AppShell>;
}
export default function App() {
return (
<EveAuthProvider apiUrl={API_BASE}>
<AuthGate />
</EveAuthProvider>
);
}Eve提供共享认证包,可消除重复代码。只需约25行代码即可添加Eve SSO登录功能。
后端():
@eve-horizon/authtypescript
import { eveUserAuth, eveAuthGuard, eveAuthConfig } from '@eve-horizon/auth';
app.use(eveUserAuth()); // 解析令牌(非阻塞)
app.get('/auth/config', eveAuthConfig()); // 提供SSO发现信息
app.get('/auth/me', eveAuthGuard(), (req, res) => {
res.json(req.eveUser); // { id, email, orgId, role }
});
app.use('/api', eveAuthGuard()); // 保护所有API路由前端():
@eve-horizon/auth-reacttsx
import { EveAuthProvider, EveLoginGate } from '@eve-horizon/auth-react';
function App() {
return (
<EveAuthProvider apiUrl="/api">
<EveLoginGate>
<ProtectedApp />
</EveLoginGate>
</EveAuthProvider>
);
}若要从组件中调用认证后的API,请使用:
createEveClienttypescript
import { createEveClient } from '@eve-horizon/auth-react';
const client = createEveClient('/api');
const res = await client.fetch('/data');自定义认证网关——当您需要控制加载和登录状态(自定义登录页面、更丰富的加载UI)时,请直接使用而非:
useEveAuth()EveLoginGatetsx
import { EveAuthProvider, useEveAuth } from '@eve-horizon/auth-react';
function AuthGate() {
const { user, loading, loginWithToken, loginWithSso, logout } = useEveAuth();
if (loading) return <Spinner />;
if (!user) return <LoginPage onSso={loginWithSso} onToken={loginWithToken} />;
return <AppShell user={user} onLogout={logout}><Routes /></AppShell>;
}
export default function App() {
return (
<EveAuthProvider apiUrl={API_BASE}>
<AuthGate />
</EveAuthProvider>
);
}How It Works
工作原理
- checks
EveAuthProviderfor cached tokensessionStorage - If no token, probes SSO broker (root-domain cookie)
/session - If SSO session exists, gets fresh Eve RS256 token
- If no session, shows login form (SSO redirect or token paste)
- All API requests include
Authorization: Bearer <token>
- 检查
EveAuthProvider中是否有缓存的令牌sessionStorage - 如果没有令牌,探测SSO代理的接口(根域Cookie)
/session - 如果存在SSO会话,获取新的Eve RS256令牌
- 如果没有会话,显示登录表单(SSO重定向或令牌粘贴)
- 所有API请求都会包含头
Authorization: Bearer <token>
NestJS Backend
NestJS后端
Apply as global middleware in . If existing controllers expect rather than , add a thin bridge that maps Eve roles to app-specific roles in one place:
eveUserAuth()main.tsreq.userreq.eveUsertypescript
import { eveUserAuth } from '@eve-horizon/auth';
app.use(eveUserAuth());
app.use((req, _res, next) => {
if (req.eveUser) {
req.user = { ...req.eveUser, role: req.eveUser.role === 'member' ? 'viewer' : 'admin' };
}
next();
});在中全局应用中间件。如果现有控制器期望而非,可添加一个简单的桥接中间件,在一处将Eve角色映射为应用特定角色:
main.tseveUserAuth()req.userreq.eveUsertypescript
import { eveUserAuth } from '@eve-horizon/auth';
app.use(eveUserAuth());
app.use((req, _res, next) => {
if (req.eveUser) {
req.user = { ...req.eveUser, role: req.eveUser.role === 'member' ? 'viewer' : 'admin' };
}
next();
});Auto-Injected Variables
自动注入的变量
The platform injects , , , and into deployed containers. No manual configuration needed. Use in manifest env blocks for frontend-accessible SSO URLs. is what enables the platform to scope branding, redirect allowlists, and app-scoped auth policy to your project.
EVE_SSO_URLEVE_API_URLEVE_ORG_IDEVE_PROJECT_ID${SSO_URL}EVE_PROJECT_ID平台会将、、和注入部署的容器,无需手动配置。在清单的环境块中使用供前端访问SSO URL。用于平台将品牌、重定向允许列表和应用级认证策略限定到您的项目。
EVE_SSO_URLEVE_API_URLEVE_ORG_IDEVE_PROJECT_ID${SSO_URL}EVE_PROJECT_IDPasswordless / Magic-Link Apps
无密码/魔法链接应用
If your app's onboarding is "admin invites a user, user clicks email, user lands in app" — model it as a passwordless app. Don't build a password reset flow you don't need. Declare it in the manifest and let the platform render a branded magic-link login page:
yaml
x-eve:
auth:
login_method: magic_link # or password_or_magic_link, password
self_signup: false # unknown emails return generic success, no email
invite_requires_password: false # invite acceptance skips /set-passwordDesign implications:
- Users are created through invites, not self-signup. Plan your admin invite UX accordingly.
- The magic-link email reuses the same block as invite emails — one branding source, two email copies.
x-eve.branding - Eve API handles eligibility (existing user, pending invite, domain signup) before any email is sent, so account-enumeration defense is preserved without app-side work.
如果您的应用采用“管理员邀请用户,用户点击邮件链接进入应用”的入职流程,请将其设计为无密码应用。无需构建不需要的密码重置流程。在清单中声明,由平台渲染品牌化的魔法链接登录页面:
yaml
x-eve:
auth:
login_method: magic_link # 可选值:password_or_magic_link、password
self_signup: false # 未知邮箱返回通用成功信息,不发送邮件
invite_requires_password: false # 接受邀请时跳过/set-password步骤设计影响:
- 用户通过邀请创建,而非自行注册。请相应规划管理员邀请的UX。
- 魔法链接邮件与邀请邮件使用相同的配置块——一处配置品牌,两处邮件复用。
x-eve.branding - Eve API会在发送邮件前验证用户资格(已有用户、待处理邀请、域名注册),无需在应用端实现账号枚举防护。
App Branding (Invites and Magic-Link Emails)
应用品牌(邀请与魔法链接邮件)
Per-app branding is a manifest concern, not a code concern. Declare it once and the platform applies it to invite emails, magic-link emails, and SSO login pages:
yaml
x-eve:
branding:
app_name: "ACME Portal"
app_logo_url: "https://app.example.com/assets/logo.svg"
primary_color: "#1f6feb"
email_from_name: "ACME Portal"
reply_to_email: "support@example.com"
support_email: "support@example.com"
support_url: "https://example.com/help"The display name and email body carry the app identity; the sender address remains the platform default (verified per-tenant is a later phase). Treat branding as a property of the project, not a per-org concern.
From:From:应用级品牌是清单的配置项,而非代码实现。只需声明一次,平台会将其应用到邀请邮件、魔法链接邮件和SSO登录页面:
yaml
x-eve:
branding:
app_name: "ACME Portal"
app_logo_url: "https://app.example.com/assets/logo.svg"
primary_color: "#1f6feb"
email_from_name: "ACME Portal"
reply_to_email: "support@example.com"
support_email: "support@example.com"
support_url: "https://example.com/help"邮件的显示名称和正文会携带应用标识;发件地址仍为平台默认值(后续阶段会支持按租户验证的地址)。请将品牌视为项目的属性,而非按组织划分的配置。
From:From:App Org Access and In-App Admin Invites
应用组织访问与应用内管理员邀请
By default an app is scoped to its project owner org. For multi-tenant apps that serve multiple customer orgs, declare an allowlist and (optionally) enable in-app admin invites:
yaml
x-eve:
auth:
org_access:
mode: allowlist
allowed_orgs: [org_customer123, customer-slug]
invite:
enabled: true
admin_roles: [admin, owner]
invited_role: member # fixed; app invites cannot create adminsDesign implications:
- Backends should use (not
eveAppUserAuth()) so authorization is bound to the app policy, not the project owner org. The middleware consultseveUserAuth()and selects an org fromGET /auth/app-access,X-Eve-Org-Id, or the first allowed org.?eve_org_id= - Build admin pages around (sends branded magic-link onboarding) instead of generic org-invite APIs. The platform enforces org role + app allowlist policy before sending.
POST /auth/app-invites - The React SDK exposes for orgs/admin-org listings and inviting members.
useEveAppAccess()
默认情况下,应用限定为项目所属组织使用。如需构建服务多个客户组织的多租户应用,请声明允许列表并(可选)启用应用内管理员邀请:
yaml
x-eve:
auth:
org_access:
mode: allowlist
allowed_orgs: [org_customer123, customer-slug]
invite:
enabled: true
admin_roles: [admin, owner]
invited_role: member # 固定值;应用邀请无法创建管理员设计影响:
- 后端应使用(而非
eveAppUserAuth()),使授权绑定到应用策略,而非项目所属组织。中间件会调用eveUserAuth()并从GET /auth/app-access、X-Eve-Org-Id或第一个允许的组织中选择组织。?eve_org_id= - 围绕构建管理员页面(发送品牌化的魔法链接入职邮件),而非使用通用的组织邀请API。平台会在发送前验证组织角色+应用允许列表策略。
POST /auth/app-invites - React SDK提供用于组织/管理员组织列表和邀请成员。
useEveAppAccess()
Domain-Based Signup (Path C Auto-Attach)
基于域名的注册(路径C自动关联)
When an app needs to serve a whole customer email domain — "anyone with a address should land in as a member" — use domain signup. Eve writes a one-shot invite on first magic-link request and auto-attaches membership when the user accepts. One project can route different domains to different orgs:
@yourcompany.comorg_yourcompanyyaml
x-eve:
auth:
org_access:
mode: allowlist
allowed_orgs: [org_acme, org_globex]
domain_signup:
enabled: true
domains:
- { domain: acme.com, target_org: org_acme, role: member }
- { domain: globex.com, target_org: org_globex }Design implications:
- Rules are walked in declaration order — first match wins. Declare more-specific patterns first.
- The trust model is "operator declares, platform trusts" — no DNS proof in v1. Declaring produces a coherence warning but is permitted.
free-mail.example - Explicit pending invites (Path B) always win over domain signup (Path C); existing users with allowed-org membership (Path A) get the standard branded send.
- Removing a rule stops new signups but does not retroactively remove existing memberships — plan offboarding as an explicit .
eve org members remove - Audit via and
auth.domain_signup.invite_createdevents.auth.domain_signup.member_attached
如果应用需要服务整个客户邮箱域名——“所有邮箱用户应自动加入并成为成员”,请使用域名注册功能。Eve会在首次魔法链接请求时生成一次性邀请,并在用户接受时自动关联成员身份。一个项目可将不同域名路由到不同组织:
@yourcompany.comorg_yourcompanyyaml
x-eve:
auth:
org_access:
mode: allowlist
allowed_orgs: [org_acme, org_globex]
domain_signup:
enabled: true
domains:
- { domain: acme.com, target_org: org_acme, role: member }
- { domain: globex.com, target_org: org_globex }设计影响:
- 规则按声明顺序匹配——第一个匹配项生效。请先声明更具体的规则。
- 信任模型为“运维人员声明,平台信任”——v1版本无需DNS验证。声明会产生一致性警告,但仍允许使用。
free-mail.example - 显式的待处理邀请(路径B)始终优先于域名注册(路径C);已有允许组织成员身份的用户(路径A)会收到标准的品牌化邮件。
- 删除规则会停止新注册,但不会追溯移除现有成员身份——请将离职处理规划为显式的操作。
eve org members remove - 可通过和
auth.domain_signup.invite_created事件进行审计。auth.domain_signup.member_attached
Project-Scoped Redirect Allowlist (Custom Domains)
项目级重定向允许列表(自定义域名)
If your app runs on its own custom domain (not under the cluster domain), declare which origins SSO may redirect to. Without this, SSO rewrites the redirect to the platform-default hostname and your branded app URL is lost:
yaml
x-eve:
auth:
allowed_redirect_origins:
- https://app.example.com
- https://www.example.comThe final allowlist is the union of manifest entries, the project's own eligible custom domains, and (for ) cross-org custom domains owned by projects in . This replaces the legacy hard-coded allowlist. The platform also guarantees on SSO session cookies so cross-site probes from your custom-domain frontend carry credentials — you no longer need to configure cookie attributes yourself.
mode: allowlistallowed_orgsEVE_DEFAULT_DOMAINSameSite=None; Secure/session如果应用运行在自定义域名(而非集群域名下),请声明SSO允许重定向的源。否则,SSO会将重定向地址改写为平台默认主机名,导致应用的品牌化URL丢失:
yaml
x-eve:
auth:
allowed_redirect_origins:
- https://app.example.com
- https://www.example.com最终的允许列表是清单条目、项目自身的合格自定义域名,以及(对于)中项目所属的跨组织自定义域名的并集。这取代了旧版硬编码的允许列表。平台还会确保SSO会话Cookie设置,以便自定义域名前端的跨域探测能携带凭证——您无需自行配置Cookie属性。
mode: allowlistallowed_orgsEVE_DEFAULT_DOMAINSameSite=None; Secure/sessionDesign Rules
设计规则
- Use the SDK, not custom auth. The SDK replaces ~750 lines of hand-rolled auth with ~50 lines.
- Non-blocking middleware first. Use globally, then
eveUserAuth()on protected routes. This enables mixed public/private routes.eveAuthGuard() - The endpoint is the handshake. The frontend discovers the SSO URL by calling the backend's
/auth/configendpoint. This decouples the frontend from platform env vars and works identically in local dev and deployed environments.eveAuthConfig() - Design for token staleness. The JWT claim reflects membership at mint time (1-day TTL). Use
orgsfor immediate revocation if needed.strategy: 'remote'
For full SDK reference, see in the skill.
references/auth-sdk.mdeve-read-eve-docs- 使用SDK,而非自定义认证:SDK用约50行代码替代了约750行手写认证代码。
- 先使用非阻塞中间件:全局使用,然后在受保护路由上使用
eveUserAuth(),支持混合公共/私有路由。eveAuthGuard() - 端点是握手点:前端通过调用后端的
/auth/config端点发现SSO URL,使前端与平台环境变量解耦,在本地开发和部署环境中表现一致。eveAuthConfig() - 针对令牌过期设计:JWT声明反映令牌生成时的成员身份(TTL为1天)。如需立即撤销权限,请使用
orgs。strategy: 'remote'
完整SDK参考请查看技能中的。
eve-read-eve-docsreferences/auth-sdk.mdObservability and Debugging
可观测性与调试
The Debugging Ladder
调试阶梯
Escalate through these stages:
1. Status → eve env show <project> <env>
2. Diagnose → eve env diagnose <project> <env>
3. Logs → eve env logs <project> <env>
4. Pipeline → eve pipeline logs <pipeline> <run-id> --follow
5. Recover → eve env deploy (rollback) or eve env resetStart at the top. Each stage provides more detail and more cost. Most issues resolve at stages 1-2.
按以下阶段逐步排查:
1. 状态 → eve env show <project> <env>
2. 诊断 → eve env diagnose <project> <env>
3. 日志 → eve env logs <project> <env>
4. 流水线 → eve pipeline logs <pipeline> <run-id> --follow
5. 恢复 → eve env deploy(回滚)或eve env reset从最上层开始排查。每个阶段提供的细节更多,但成本也更高。大多数问题可在1-2阶段解决。
Pipeline Observability
流水线可观测性
Monitor pipeline execution in real time:
bash
eve pipeline logs <pipeline> <run-id> --follow # stream all steps
eve pipeline logs <pipeline> <run-id> --follow --step build # stream one stepFailed steps include failure hints and link to build diagnostics when applicable.
实时监控流水线执行:
bash
eve pipeline logs <pipeline> <run-id> --follow # 流式查看所有步骤日志
eve pipeline logs <pipeline> <run-id> --follow --step build # 流式查看单个步骤日志失败步骤会包含失败提示,并在适用时链接到构建诊断信息。
Build Debugging
构建调试
When builds fail:
bash
eve build list --project <project_id>
eve build diagnose <build_id>
eve build logs <build_id>Common causes: missing registry credentials, Dockerfile path mismatch, build context too large.
构建失败时:
bash
eve build list --project <project_id>
eve build diagnose <build_id>
eve build logs <build_id>常见原因:缺少仓库凭证、Dockerfile路径不匹配、构建上下文过大。
Health Checks
健康检查
Design services with health endpoints. Eve polls health to determine deployment readiness. A deploy is complete when and .
ready === trueactive_pipeline_run === null为服务设计健康检查端点。Eve会轮询健康状态以确定部署是否就绪。当且时,部署完成。
ready === trueactive_pipeline_run === nullDesign Checklist
设计检查清单
Service Topology:
- Each service has one responsibility
- Managed DB declared for Postgres needs
- External services marked with
x-eve.external: true - Only public-facing services have ingress enabled
- Platform-injected env vars used (not hardcoded URLs)
- Hostname strategy chosen (generated URL, alias, or custom domain via )
x-eve.ingress.domains - Stable egress opted in only for services that integrate with source-IP-allowlisted vendors
Database:
- Migrations are plain SQL files in with timestamp prefixes
db/migrations/ - job service declared in manifest with
eve-migratemountx-eve.files - wraps all DB access with RLS context (
DatabaseService)set_config - RLS policies on every table with
org_id - extension enabled, UUID primary keys,
pgcryptotriggersupdated_at - App data separated from agent data by schema or convention
Pipeline:
- Canonical pipeline defined
build → release → deploy → migrate → smoke-test - Migrate step runs after deploy (managed DB must exist first)
- Smoke test script validates deployed services end-to-end
- Registry chosen and credentials set as secrets
- OCI labels on Dockerfiles (for GHCR)
- Image digests flow through release (no tag-based deploys)
Environments:
- Staging and production environments defined
- Each environment linked to a pipeline
- Promotion workflow defined (build once, deploy many)
- Recovery procedure known (diagnose -> rollback -> reset)
Secrets:
- All secrets set per-project via
eve secrets set - Manifest uses interpolation
${secret.KEY} - passes
eve manifest validate --validate-secrets - exists for local development
.eve/dev-secrets.yaml - Git credentials (or
github_token) configuredssh_key - Service token permissions declared per service (default read-only; write opted in explicitly)
Authentication:
- middleware added to backend (
@eve-horizon/auth+eveUserAuth, oreveAuthGuardfor multi-org apps)eveAppUserAuth - Auth config endpoint serves SSO discovery ()
eveAuthConfig - wraps frontend (
@eve-horizon/auth-react+EveAuthProvideror customEveLoginGategate)useEveAuth - used for authenticated API calls from frontend
createEveClient - Platform-injected auth env vars used (,
EVE_SSO_URL,EVE_ORG_ID)EVE_PROJECT_ID - Eve roles mapped to app roles in one place (bridge middleware), not scattered across controllers
- If passwordless: +
x-eve.auth.login_method: magic_linkinvite_requires_password: false - If multi-tenant: with
x-eve.auth.org_access.mode: allowlistdeclared; in-app admin invites useallowed_orgsPOST /auth/app-invites - If domain-based onboarding: declares per-rule
domain_signup.domains; more-specific rules listed firsttarget_org - If custom domain: declared;
x-eve.auth.allowed_redirect_originsconfirms resolved allowlisteve project auth-context - If branded: declared (shared by invite and magic-link emails);
x-eve.brandingdisplay name and logo setFrom:
App CLI (the Eve way):
- App API wrapped in a domain CLI (e.g., )
eden projects list - CLI declared in manifest via with
x-eve.cliandnamebin - CLI bundled as single-file executable (esbuild for Node.js)
- CLI reads and
EVE_APP_API_URL_{SERVICE}automaticallyEVE_JOB_TOKEN - All CLI commands support for machine-readable output
--json - Agent skill references CLI commands, not raw curl/REST calls
Observability:
- Services expose health endpoints
- The debugging ladder is understood (status -> diagnose -> logs -> recover)
- Pipeline logs are accessible via
eve pipeline logs --follow
服务拓扑:
- 每个服务单一职责
- 为Postgres需求声明托管数据库
- 外部服务标记
x-eve.external: true - 仅面向公众的服务启用Ingress
- 使用平台注入的环境变量(而非硬编码URL)
- 确定主机名策略(生成URL、别名或通过绑定自定义域名)
x-eve.ingress.domains - 仅为与限制源IP的供应商集成的服务启用稳定出口
数据库:
- 迁移脚本为目录下带时间戳前缀的纯SQL文件
db/migrations/ - 在清单中声明任务服务并配置
eve-migrate挂载x-eve.files - 使用RLS上下文(
DatabaseService)封装所有数据库访问set_config - 每个带的表都配置RLS策略
org_id - 启用扩展,使用UUID主键和
pgcrypto触发器updated_at - 应用数据与Agent数据按架构或约定分离
流水线:
- 定义标准的流水线
构建 → 发布 → 部署 → 迁移 → 冒烟测试 - 迁移步骤在部署后运行(托管数据库需先存在)
- 冒烟测试脚本对部署的服务进行端到端验证
- 选择镜像仓库并将凭证设置为密钥
- Dockerfile中添加OCI标签(针对GHCR)
- 镜像摘要通过发布流程流转(不使用基于标签的部署)
环境:
- 定义staging和production环境
- 每个环境关联流水线
- 定义版本推广流程(构建一次,多次部署)
- 了解恢复流程(诊断 → 回滚 → 重置)
密钥:
- 所有密钥通过按项目设置
eve secrets set - 清单使用插值
${secret.KEY} - 验证通过
eve manifest validate --validate-secrets - 存在用于本地开发
.eve/dev-secrets.yaml - 配置Git凭证(或
github_token)ssh_key - 按服务声明服务令牌权限(默认只读;写入权限需显式开启)
认证:
- 后端添加中间件(
@eve-horizon/auth+eveUserAuth,多租户应用使用eveAuthGuard)eveAppUserAuth - 提供认证配置端点用于SSO发现()
eveAuthConfig - 前端使用封装(
@eve-horizon/auth-react+EveAuthProvider或自定义EveLoginGate网关)useEveAuth - 使用从前端调用认证后的API
createEveClient - 使用平台注入的认证环境变量(、
EVE_SSO_URL、EVE_ORG_ID)EVE_PROJECT_ID - 在一处将Eve角色映射为应用角色(桥接中间件),而非分散在多个控制器中
- 若为无密码应用:设置+
x-eve.auth.login_method: magic_linkinvite_requires_password: false - 若为多租户应用:设置并声明
x-eve.auth.org_access.mode: allowlist;应用内管理员邀请使用allowed_orgsPOST /auth/app-invites - 若为基于域名的入职:声明每个规则的
domain_signup.domains;先声明更具体的规则target_org - 若使用自定义域名:声明;使用
x-eve.auth.allowed_redirect_origins确认最终允许列表eve project auth-context - 若为品牌化应用:声明(邀请和魔法链接邮件共享);设置
x-eve.branding显示名称和LogoFrom:
应用CLI(Eve风格):
- 应用API封装为领域CLI(如)
eden projects list - 在清单中通过声明CLI的
x-eve.cli和namebin - CLI打包为单文件可执行程序(Node.js使用esbuild)
- CLI自动读取和
EVE_APP_API_URL_{SERVICE}EVE_JOB_TOKEN - 所有CLI命令支持参数以提供机器可读输出
--json - Agent技能引用CLI命令,而非原生curl/REST调用
可观测性:
- 服务暴露健康检查端点
- 理解调试阶梯(状态 → 诊断 → 日志 → 恢复)
- 可通过访问流水线日志
eve pipeline logs --follow
Cross-References
交叉引用
- SPA + API + managed Postgres implementation:
references/spa-api-managed-db.md - Manifest syntax and options:
eve-manifest-authoring - Deploy commands and error resolution:
eve-deploy-debugging - Secret management and access groups:
eve-auth-and-secrets - Pipeline and workflow definitions:
eve-pipelines-workflows - Local development workflow:
eve-local-dev-loop - Layering agentic capabilities onto this foundation:
eve-agentic-app-design - Auth SDK and SSO integration: →
eve-read-eve-docsreferences/auth-sdk.md - Object storage and filesystem: →
eve-read-eve-docsreferences/object-store-filesystem.md - External integrations (Slack, GitHub): →
eve-read-eve-docsreferences/integrations.md
- SPA + API + 托管Postgres实现:
references/spa-api-managed-db.md - 清单语法与选项:
eve-manifest-authoring - 部署命令与错误排查:
eve-deploy-debugging - 密钥管理与访问组:
eve-auth-and-secrets - 流水线与工作流定义:
eve-pipelines-workflows - 本地开发流程:
eve-local-dev-loop - 在此基础上添加Agent能力:
eve-agentic-app-design - Auth SDK与SSO集成:→
eve-read-eve-docsreferences/auth-sdk.md - 对象存储与文件系统:→
eve-read-eve-docsreferences/object-store-filesystem.md - 外部集成(Slack、GitHub):→
eve-read-eve-docsreferences/integrations.md