## Summary
- add an asynchronous admin chat moderation job pipeline for message,
reaction, and ban cleanup
- expose the moderation operation through HTTP/gRPC admin APIs and
persist resumable worker progress
- remove the obsolete version parameter from the async moderation path
while retaining CAS for synchronous chat edits/deletes
## Verification
- cargo check --workspace --all-targets
- cargo test -p synctv-core --lib (1350 passed)
- cargo test -p synctv-api-common --lib (655 passed)
- PostgreSQL moderation race regression passed
## Summary
- add a `web-ui-dynamic` feature that serves a mutable Web distribution
without compile-time embedding
- add `server.web_ui_directory` and `SYNCTV_SERVER_WEB_UI_DIRECTORY`,
with per-request disk reads, SPA fallback, security headers, and path
containment checks
- keep `web-ui` release builds embedded while allowing the same
production binary and Docker image to use a mounted runtime directory
- configure `make dev-serve` to use `synctv-web-ui/dist` and document
both modes
## Docker behavior
CI continues to build release images with `web-ui`, so embedded assets
remain the default. Mounting a distribution and setting
`SYNCTV_SERVER_WEB_UI_DIRECTORY` makes that directory authoritative at
runtime.
## Verification
- `cargo fmt --all -- --check`
- `git diff --check`
- `cargo test -p synctv-api-http --features web-ui-dynamic
http::web_ui::tests`
- `cargo test -p synctv-api-http --features web-ui http::web_ui::tests`
- `cargo check -p synctv --features web-ui-dynamic`
- `cargo check -p synctv --features web-ui`
## Summary
- disable the built-in SyncTV STUN server by default across application,
Compose, image, environment, and Helm configuration
- default `webrtc.externalIceServers` to Cloudflare and Google public
STUN endpoints while preserving persisted overrides and explicit `[]`
- update deployment validation, tests, examples, and English/Chinese
documentation
Tailscale is not included because it publishes STUN endpoints through
its dynamic DERP map and does not provide a stable general-purpose
hostname suitable for this default.
## Testing
- `cargo fmt --all -- --check`
- `cargo test -p synctv-core --test global_settings_registry_tests`
- `cargo test -p synctv-core
test_runtime_settings_default_to_public_stun_servers`
- `cargo test -p synctv default_webrtc_config_disables_builtin_stun`
- `cargo check --workspace --all-targets`
- `bash scripts/validate-helm.sh`
- Compose configuration rendering
- `npm run validate:content`
- `npm run check`
- `git diff --check`
## Summary
- split room, node, and global presence into authenticated member and
anonymous guest counts
- deduplicate member and guest actors independently while retaining
total connection counts
- update discovery ordering and realtime online-count messages to use
the separated values
- remove the previous mixed online-user field as a breaking protocol
change
Frontend: https://github.com/synctv-org/synctv-app/pull/41
## Verification
- make nextest-default (5231 passed)
- make clippy-check
- make proto-freshness
- cargo fmt --all -- --check
- git diff --check
## Summary
- send a typed realtime termination message before server-initiated
WebSocket disconnects
- restore the view_playback_history permission bit across effective
permissions and runtime settings round trips
- remove the unused common ErrorCode enum and document the dedicated
termination codes
## Validation
- make nextest: 6715 passed
- make clippy
- git diff --check
## Summary
- Add recoverable soft deletion for users, rooms, playlists, media, and
chat messages, with retention-based physical cleanup.
- Hide deleted users and owned resources from active API, room,
playback, messaging, and realtime paths while preserving restoration
metadata.
- Add user lifecycle administration across HTTP, gRPC, management
runtime, and SyncTV CLI, including deleted-user listing and restore
operations.
- Add lifecycle migration, cleanup orchestration, audit fields,
resource-change events, and refreshed SQLx offline metadata.
## Design
- Model account, administrator, system, room, and user deletion sources
explicitly so cascade ownership and audit history remain deterministic.
- Release email and OAuth identity occupancy during deletion;
restoration reclaims available identities and reports conflicts
according to restore options.
- Preserve recoverable aggregate rows during the retention window,
remove ephemeral membership and playback state immediately, and purge
expired data in dependency order.
- Wait for realtime observation acknowledgements before publishing
lifecycle changes to avoid subscription registration races.
## Verification
- `make nextest`: 6707 passed, 0 skipped
- `make clippy`: passed for the workspace and all targets
- `make clippy-check`: passed
- `cargo fmt --all -- --check`: passed
- `git diff --check`: passed