开发环境
SyncTV 是 Rust workspace,开发时通常需要:
- Rust stable toolchain。
- PostgreSQL。
- Redis。
- Node.js 和 npm,用于
docs/文档站。 - Docker 和 Docker Compose,用于快速启动依赖服务。
- Protobuf/gRPC 相关构建依赖,具体取决于本机平台和 Rust crate 构建过程。
建议先确认:
rustc --versioncargo --versiondocker --versiondocker compose versionnode --versionnpm --version- synctv 核心二进制和 CLI
- synctv-core 业务逻辑、配置、服务和 repository
- synctv-api HTTP/gRPC API
- synctv-livestream RTMP/HLS/HTTP-FLV
- synctv-cluster 集群协调
- synctv-proxy 媒体代理和 slice cache
- synctv-proto protobuf 定义
文件夹helm
- synctv Helm chart
- docs Astro Starlight 文档站
启动开发依赖
Section titled “启动开发依赖”推荐使用 Makefile 入口。make help 会列出所有开发目标。
make dev-upmake dev-up 启动 PostgreSQL 和 Redis,并等待服务就绪。需要完整媒体和认证依赖时:
make dev-stackmake dev-stack 会启动 PostgreSQL、Redis、OpenList、Emby、Jellyfin、RustFS 和 Casdoor,并初始化 Casdoor database、RustFS bucket、OpenList 本地媒体目录、Emby/Jellyfin 管理账号和本地媒体库。常用端口:
| 服务 | 地址 | 默认账号 |
|---|---|---|
| SyncTV | http://127.0.0.1:8080 | root / LocalDevRootPass2026! |
| PostgreSQL | 127.0.0.1:5432 | synctv / synctv |
| Redis | 127.0.0.1:6379 | 无密码 |
| OpenList | http://127.0.0.1:5244 | admin / synctv-openlist |
| Emby | http://127.0.0.1:8096 | MyEmbyUser / synctv-emby |
| Jellyfin | http://127.0.0.1:8097 | root / synctv-jellyfin |
| RustFS | http://127.0.0.1:9000 | rustfsadmin / rustfsadmin |
| RustFS Console | http://127.0.0.1:9001 | rustfsadmin / rustfsadmin |
| Casdoor | http://127.0.0.1:8000 | admin / 123 |
停止容器但保留 volume:
make dev-down清理容器和 volume:
make dev-clean开发 Compose 只启动本地依赖服务,SyncTV 后端由宿主机 cargo run 启动。
Casdoor/OAuth2 provider 仍然通过 runtime settings 配置。启动 Casdoor 后,在 Casdoor 控制台创建应用,再用 synctv settings update oauth2 写入 oauth2.providers。
本机运行服务
Section titled “本机运行服务”Makefile 已经内置本机运行需要的环境变量:
make dev-serve这个目标会先启动 PostgreSQL 和 Redis,然后用本机 cargo run 启动 SyncTV。需要完整依赖时,先运行 make dev-stack。
后台运行使用同一套开发配置:
make dev-startmake dev-stopmake dev-start 会构建 target/debug/synctv、写入 .dev-data/run/synctv.pid,并等待 management socket 和 HTTP readiness。make dev-smoke 也通过这个入口启动 SyncTV。
手动流程:
-
确认依赖服务已启动:
Terminal window make dev-up -
为当前 shell 导出本机开发配置:
Terminal window export SYNCTV_DATABASE_URL="postgresql://synctv:synctv@localhost:5432/synctv"export SYNCTV_REDIS_URL="redis://localhost:6379"export SYNCTV_JWT_SECRET="local-compose-jwt-secret-not-for-production-2026"export SYNCTV_CLUSTER_SECRET="local-compose-cluster-secret-2026"export SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY="222102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"export SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET="local-compose-opaque-server-setup-secret-not-for-production-2026"export SYNCTV_BOOTSTRAP_CREATE_ROOT_USER="true"export SYNCTV_BOOTSTRAP_ROOT_PASSWORD="LocalDevRootPass2026!" -
校验配置:
Terminal window cargo run -p synctv --bin synctv -- config validate -
启动服务:
Terminal window cargo run -p synctv --bin synctv -- serve
导出上述环境变量后,也可以直接运行:
cargo run -p synctv --bin synctv -- serve使用指定配置文件:
cargo run -p synctv --bin synctv -- serve --config synctv.yaml只验证配置、不真正启动:
cargo run -p synctv --bin synctv -- serve --config synctv.yaml --dry-run开发时修改配置结构后,先跑:
cargo run -p synctv --bin synctv -- config --config synctv.yaml validate查看最终合并后的配置,secret 会被隐藏:
cargo run -p synctv --bin synctv -- config --config synctv.yaml showcargo run -p synctv --bin synctv -- config --config synctv.yaml show --output json配置来源优先级和环境变量规则见 配置文件如何工作。
服务启动阶段会自动执行 embedded SQLx migrations。需要在不启动服务的情况下预检数据库状态时,可以单独执行:
cargo run -p synctv --bin synctv -- db migrate检查数据库连接和迁移状态:
cargo run -p synctv --bin synctv -- db status开发中如果数据库状态异常,优先检查:
SYNCTV_DATABASE_URL或database.url。- PostgreSQL 容器是否健康。
- migration 文件是否与代码期望一致。
- 当前分支是否有未应用的 schema 变更。
Schema 边界
Section titled “Schema 边界”迁移只负责持久化结构和稳定的数据完整性。数据库适合表达主键、外键、必要存储列、查询索引、唯一索引,以及很少随产品策略变化的物理约束。
不要把易变业务策略写进 SQL 约束。业务枚举值列表、审核状态、房间/成员角色、Provider 类型、权限规则、runtime settings 白名单、播放限制、房间策略、封禁/审核流程等产品级校验应放在领域层或服务层,用类型和测试约束行为。status、role、signup_method、message_type、审核状态等枚举式字段入库应使用数字码(通常 SMALLINT 足够),不要用字符串或数据库 enum 类型保存。
如果直接写 SQL 可能制造业务非法状态,优先收紧服务写路径、增加一致性巡检或修复工具。
UNIQUE 可以用于稳定身份或几乎不会变化的唯一性不变量,尤其是需要数据库原子性时,例如用户名、邮箱、Provider 实例名、OAuth 账号身份、幂等键,以及“某个稳定作用域只能有一条当前有效记录”这类模式。不要把可能在普通产品迭代中被放宽、改作用域或重新解释的策略写成 UNIQUE。只有当某条规则独立于业务策略、确实是长期存储不变量时,才把它下沉到数据库。
面向用户展示的标签和显示名,例如房间名,默认属于产品策略,除非它们被明确设计成稳定身份标识。需要并发安全时,在服务层用事务锁或其他协调机制保证行为。
CI 等价的非 ignored 测试:
cargo nextest run --workspace --locked --run-ignored default --nff文档测试:
cargo test --workspace --doc --locked需要 Docker/PostgreSQL/Redis 的 ignored 测试:
cargo nextest run --workspace --locked --run-ignored only --nff只跑某个 crate:
cargo nextest run -p synctv-api --locked --run-ignored default --nff只跑某个测试:
cargo nextest run -p synctv-api test_name --locked --run-ignored default --nff格式检查:
cargo fmt --all --checkClippy:
cargo clippy --workspace --all-targets --locked -- -D warnings不要对整个 workspace 使用 --all-features:部分 feature 组合是刻意互斥的,
例如 mimalloc/jemalloc 和 tls-aws-lc/tls-ring。非默认构建应使用显式
feature 组合检查。TLS 的约定是:tls-aws-lc / tls-ring 选择 rustls crypto
provider,tls-webpki-roots / tls-native-roots 选择信任根来源;这个约定会在上游
crate 暴露对应开关的地方传播。少数依赖有自己的限制:SQLx 0.8 的 native roots
只能通过 ring 后端启用,reqwest 0.13 使用 platform verifier;基础邮件 TLS 保留
webpki roots,因为 lettre 编译 rustls 时要求至少启用一个 verifier/root feature。
修改 TLS 相关代码时至少检查 provider 与 root 的四个组合:
cargo check -p synctv --no-default-features --lockedcargo check -p synctv --no-default-features --features "tls-aws-lc,tls-webpki-roots" --lockedcargo check -p synctv --no-default-features --features "tls-aws-lc,tls-native-roots" --lockedcargo check -p synctv --no-default-features --features "tls-ring,tls-webpki-roots" --lockedcargo check -p synctv --no-default-features --features "tls-ring,tls-native-roots" --lockedcargo check -p synctv --no-default-features --features "k8s,mimalloc,tls-aws-lc,tls-webpki-roots,tls-native-roots" --locked如果修改了特定功能,优先跑对应的聚焦测试,再跑更大的测试集。编译通过只是最低检查。
Provider 与播放端到端验证
Section titled “Provider 与播放端到端验证”修改 Provider、播放 URL 签名、proxy、manifest、字幕、danmaku、thumbnail、RTMP、live proxy、播放后台任务或资源生命周期时,需要在单元测试之外做真实服务验证:
- 使用构建出的
synctv二进制启动服务,覆盖真实启动、配置、migration 和路由; - 使用
synctvCLI 创建用户、房间、Provider、媒体、动态播放列表、RTMP publish key 和播放状态; - 使用真实 WebSocket 让房间进入 active 状态;
- 使用
curl请求每个返回的 direct/proxy URL、manifest、indexed segment、字幕、danmaku、thumbnail 和 Range URL; - 覆盖 Direct URL、Alist、Emby、Jellyfin、Bilibili 匿名播放、RTMP、live proxy、HLS、FLV、cache MISS/HIT、URL 过期和资源清理;
- 覆盖动态 playlist 的路径返回、媒体解析、播放、切换、封面/thumbnail 路由和自动切换后的 target 变化;
- RTMP/live proxy 使用真实上游推流,验证 stream info、HLS playlist/segment、FLV、断开后的 idle cleanup;
- CLI 缺少某个工作流时,先补
synctvCLI,再把该工作流纳入手动 E2E。
Provider 返回的 PlaybackResult 是验证清单。每个 mode 和辅助 URL 都要实际请求,包含动态 playlist 解析出的媒体项。播放后台任务使用当前进程 ConnectionRuntime::active_room_ids(),验证时通过真实 WebSocket 驱动 active room,避免用数据库写入替代连接生命周期。
SQLx offline metadata
Section titled “SQLx offline metadata”数据库查询如果使用 SQLx macros,会在编译期检查 SQL,并把 metadata 缓存在 .sqlx/。修改 SQL、migration 或查询返回类型后需要刷新。
需要编译期校验的 repository 查询应继续使用 SQLx checked macros。更新 .sqlx 是正常开发流程,metadata 变更属于 SQL 改动的一部分。
播放后台任务相关查询还需要保留 room-scoped 过滤和当前 room_playback_progress.target_hash 绑定。修改这些 SQL 时,代码、.sqlx metadata 和 active-room E2E 证据一起更新。
刷新流程:
make dev-cleanmake dev-up
local_database_url="postgresql://synctv:synctv@localhost:5432/synctv"
SYNCTV_DATABASE_URL="$local_database_url" \cargo run -p synctv --bin synctv -- db migrate
DATABASE_URL="$local_database_url" \cargo sqlx prepare --workspace
SQLX_OFFLINE=true cargo check --workspace --all-targetsOpenAPI 功能
Section titled “OpenAPI 功能”内置 OpenAPI 文档由 openapi feature 启用。开发者获取方式见 OpenAPI 文档入口。
常用检查:
cargo check --workspace --all-targets --features openapi启动带 Swagger UI 的服务:
cargo run -p synctv --features openapi --bin synctv -- serve文档站在 docs/ 目录,是独立的 Astro Starlight 项目。
首次安装依赖:
cd docsnpm install本地预览:
cd docsnpm run dev构建:
cd docsnpm run build如果文档站部署在域名子路径下,构建时指定 SYNCTV_DOCS_BASE。如果需要正确生成 canonical URL 和 sitemap,同时指定 SYNCTV_DOCS_SITE。
cd docsSYNCTV_DOCS_SITE=https://example.com SYNCTV_DOCS_BASE=/synctv npm run buildSYNCTV_DOCS_BASE 只表示路径前缀,例如 /synctv、/docs。部署在域名根路径时不需要设置。
构建输出在 docs/dist,它是生成产物,不需要提交。
修改 CLI 时
Section titled “修改 CLI 时”CLI 定义在 synctv/src/cli/。修改命令或参数后至少检查:
cargo run -p synctv --bin synctv -- --helpcargo run -p synctv --bin synctv -- user --helpcargo run -p synctv --bin synctv -- provider --help如果新增命令,也要更新 CLI 参考。
修改 Helm 或 Compose 时
Section titled “修改 Helm 或 Compose 时”Helm:
helm lint ./helm/synctvhelm template synctv ./helm/synctvhelm template synctv ./helm/synctv --set ingress.grpc.enabled=trueCompose:
docker compose -f docker-compose.dev.yml configdocker compose config注意:渲染成功只说明 YAML 语法和模板基本可用,不代表业务配置安全。还要运行 SyncTV 配置校验或实际启动验证。
- 新增配置字段时,同时更新 配置总索引、完整配置示例 和对应配置专题页。
- 新增 CLI 命令时,同时更新 CLI 参考。
- 修改部署模板时,同时更新 Docker Compose 部署 或 Helm 部署。
- 修改常见错误、端口、Ingress、认证或代理行为时,同步更新 排障入口。
- 修改运行时入口、依赖关系、Provider/proxy 边界或集群模型时,同步更新 架构总览。
- 修改登录、2FA、OAuth2、token、management 或权限边界时,同步更新 认证与安全模型。
- 修改用户、房间、审核、Provider、runtime settings 或管理 CLI 语义时,同步更新 管理 SyncTV。
- 修改房间角色、权限名称、room settings、成员覆盖或用户偏好时,同步更新 房间、权限与用户偏好。
- 修改
SettingsRegistry注册的热更新字段时,同步更新 Runtime settings 参考。 - 修改 API feature、Swagger UI 路径或 OpenAPI JSON 路径时,同时更新 OpenAPI 文档入口。
- 修改 cluster/admin/service protobuf 时,同时更新 gRPC 调试。
- 修改 HTTP、gRPC、Realtime 或 protobuf 协议语义时,同时更新 API 与 protobuf 演进策略、SDK 与 API 示例 和 错误参考。
- 修改 metrics 指标名称、标签或含义时,同时更新 Metrics Catalog 和 观测与运行手册。