refactor: rename relay to plyr.fm (#83)

* refactor(config): rename relay to plyr.fm

- update app name from 'relay' to 'plyr.fm'
- update canonical host to plyr.fm
- update broadcast channel prefix to 'plyr'
- update CORS default regex to include plyr.fm
- update database default URL to plyr
- update atproto namespace from 'app.relay' to 'app.plyr'
- add old_app_namespace field for migration support
- add old_track_collection computed field
- update resolved_scope to include both old and new namespaces when migrating

* chore(infra): update R2 bucket references to generic names

- production: relay → audio-prod
- staging: relay-stg → audio-staging
- update public bucket URLs to new buckets

* chore(frontend): rename wrangler project from relay to plyr

* docs: update project name from relay to plyr in root docs

authored by zzstoatzz.io and committed by GitHub 34d608d9 da634904

Changed files
+37 -18
frontend
src
backend
+3 -3
CLAUDE.md
··· 1 - # relay 1 + # plyr 2 2 3 3 music streaming platform on ATProto. 4 4 ··· 14 14 ## structure 15 15 16 16 ``` 17 - relay/ 18 - ├── src/relay/ 17 + plyr/ 18 + ├── src/backend/ 19 19 │ ├── api/ # public endpoints (see api/CLAUDE.md) 20 20 │ ├── _internal/ # internal services (see _internal/CLAUDE.md) 21 21 │ ├── models/ # database schemas
+2 -2
fly.staging.toml
··· 14 14 [env] 15 15 ATPROTO_PDS_URL = 'https://pds.zzstoatzz.io' 16 16 PORT = '8000' 17 - R2_BUCKET = 'relay-stg' 17 + R2_BUCKET = 'audio-staging' 18 18 R2_ENDPOINT_URL = 'https://8feb33b5fb57ce2bc093bc6f4141f40a.r2.cloudflarestorage.com' 19 - R2_PUBLIC_BUCKET_URL = 'https://pub-3b2a5274e4f4408cb8b5e0653f300116.r2.dev' 19 + R2_PUBLIC_BUCKET_URL = 'https://pub-0a0a2e70496c461581c9fafb442b269d.r2.dev' 20 20 STORAGE_BACKEND = 'r2' 21 21 22 22 [http_service]
+2 -2
fly.toml
··· 27 27 [env] 28 28 PORT = '8000' 29 29 STORAGE_BACKEND = 'r2' 30 - R2_BUCKET = 'relay' 30 + R2_BUCKET = 'audio-prod' 31 31 R2_ENDPOINT_URL = 'https://8feb33b5fb57ce2bc093bc6f4141f40a.r2.cloudflarestorage.com' 32 - R2_PUBLIC_BUCKET_URL = 'https://pub-841ec0f5a7854eaab01292d44aca4820.r2.dev' 32 + R2_PUBLIC_BUCKET_URL = 'https://pub-d4ed8a1e39d44dac85263d86ad5676fd.r2.dev' 33 33 ATPROTO_PDS_URL = 'https://pds.zzstoatzz.io' 34 34 35 35 # secrets to set via: fly secrets set KEY=value
+1 -1
frontend/wrangler.toml
··· 1 - name = "relay" 1 + name = "plyr" 2 2 compatibility_date = "2024-01-01" 3 3 compatibility_flags = ["nodejs_compat"] 4 4 pages_build_output_dir = ".svelte-kit/cloudflare"
+29 -10
src/backend/config.py
··· 59 59 """Core application configuration.""" 60 60 61 61 name: str = Field( 62 - default="relay", 62 + default="plyr.fm", 63 63 description="Public-facing application name", 64 64 ) 65 65 tagline: str = Field( ··· 80 80 description="Interval for background tasks in seconds", 81 81 ) 82 82 canonical_host: str = Field( 83 - default="relay.zzstoatzz.io", 83 + default="plyr.fm", 84 84 description="Canonical host used for metadata and share links", 85 85 ) 86 86 canonical_url_override: str | None = Field( ··· 88 88 description="Override canonical URL if it differs from https://{canonical_host}", 89 89 ) 90 90 broadcast_channel_prefix: str = Field( 91 - default="relay", 91 + default="plyr", 92 92 description="Prefix used for browser BroadcastChannel identifiers", 93 93 ) 94 94 ··· 119 119 cors_origin_regex: str | None = Field( 120 120 default=None, 121 121 validation_alias="FRONTEND_CORS_ORIGIN_REGEX", 122 - description="CORS origin regex pattern (if not set, uses default for relay-4i6.pages.dev)", 122 + description="CORS origin regex pattern (if not set, uses default for plyr.fm and relay-4i6.pages.dev)", 123 123 ) 124 124 125 125 @computed_field ··· 129 129 if self.cors_origin_regex is not None: 130 130 return self.cors_origin_regex 131 131 132 - # default: allow localhost for dev + cloudflare pages (including preview deployments) 133 - return r"^(https://([a-z0-9]+\.)?relay-4i6\.pages\.dev|http://localhost:5173)$" 132 + # default: allow localhost for dev + plyr.fm + cloudflare pages (including preview deployments) 133 + return r"^(https://(www\.)?plyr\.fm|https://([a-z0-9]+\.)?relay-4i6\.pages\.dev|http://localhost:5173)$" 134 134 135 135 136 136 class DatabaseSettings(RelaySettingsSection): 137 137 """Database configuration.""" 138 138 139 139 url: str = Field( 140 - default="postgresql+asyncpg://localhost/relay", 140 + default="postgresql+asyncpg://localhost/plyr", 141 141 validation_alias="DATABASE_URL", 142 142 description="PostgreSQL connection string", 143 143 ) ··· 202 202 description="OAuth redirect URI", 203 203 ) 204 204 app_namespace: str = Field( 205 - default="app.relay", 205 + default="app.plyr", 206 206 validation_alias="ATPROTO_APP_NAMESPACE", 207 207 description="ATProto app namespace used for record collections", 208 208 ) 209 + old_app_namespace: str | None = Field( 210 + default=None, 211 + validation_alias="ATPROTO_OLD_APP_NAMESPACE", 212 + description="Optional previous ATProto namespace for migration (e.g., 'app.relay'). When set, OAuth scopes will include both old and new namespaces.", 213 + ) 209 214 scope_override: str | None = Field( 210 215 default=None, 211 216 validation_alias="ATPROTO_SCOPE_OVERRIDE", ··· 220 225 @computed_field 221 226 @property 222 227 def track_collection(self) -> str: 223 - """Collection name for relay audio records.""" 228 + """Collection name for plyr audio records.""" 224 229 225 230 return f"{self.app_namespace}.track" 226 231 227 232 @computed_field 228 233 @property 234 + def old_track_collection(self) -> str | None: 235 + """Collection name for old namespace, if migration is active.""" 236 + 237 + if self.old_app_namespace: 238 + return f"{self.old_app_namespace}.track" 239 + return None 240 + 241 + @computed_field 242 + @property 229 243 def resolved_scope(self) -> str: 230 - """OAuth scope, falling back to the repo scope for the configured namespace.""" 244 + """OAuth scope, falling back to the repo scope for the configured namespace(s).""" 231 245 232 246 if self.scope_override: 233 247 return self.scope_override 248 + 249 + # if we have an old namespace, request access to both collections 250 + if self.old_app_namespace: 251 + return f"atproto transition:generic repo:{self.track_collection} repo:{self.old_track_collection}" 252 + 234 253 return f"atproto repo:{self.track_collection}" 235 254 236 255