Skip to content

Runtime Settings Reference

Runtime settings are hot-reload settings stored in PostgreSQL. They are mainly for changing product policy while the service is running. They are different from YAML/env/CLI startup configuration:

TypeStorageHot reloadSuitable for
Startup configurationYAML, env, secret files, CLI flagsNo; usually requires restartPorts, database, Redis, secrets, TLS, data_dir, cache enablement
Runtime settingsPostgreSQL settings tableYes; replicas sync through LISTEN/NOTIFYRegistration, room creation, permission defaults, RTMP, CORS, chat retention
Terminal window
synctv settings list
synctv settings get user
synctv settings update --set user.enablePasswordSignup=true

Both --set PATH=VALUE and --unset PATH are repeatable. Plain strings can be unquoted; arrays and objects use JSON:

Terminal window
synctv settings update \
--set email.whitelistEnabled=true \
--set 'email.whitelistDomains=["example.com"]'
synctv settings update --unset email.smtpProxy

The CLI builds the protobuf FieldMask automatically. Paths use lowerCamel leaf fields; --unset clears optional configuration. --request-json accepts a complete UpdateSettingsRequest ProtoJSON document for generated configuration and automated batch requests.

Check the current binary with synctv settings --help.

Runtime settings are written to PostgreSQL and propagated to other replicas through PostgreSQL LISTEN/NOTIFY.

Semantics:

  • Each setting key has a registered typed provider.
  • Writes are type-checked and value-validated before persistence.
  • Cross-key invariants use transactional validation, for example room policy is validated in a single transaction.
  • If a replica misses notifications, it refreshes from a full snapshot.
KeyTypeDefaultValidationMeaning
server.namestring"SyncTV"1..=128 characters, no surrounding whitespace or control charactersPublic server display name
server.allowRoomCreationbooltrueboolWhether users can create rooms
server.maxRoomsPerUseri64101..=1000Maximum rooms per user
server.maxMembersPerRoomi641001..=10000Maximum members per room
server.maxChatMessagesu64500<=10000; 0 means unlimitedService-level public chat message cap policy; cleanup uses chat.maxMessagesPerRoom
KeyTypeDefaultMeaning
permissions.adminDefaultPermissionsPermission-name arrayBuilt-in admin permission setGlobal default permissions for room admin
permissions.memberDefaultPermissionsPermission-name arrayBuilt-in member permission setGlobal default permissions for room member
permissions.guestDefaultPermissionsPermission-name array[]Global default permissions for room guest; only view_members, view_chat_history, use_voice_chat, and use_p2p_media are accepted

These settings are stored as JSON arrays of stable permission names, for example:

["send_chat_messages", "manage_own_media", "browse_library", "view_members"]

permissions.guestDefaultPermissions has a dedicated guest ceiling. It rejects browse_library, send_chat_messages, media-resource, playback-control, and administration permissions. Valid example:

["view_members", "view_chat_history", "use_voice_chat", "use_p2p_media"]

See Roles, Permissions, and Preferences for permission names, role defaults, and room override rules.

KeyTypeDefaultValidationMeaning
room.disableCreateRoomboolfalseboolDisable room creation
room.createRoomNeedReviewboolfalseboolRequire review for room creation
room.passwordPolicyenum stringoptionaloptional, required, forbiddenRoom password policy
KeyTypeDefaultMeaning
user.enablePasswordSignupboolfalseAllow local password signup, including OPAQUE registration and direct password transport registration
user.passwordSignupNeedReviewboolfalseRequire review for password signup
user.enableEmailSignupboolfalseAllow email registration where confirmation sets local password credentials
user.emailSignupNeedReviewboolfalseRequire review for email signup
user.enableWebauthnSignupboolfalseAllow WebAuthn/passkey as the initial account registration method; authenticated passkey binding is not signup
user.webauthnSignupNeedReviewboolfalseRequire review for WebAuthn signup; the review queue stores the pending passkey and approval creates the account with its WebAuthn credential
user.enableGuestbooltrueAllow guest capability

All registration modes are disabled by default. Production deployments should enable only the intended entry points and configure review independently for each mode.

KeyTypeDefaultMeaning
oauth2.providersJSON array[]OAuth2/OIDC provider instance registry. Each element is an OAuth2ProviderSettings ProtoJSON object
oauth2.allowedRedirectUrlsJSON string array[]Allowlist of HTTPS callbacks requested by clients; loopback callbacks are handled separately

oauth2.providers is the OAuth2 configuration entry point. instanceName may contain only ASCII letters, digits, _, and -, and must be at most 64 bytes. Each element uses one provider oneof field such as github or oidc:

Configure the shared callback allowlist as a runtime setting. Store builds commonly use one fixed App Link callback:

Terminal window
synctv settings update --set 'oauth2.allowedRedirectUrls=["https://syncs.tv/oauth2/callback"]'

Apple Services IDs accept registered HTTPS Return URLs. An Apple provider client callback must exactly match that provider’s redirectUrl; macOS and iOS clients should receive this HTTPS callback through ASWebAuthenticationSession.

[
{
"instanceName": "github",
"enableSignup": true,
"signupNeedReview": false,
"github": {
"clientId": "github-client-id",
"clientSecret": "github-client-secret",
"redirectUrl": "https://app.example.com/oauth2/callback"
}
},
{
"instanceName": "corp_oidc",
"enableSignup": false,
"signupNeedReview": false,
"oidc": {
"clientId": "synctv",
"clientSecret": "oidc-client-secret",
"issuer": "https://idp.example.com",
"redirectUrl": "https://app.example.com/oauth2/callback"
}
}
]

A missing provider instance means that login entry point is unavailable. Missing or false enableSignup blocks first-time OAuth2 account creation while existing linked OAuth2 logins continue to work. signupNeedReview=true stores first-time OAuth2 signup in the user registration review queue; approval creates the local account and OAuth2 binding.

User-level 2FA and notification preferences are user preferences. Provider instance bindings are stored on provider credentials created during provider login. See Roles, Permissions, and Preferences.

KeyTypeDefaultMeaning
rtmp.customPublishHoststring/nullnullOptional custom publish host returned to stream publishers
rtmp.tsDisguisedAsPngboolfalseDisguise TS segments as PNG paths or responses

Set it with {"settings":{"rtmp":{"customPublishHost":"rtmp://live.example.com"}},"updateMask":"rtmp.customPublishHost"}. Clear it with {"settings":{"rtmp":{}},"updateMask":"rtmp.customPublishHost"}.

KeyTypeDefaultMeaning
email.enabledboolfalseEnable email delivery
email.smtpHoststring/nullnullSMTP server host
email.smtpPortu16587SMTP server port
email.smtpCredentialsobject/nullnullOptional SMTP credentials {username, password}
email.smtpProxyobject/nullnullOptional SOCKS5 proxy {url, credentials?}
email.useTlsbooltrueUse SMTP TLS
email.fromEmailstring/nullnullSender email address
email.fromNamestring"SyncTV"Sender display name
email.whitelistEnabledboolfalseEnable email allowlist
email.whitelistDomainsstring[][]Email allowlist domains or addresses

When email.whitelistEnabled=true but email.whitelistDomains is empty, no email domain is rejected. Matching is enforced only when the allowlist has entries.

The SOCKS5 proxy URL contains only the scheme, host, and port. Proxy credentials live in smtpProxy.credentials. With a proxy configured, the SOCKS5 server resolves the SMTP target hostname. Updating any SMTP or proxy field invalidates cached connections, and the next message uses the updated configuration.

Optional configuration is updated through its FieldMask path, for example {"settings":{"email":{"smtpProxy":{"url":"socks5://proxy.example.com:1080"}}},"updateMask":"email.smtpProxy"}. Clear the proxy with {"settings":{"email":{}},"updateMask":"email.smtpProxy"}. The same semantics apply to email.smtpHost, email.fromEmail, and email.smtpCredentials. Management reads omit passwords. Updating credentials with an unchanged username and no password preserves the current password.

KeyTypeDefaultValidationMeaning
webrtc.externalIceServersJSON/string structure[]Valid ICE server arrayExternal ICE servers returned to native clients
webrtc.maxVoiceParticipantsPerRoomu3282..=32Maximum simultaneous voice Mesh participants per room

The external list is empty by default. When built-in STUN is enabled and has a client-reachable advertised address, the server adds it to the ICE servers returned to clients. Built-in STUN listener configuration is startup configuration. See WebRTC Configuration.

The voice limit is read dynamically for every join. Lowering it blocks subsequent joins while preserving existing calls; leaving or disconnecting releases a slot immediately. Multi-replica deployments coordinate room slots atomically through Redis.

KeyTypeDefaultValidationMeaning
chat.maxMessagesPerRoomu64500<=100000; 0 means unlimitedMaximum retained chat messages per room
chat.maxPinnedMessagesPerRoomu6420<=1000Maximum retained pinned chat messages per room
chat.messageRetentionDaysi64 days901..=3650Maximum chat message retention age
KeyTypeDefaultMeaning
cors.allowedOriginsJSON/string structure[]Runtime CORS allowed origins for proxy-related paths

Main service startup CORS is server.cors_allowed_origins. Runtime CORS is for policy that can change while the service runs.

Terminal window
synctv settings update --set user.enablePasswordSignup=true
  • Confirm Hot-Reload Scope: Ports, secrets, database, Redis, TLS, and cache enablement are startup configuration, not runtime settings.
  • Read Current Value: Run synctv settings get <key> before changing a value and keep it for rollback.
  • Watch Replicas: Multi-replica sync depends on PostgreSQL notifications; observe all replicas after changes.
  • Record Reason: Keep reasons for registration, room creation, RTMP, and permission-default policy changes.