Files
Genarrative/.env.example
kdletters 1a7abfd059
Project CI / AI game creator shell Rust shard 4/4 (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (push) Has been cancelled
AGC 项目定时快照上传(目标 OSS agc-dev) (#400)
## 交付内容

- 客户端新增 `project_snapshot` 模块:项目扫描与排除口径、增量索引、差异对比、上传编排、状态查询。
- 触发:工作区窗口存活期间的周期定时器 + 工作区窗口关闭(`CloseRequested`);应用退出只在有界预算内等待在途同步收尾,不重复发起。
- 服务端新增两条登录态路由 `POST /api/agc/project-snapshots/files` 与 `/manifest`,由 api-server 用服务端凭据写入私有前缀 `agc/project-snapshots/v1/{user}/{project}/`;客户端不持有 OSS 凭据、不直连 OSS。
- `platform-oss` 新增内部对象精确写入与探测、项目快照对象键构造;修复 `head_internal_object` 读 HEAD 响应长度恒为 0(会导致服务端"已存在即跳过"永不生效)。
- `shared-contracts` 新增 `agc_project_snapshots` DTO 与项目 ID、相对路径、摘要校验。
- 真实 OSS 存储层冒烟示例 + 客户端真实链路冒烟用例(`#[ignore]`,env 驱动)。
- 登记 `check-config.mjs` 的 native-only 命令白名单,恢复 `npm run agc` 可启动。

## 验证证据

- 存储层:`cargo run -p platform-oss --example agc_project_snapshot_live_smoke` 对真实 `agc-dev` 完成写入 → 读回(contentLength 32)→ 清单写入 → 探针清理。
- HTTP 层:登录态下 7 项校验(401 无 token、400 路径穿越/长度不一致/非法摘要/空正文/重复路径清单)全部符合预期且不写对象。
- 客户端链路(真实项目 gameagent-033b6cf3…):第一次 `synced uploaded=6 uploadedBytes=36694 remoteSkipped=6`,紧接着第二次 `no-op uploaded=0`。
- GUI 触发:`trigger=periodic ... uploaded=6`;把周期设为 600 秒排除干扰、改一个文件后关窗得到 `trigger=project-close ... revision=2 uploaded=1`,索引摘要由 `28d837cd84f8ab62` 推进到 `bff34e2e336d901f`(同步在进程退出前完成)。
- 门禁:AGC `project_snapshot` 14 passed(+1 ignored live)、api-server `project_snapshots` 3 passed、platform-oss 39 passed、shared-contracts 87 passed、`cargo fmt --check`(两处)、`check:encoding`、`check:doc-index`、`git diff --check`、`check-config.mjs` 全部通过。

## 已知未决(不阻塞本里程碑)

- 远端对象只增不减:没有删除路径,也没有 bucket 生命周期规则;要收口需要先定保留语义(清单引用 GC 还是 OSS 生命周期)。
- 部署环境需确认 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_*` 或回退的 `ALIYUN_OSS_*` 具备目标 bucket 私有前缀的 `PutObject` 权限;未配置时接口返回 503、客户端失败关闭(不推进索引)。
- 缺少按用户/项目的配额与限流(error_reports 有每小时提交上限的先例,本功能没有)。
- 没有界面入口与状态可见性:`read_local_project_snapshot_state` 已注册但未接 UI,失败只写本机日志。

## 不做

- 不做云端下载/恢复、跨设备合并、版本回滚。
- 不改 `/api/external/v1` 与 External OpenAPI,不新增 SpacetimeDB 表。

---------

Co-authored-by: kdletters <61648117+kdletters@users.noreply.github.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/400
2026-09-17 18:34:51 +08:00

250 lines
11 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Server-side OpenAI-compatible LLM endpoint base URL.
LLM_BASE_URL="https://api.tiantoken.com/v1"
# Server-side API key used by the local Vite proxy.
# Recommended: set `LLM_API_KEY` locally, or use `TIANTOKEN_API_KEY`
# through the Rust api-server proxy.
# Legacy compatibility: `VITE_LLM_API_KEY` is still supported by the proxy,
# but it should not be relied on by browser code.
LLM_API_KEY=""
# Router account provisioning secret (server-side only). Prefer the protected
# file form in production; never expose either value to clients or commit it.
GENARRATIVE_LLM_ROUTER_PROVISIONING_SECRET=""
GENARRATIVE_LLM_ROUTER_PROVISIONING_SECRET_FILE=""
# Optional frontend override for the local proxy path.
VITE_LLM_PROXY_BASE_URL="/api/llm"
# Optional frontend override for the local custom-world scene image proxy path.
VITE_SCENE_IMAGE_PROXY_BASE_URL="/api/custom-world/scene-image"
# Runtime API routes use Rust Axum api-server.
RUST_SERVER_TARGET="http://127.0.0.1:3100"
# Optional hard override. When set, it wins over RUST_SERVER_TARGET.
GENARRATIVE_RUNTIME_SERVER_TARGET=""
# Rust api-server local target used by the Big Fish / Puzzle compatibility gateways
# and by the standalone Rust dev / deploy scripts.
GENARRATIVE_API_PORT="3100"
GENARRATIVE_API_TARGET="http://127.0.0.1:3100"
GENARRATIVE_ADMIN_USERNAME=""
GENARRATIVE_ADMIN_PASSWORD=""
GENARRATIVE_ADMIN_TOKEN_TTL_SECONDS="14400"
GENARRATIVE_INTERNAL_API_SECRET="CHANGE_ME_FOR_PRODUCTION"
GENARRATIVE_SPACETIME_SERVER_URL="http://127.0.0.1:3001"
GENARRATIVE_SPACETIME_DATABASE="genarrative-dev"
GENARRATIVE_SPACETIME_POOL_SIZE="4"
# Editor and asset tool APIs. Defaults are enabled outside production and
# disabled in production unless explicitly enabled.
EDITOR_API_ENABLED="true"
ASSETS_API_ENABLED="true"
# Rust api-server JWT settings.
JWT_SECRET="CHANGE_ME_FOR_PRODUCTION"
# Access token 有效期。
JWT_EXPIRES_IN="2h"
# Refresh session 配置。
AUTH_REFRESH_COOKIE_NAME="genarrative_refresh_session"
AUTH_REFRESH_SESSION_TTL_DAYS="30"
AUTH_REFRESH_COOKIE_PATH="/api/auth"
AUTH_REFRESH_COOKIE_SAME_SITE="Lax"
AUTH_REFRESH_COOKIE_SECURE="false"
# 开发期便捷开关:true 时允许 /api/auth/entry 对未知手机号用本次密码直接创建账号;生产必须保持 false。
GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED="false"
# 手机号验证码登录配置(阿里云 PNVS)。
# 正式环境请改成你自己的 AccessKey 和短信签名/模板。
# 在 `.env.local` 或进程环境中填入 AccessKey 后会自动启用;如需强制关闭,请显式设置 `SMS_AUTH_ENABLED="false"`。
SMS_AUTH_ENABLED="false"
SMS_AUTH_PROVIDER="aliyun"
ALIYUN_SMS_ACCESS_KEY_ID=""
ALIYUN_SMS_ACCESS_KEY_SECRET=""
ALIYUN_SMS_ENDPOINT="dypnsapi.aliyuncs.com"
# 默认使用阿里云文档中的赠送测试签名/模板,可按控制台实际配置覆盖。
ALIYUN_SMS_SIGN_NAME="速通互联验证码"
ALIYUN_SMS_TEMPLATE_CODE="100001"
ALIYUN_SMS_TEMPLATE_PARAM_KEY="code"
ALIYUN_SMS_COUNTRY_CODE="86"
ALIYUN_SMS_SCHEME_NAME=""
ALIYUN_SMS_CODE_LENGTH="6"
ALIYUN_SMS_CODE_TYPE="1"
ALIYUN_SMS_VALID_TIME_SECONDS="300"
ALIYUN_SMS_INTERVAL_SECONDS="60"
ALIYUN_SMS_DUPLICATE_POLICY="1"
ALIYUN_SMS_CASE_AUTH_POLICY="1"
ALIYUN_SMS_RETURN_VERIFY_CODE="false"
SMS_AUTH_MAX_SEND_PER_PHONE_PER_DAY="20"
SMS_AUTH_MAX_SEND_PER_IP_PER_HOUR="30"
SMS_AUTH_MAX_VERIFY_FAILURES_PER_PHONE_PER_HOUR="12"
SMS_AUTH_MAX_VERIFY_FAILURES_PER_IP_PER_HOUR="24"
SMS_AUTH_CAPTCHA_TTL_SECONDS="180"
SMS_AUTH_CAPTCHA_TRIGGER_VERIFY_FAILURES_PER_PHONE="3"
SMS_AUTH_CAPTCHA_TRIGGER_VERIFY_FAILURES_PER_IP="5"
SMS_AUTH_BLOCK_PHONE_FAILURE_THRESHOLD="6"
SMS_AUTH_BLOCK_IP_FAILURE_THRESHOLD="10"
SMS_AUTH_BLOCK_PHONE_DURATION_MINUTES="30"
SMS_AUTH_BLOCK_IP_DURATION_MINUTES="30"
# 仅开发环境:允许本地开发测试自动走游客账号。
# 一旦你已经启用手机号/微信登录,建议改成 `false`,这样会直接进入真实登录界面。
VITE_AUTH_ALLOW_DEV_GUEST="false"
# 微信登录配置。
# 当前实现已支持:
# 1. `WECHAT_AUTH_PROVIDER="mock"` 的本地假回调联调
# 2. `WECHAT_AUTH_PROVIDER="real"` 的真实微信 OAuth 回调
# 正式联调时除了补齐 AppID / AppSecret,还要确保微信开放平台回调域名与
# `WECHAT_CALLBACK_PATH` 拼出的完整地址一致。
WECHAT_AUTH_ENABLED="false"
WECHAT_AUTH_PROVIDER="mock"
WECHAT_APP_ID=""
WECHAT_APP_SECRET=""
WECHAT_CALLBACK_PATH="/api/auth/wechat/callback"
WECHAT_REDIRECT_PATH="/"
WECHAT_AUTHORIZE_ENDPOINT="https://open.weixin.qq.com/connect/qrconnect"
WECHAT_ACCESS_TOKEN_ENDPOINT="https://api.weixin.qq.com/sns/oauth2/access_token"
WECHAT_USER_INFO_ENDPOINT="https://api.weixin.qq.com/sns/userinfo"
WECHAT_JS_CODE_SESSION_ENDPOINT="https://api.weixin.qq.com/sns/jscode2session"
WECHAT_STABLE_ACCESS_TOKEN_ENDPOINT="https://api.weixin.qq.com/cgi-bin/stable_token"
WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_QUERY_ORDER_ENDPOINT="https://api.weixin.qq.com/xpay/query_order"
WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_NOTIFY_PROVIDE_GOODS_ENDPOINT="https://api.weixin.qq.com/xpay/notify_provide_goods"
WECHAT_PHONE_NUMBER_ENDPOINT="https://api.weixin.qq.com/wxa/business/getuserphonenumber"
WECHAT_STATE_TTL_MINUTES="15"
WECHAT_MOCK_USER_ID="wx-mock-user"
WECHAT_MOCK_UNION_ID="wx-mock-union"
WECHAT_MOCK_DISPLAY_NAME="微信旅人"
WECHAT_MOCK_AVATAR_URL=""
WECHAT_MINIPROGRAM_MESSAGE_TOKEN=""
WECHAT_MINIPROGRAM_MESSAGE_ENCODING_AES_KEY=""
# Model name for chat completions.
VITE_LLM_MODEL="gpt-5.4-mini"
GENARRATIVE_LLM_PROVIDER="openai-compatible"
GENARRATIVE_LLM_BASE_URL="https://api.tiantoken.com/v1"
GENARRATIVE_LLM_API_KEY=""
GENARRATIVE_LLM_MODEL="gpt-5.4-mini"
# Server-side DashScope endpoint and API key used by the local scene-image proxy.
DASHSCOPE_BASE_URL="https://dashscope.aliyuncs.com/api/v1"
DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY"
# Tiantoken LLM and GPT-image-2 / Gemini image generation config.
TIANTOKEN_BASE_URL="https://api.tiantoken.com"
TIANTOKEN_API_KEY=""
TIANTOKEN_IMAGE_REQUEST_TIMEOUT_MS="1000000"
# VectorEngine is retained for Suno audio generation only.
VECTOR_ENGINE_BASE_URL="https://api.vectorengine.cn"
VECTOR_ENGINE_API_KEY=""
VECTOR_ENGINE_AUDIO_REQUEST_TIMEOUT_MS="180000"
# ElevenLabs editor sound-effect generation is server-side only.
ELEVENLABS_BASE_URL="https://api.elevenlabs.io"
ELEVENLABS_API_KEY=""
ELEVENLABS_REQUEST_TIMEOUT_MS="180000"
# 阿里云 OSS 配置。
# Rust `server-rs` 的 `api-server` 会优先从 `.env` / `.env.local` 读取这些变量,
# 用于签发浏览器 PostObject 直传票据,并保持 `/generated-*` 旧路径习惯。
# 当前正式口径按私有 bucket 处理,后续在 SpacetimeDB 中存 `bucket + object_key` 两列。
ALIYUN_OSS_BUCKET=""
ALIYUN_OSS_ENDPOINT="oss-cn-shanghai.aliyuncs.com"
ALIYUN_OSS_ACCESS_KEY_ID=""
ALIYUN_OSS_ACCESS_KEY_SECRET=""
ALIYUN_OSS_READ_EXPIRE_SECONDS="600"
ALIYUN_OSS_POST_EXPIRE_SECONDS="600"
ALIYUN_OSS_POST_MAX_SIZE_BYTES="20971520"
ALIYUN_OSS_SUCCESS_ACTION_STATUS="200"
# AGC 项目定时快照上传目标。对象只落在服务端私有前缀
# `agc/project-snapshots/v1/{user}/{project}/` 下,客户端直传票据不覆盖该前缀。
# bucket 与凭据可以与资源 bucket 分离;凭据未设置时回退使用 ALIYUN_OSS_ACCESS_KEY_*
# 但 bucket / endpoint 默认指向 AGC 发行 bucket,需要该凭据具备目标 bucket 的 PutObject 权限。
GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_BUCKET="agc-dev"
GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_ENDPOINT="oss-rg-china-mainland.aliyuncs.com"
GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_ACCESS_KEY_ID=""
GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_ACCESS_KEY_SECRET=""
# BgFilter 受限资源 worker。父 api-server / external-generation-worker 与唯一的
# `GENARRATIVE_PROCESS_ROLE=bgfilter-worker` 进程必须使用同一个内部 Token。
# `npm run dev` 与 `npm run dev:api-server` 都会自动带起并验活唯一 worker,不要再开第二个终端重复启动。
# 只有需要脱离父 API 单独验证 worker 时才运行 `npm run dev:bgfilter-worker`;不要让 `all` 角色兼任它。
GENARRATIVE_BGFILTER_WORKER_HOST="127.0.0.1"
GENARRATIVE_BGFILTER_WORKER_PORT="8083"
GENARRATIVE_BGFILTER_WORKER_BASE_URL="http://127.0.0.1:8083"
GENARRATIVE_BGFILTER_INTERNAL_TOKEN="CHANGE_ME_FOR_LOCAL"
GENARRATIVE_BGFILTER_WORKER_CONCURRENCY="16"
GENARRATIVE_EDITOR_BGFILTER_SINGLE_IMAGE_ESTIMATE_MS="5000"
GENARRATIVE_BGFILTER_WORKER_MAX_REQUESTS="2048"
GENARRATIVE_BGFILTER_WORKER_CONNECT_TIMEOUT_MS="2000"
# SpacetimeDB 数据目录备份到 OSS。备份 bucket 可与资源 bucket 分离;未设置时脚本回退使用 ALIYUN_OSS_BUCKET。
GENARRATIVE_DATABASE_BACKUP_DATA_DIR=""
GENARRATIVE_DATABASE_BACKUP_WORK_DIR=""
GENARRATIVE_DATABASE_BACKUP_OSS_BUCKET=""
GENARRATIVE_DATABASE_BACKUP_OSS_ENDPOINT=""
GENARRATIVE_DATABASE_BACKUP_OSS_PREFIX="database-backups"
GENARRATIVE_DATABASE_BACKUP_KEEP_LOCAL="false"
GENARRATIVE_DATABASE_BACKUP_OSS_ACCESS_KEY_ID=""
GENARRATIVE_DATABASE_BACKUP_OSS_ACCESS_KEY_SECRET=""
GENARRATIVE_DATABASE_BACKUP_STOP_SERVICE=""
# Optional model name for custom-world scene image generation.
DASHSCOPE_IMAGE_MODEL="wan2.7-image"
# Optional model names for character asset studio.
DASHSCOPE_CHARACTER_VISUAL_MODEL="wan2.7-image-pro"
DASHSCOPE_CHARACTER_IMAGE_SEQUENCE_MODEL="wan2.7-image-pro"
DASHSCOPE_CHARACTER_REFERENCE_VIDEO_MODEL="wan2.7-r2v"
DASHSCOPE_CHARACTER_MOTION_TRANSFER_MODEL="wan2.2-animate-move"
# Optional Ark Seedance config for character animation image-to-video.
# If omitted, image-to-video will fall back to `ARK_API_KEY` / `LLM_API_KEY`
# and `ARK_BASE_URL` / `LLM_BASE_URL`.
ARK_CHARACTER_VIDEO_BASE_URL="https://ark.cn-beijing.volces.com/api/v3"
ARK_CHARACTER_VIDEO_API_KEY=""
ARK_CHARACTER_VIDEO_MODEL="doubao-seedance-2-0-fast-260128"
ARK_CHARACTER_VIDEO_REQUEST_TIMEOUT_MS="420000"
# Optional: server-side polling timeout for custom-world scene image generation, in milliseconds.
DASHSCOPE_IMAGE_REQUEST_TIMEOUT_MS="150000"
# Optional: longer timeout for character video generation, in milliseconds.
DASHSCOPE_CHARACTER_VIDEO_REQUEST_TIMEOUT_MS="420000"
# Optional: generic frontend timeout for regular LLM requests, in milliseconds.
VITE_LLM_REQUEST_TIMEOUT_MS="15000"
# Optional: longer timeout for custom world generation, in milliseconds.
VITE_LLM_CUSTOM_WORLD_TIMEOUT_MS="120000"
# Optional: timeout for custom-world scene image generation, in milliseconds.
VITE_SCENE_IMAGE_REQUEST_TIMEOUT_MS="150000"
# Optional: print full LLM prompts / outputs in the browser console.
# Keep this off by default for cleaner logs.
VITE_LLM_DEBUG_LOG="false"
# Optional: global frontend debug mode. When empty, it follows Vite dev mode.
# Set to "true" to expose local diagnostic panels, or "false" to hide them.
VITE_DEBUG_MODE=""
# Optional: show the image editor right-side Agent entry at runtime.
# This is read by api-server and exposed through /api/runtime/frontend-config.
GENARRATIVE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR="false"
# Optional: official VikingDB credentials for regenerating build-tag similarities
# with the Python embedding script. The script auto-loads `.env.local` and uses
# the fixed `bge-large-zh` embedding model.
VOLCENGINE_ACCESS_KEY_ID=""
VOLCENGINE_SECRET_ACCESS_KEY=""
VIKINGDB_HOST=""
VIKINGDB_REGION=""
# APP_URL: The URL where this applet is hosted.
# AI Studio automatically injects this at runtime with the Cloud Run service URL.
# Used for self-referential links, OAuth callbacks, and API endpoints.
APP_URL="MY_APP_URL"