# 本地开发与配置

本文说明星线 App 的源码入口、隔离开发环境和配置方法。App 与聊天命令默认从 App 仓库根目录执行；Account 命令必须进入其当前维护仓库，不能使用 App 工作树中同名的历史 `identity/` 副本。示例中的账号、口令和 `example.test` 域名均为合成测试值。配置依据 2026-10-23 当前源码整理，本次文档整理没有启动服务、模拟器或访问生产配置。

## 先理解组成

| 仓库路径 | 职责 | 开发入口 |
| --- | --- | --- |
| `ios-app/` | iPhone 原生界面、本机数据、系统浏览器登录 | Xcode 工程 `StarlineWorkbench.xcodeproj` |
| `android-app/` | Android Compose 界面、Keystore 和本机数据 | Gradle Wrapper |
| Account 当前仓库的 `identity/` | 账号、验证码、通行密钥、OIDC、管理权限、PII 保护 | Node.js / TypeScript / Fastify / MySQL；App 副本不是当前权威源 |
| Account 当前仓库的 `identity/client/` | Account 与管理站前端 | React / Vite |
| `chat-service/` | 聊天、新事、媒体、设备会话、通话信令 | Node.js / SQLite |
| `chat-crypto/` | OpenMLS 加密核心及跨端绑定 | Rust 与平台构建脚本 |
| `app-download/dist/` | 公开下载介绍页 | 静态 HTTP 服务 |

开发前先查看当前工作区差异。需要可丢弃环境时使用新的独立工作区，不把现有 App 私有目录、账号数据库、Keychain 或 Keystore 当作测试夹具。Account、聊天和 App 必须指向同一环境；本地签发的 ticket 不能提交给正式聊天服务。

## 工具与依赖

服务端的 `package.json` 要求 Node.js 24 或更新版本；身份服务使用 MySQL 8.4。Android 当前使用 Java 17、Android SDK 35，最低支持 Android 8.0（API 26）；构建应使用仓库自带 `gradlew`。iOS 工程使用 Swift 6、最低 iOS 17，需安装可用的 Xcode 与 XcodeGen。具体 Xcode、SDK 和签名兼容性以所选工具链实际构建结果为准，不由一次历史构建推断。

```sh
node --version
java -version
xcodebuild -version
```

未安装的目标平台可跳过对应工具检查。依赖使用锁文件安装；前三条在当前 Account 仓库执行，最后一条在 App 仓库执行：

```sh
npm --prefix identity ci
npm --prefix identity/client ci
npm --prefix identity/client run build
npm --prefix chat-service ci
```

## 隔离的账号与聊天联调

身份测试与本地 fixture 固定使用回环地址 `127.0.0.1:3310` 上的新建 `identity_dev` 数据库。可以在专用开发环境创建容器；下面的口令公开且只用于可丢弃的本地数据库，禁止用于公网：

```sh
docker run --name starline-identity-dev \
  -p 127.0.0.1:3310:3306 \
  -e MYSQL_DATABASE=identity_dev \
  -e MYSQL_USER=identity \
  -e MYSQL_PASSWORD=local-test-only \
  -e MYSQL_ROOT_PASSWORD=local-root-fixture-only \
  -d mysql:8.4
```

等待数据库就绪后，在当前 Account 的新建隔离工作区运行：

```sh
cd identity
node scripts/start-local-preview.mjs --local-fixtures
```

预览启动器先检查依赖、数据库和端口，已有健康服务会被复用；端口被其他异常服务占用时会退出。它持续运行账号后端与前端，不按展示时长关闭。此命令只证明启动流程，不提供当前注册、客户端登记和原生回跳的完整夹具。

当前注册即使在 development 也需要 captcha。保留的 `preview-fixture.mjs` 没有提交该参数，不能照旧当作可用的一键注册；它需要先按现行协议修订并验证。App 历史副本的 `create-chat-local-client.ts` 在当前 Account 主源码中不存在，也不能复制回共享服务冒充当前工具。隔离测试应使用 `env=test` 专用构造和合成依赖；需要浏览器联调时另行完成受控人机验证与客户端登记，精确登记本地 HTTPS／开发回调、scopes 和 confidential 类型，不使用生产客户端秘密。

聊天本地配置需由上述受控登记产生并保存在被忽略的受保护文件中；它不是本页启动命令自动生成的产物。取得匹配配置后才能继续：

另开终端，从仓库根目录执行：

```sh
cd chat-service
CHAT_DATABASE_PATH=./data/qa-chat.sqlite node --env-file=.env.local src/main.mjs
```

这里显式使用独立 SQLite 文件，避免接触已有预览数据。此服务前台持续运行，正常结束应发送终端中断，让服务关闭连接。账号页为 `http://localhost:9100`，前端开发入口为 `http://localhost:9101`，聊天健康检查为 `http://localhost:4210/health`。WebAuthn 本地 RP 使用 `localhost`，不要把 IP 页面和域名页面混为同一 RP。

## 连接原生 App

iOS 在 Xcode 的 Debug Run 环境中设置 `STARLINE_CHAT_BASE_URL=http://localhost:4210`。该覆盖仅在 Debug 生效，Release 忽略它；HTTP 仅允许本机回环主机。默认地址已经是正式聊天服务，旧资料中“模拟器默认连接 localhost”的表述不再适用。

```sh
cd ios-app
xcodegen generate
open StarlineWorkbench.xcodeproj
```

若缺少 `chat-crypto/dist/StarlineChatCrypto.xcframework`，先按工具链准备 Rust iOS 目标，再从仓库根目录执行 `bash chat-crypto/scripts/build-apple.sh`。该脚本构建原生库，并不证明聊天界面已启用端到端加密。

Android 模拟器对本机聊天 API 做隔离联调时可显式构建：

```sh
cd android-app
./gradlew :app:assembleDebug \
  -PstarlineChatBaseUrl=http://10.0.2.2:4210 \
  --max-workers=1
```

`10.0.2.2` 是 Android 模拟器的宿主机别名，不能直接用于实体手机。上述覆盖和端口反向转发只解决普通 API 的网络可达性，不能直接完成隔离 Account 的原生登录。当前 Android `NativeAuth.kt` 仅信任正式 `https://account.thestarline.cn` 授权目的地，没有 Debug localhost 例外；本地聊天服务返回本地 Account 授权 URL 时，客户端会拒绝打开。完整隔离原生登录需要另行设计并实现受控测试信任配置，再单独验收，目前没有现成的完整流程。不要放宽正式构建的信任范围，或把模拟器地址写入公开发行包。安装到已有预览设备前先确认签名兼容，不卸载、不清空数据。

## 配置变量目录

配置值应由本地受保护文件或部署系统注入，公开文档只说明名字与用途。生产模式包含固定批准域名、HTTPS 和密钥强度约束，`https://account.example.test/oidc` 这样的合成值仅用于测试构造，不能直接作为生产配置运行。

| 分组 | 变量名 | 用途与边界 |
| --- | --- | --- |
| 身份基础 | `NODE_ENV`、`IDENTITY_HOST`、`IDENTITY_PORT`、`IDENTITY_DATABASE_URL`、`IDENTITY_DB_PREFIX` | 模式、监听和数据库命名空间 |
| 身份安全 | `IDENTITY_SECRET`、`IDENTITY_PII_KEY`、`IDENTITY_PII_MIGRATION_APPROVED`、`IDENTITY_ORIGINS`、`IDENTITY_TRUST_PROXY`、`IDENTITY_OIDC_JWKS_FILE` | 稳定加密材料、PII 迁移审批、精确来源与可信代理 |
| 身份站点 | `IDENTITY_ACCOUNT_ORIGIN`、`IDENTITY_OPEN_ORIGIN`、`IDENTITY_WEBAUTHN_RP_ID` | 页面来源与通行密钥 RP |
| 邮件投递 | `IDENTITY_DELIVERY`、`TENCENT_SES_SECRET_ID`、`TENCENT_SES_SECRET_KEY`、`TENCENT_SES_TEMPLATE_ID` | 当前生产仅使用腾讯 SES；生产禁用开发投递 |
| 非生产邮件备用 | `SMTP_HOST`、`SMTP_PORT`、`SMTP_SECURE`、`SMTP_USER`、`SMTP_PASSWORD`、`SMTP_FROM`、`SMTP_LOCAL_SINK` | 当前 SMTP 不作为生产回退，本地 sink 仅允许非生产回环 |
| 短信 | `ALIBABA_CLOUD_ACCESS_KEY_ID`、`ALIBABA_CLOUD_ACCESS_KEY_SECRET`、`ALIYUN_SMS_SIGN_NAME`、`ALIYUN_SMS_TEMPLATE_CODE` | 当前阿里云短信配置；旧腾讯短信变量不再适用 |
| 人机验证 | `TENCENT_CAPTCHA_APP_ID`、`TENCENT_CAPTCHA_APP_SECRET`、`TENCENT_CAPTCHA_SECRET_ID`、`TENCENT_CAPTCHA_SECRET_KEY` | 开发注册也受门禁，缺配置不模拟通过 |
| 聊天 | `CHAT_HOST`、`CHAT_PORT`、`CHAT_DATABASE_PATH`、`CHAT_ISSUER_URL`、`CHAT_PUBLIC_URL`、`CHAT_CLIENT_ID`、`CHAT_CLIENT_SECRET` | 存储与 confidential OIDC 客户端 |
| 可选服务 | `CHAT_PROFILE_ENCRYPTION_KEY`、`CHAT_CRYPTO_NODE_BUNDLE`、`CHAT_TRUST_PROXY_ALLOWLIST`、`CHAT_IP_CITY_DATABASE_DIR`、`CHAT_MEMORY_MODEL_URL`、`CHAT_MEMORY_MODEL` | 资料加密、MLS 校验、城市与自建模型 |
| 媒体与推送 | `LIVEKIT_URL`、`LIVEKIT_API_KEY`、`LIVEKIT_API_SECRET`、`APNS_TEAM_ID`、`APNS_KEY_ID`、`APNS_KEY_PATH`、`APNS_VOIP_TOPIC`、`APNS_ENVIRONMENT` | 通话媒体与 APNs；密钥留在服务端 |

第三方身份变量还有 `WECHAT_APP_ID`、`WECHAT_APP_SECRET`、`QQ_APP_ID`、`QQ_APP_SECRET`、`ALIPAY_APP_ID`、`ALIPAY_PRIVATE_KEY`、`ALIPAY_PUBLIC_KEY`。配置存在只说明适配器具备材料，不能代替平台开通与真实回调验收。当前管理通行密钥策略由 `IDENTITY_ADMIN_PASSKEY_REQUIRED` 精确值控制，不再是旧副本的生产硬编码；小程序、实名与 PII 的附加条件见[完整配置参考](https://document.thestarline.cn/app/configuration-reference.md)。验证方法见[测试与验收](https://document.thestarline.cn/app/testing.md)，生产处理见[运行维护](https://document.thestarline.cn/app/operations.md)。
