Skip to content

PlayoutAdmin — Environment Variables & Changelog

2026-07-12 — VOD media serving moved off CoreAPI (cproxy passthrough)

Why: CoreAPI's /assets/* route (ServeAsset) streamed every media byte through the Fiber app process — the same process handling DB writes, tusd webhooks, and thumbnail generation. This put a control-plane service in the data plane for all VOD traffic. Phase 1 removes CoreAPI from that path entirely: a cproxy node now caches reads directly from SeaweedFS.

New chain:

Browser → nginx (/assets/) → cproxy_vod:8080 → SeaweedFS:8333
(Previously: Browser → nginx (/assets/) → CoreAPI:3000 → SeaweedFS)

Backend change — bucket now embedded in asset URLs

CoreAPI/domain/media/models.goPublicURL()/ThumbURL() now include the Bucket field, since cproxy/SeaweedFS's S3 gateway requires /<bucket>/<key> in the path (no implicit default bucket, unlike CoreAPI's old ServeAsset which silently assumed one).

before: /assets/jastv/banner/hero.jpg
after:  /assets/playtelly/jastv/banner/hero.jpg

No DB migration needed — Bucket was already populated on every Media row; this is a computed-field change only, takes effect immediately on restart.

nginx — /assets/ proxy target changed

nginx.conf.template/assets/ now proxies to ${ASSET_SERVING_URL} (cproxy) instead of ${COREAPI_URL}. Trailing slash on proxy_pass strips the /assets/ prefix before forwarding, since cproxy/SeaweedFS has no such namespace — it expects the bucket-prefixed path directly.

GET /assets/playtelly/jastv/vod/a.mp4
  → http://cproxy_vod:8080/playtelly/jastv/vod/a.mp4
  → http://seaweedfs:8333/playtelly/jastv/vod/a.mp4

cproxy — new node added

New service cproxy_vod in seaweedfs.yml, config in cproxy-vod.yml. Single static passthrough origin, url-pattern: ^/.*$ (bucket-agnostic — forwards whatever path it receives straight to SeaweedFS's S3 gateway). Host-exposed on 9222 (proxy) / 9221 (api) for local curl-testing; internal container-network address is cproxy_vod:8080.

MediaList.jsx — previously used window.location.origin to build asset URLs. Now uses two separate env-driven constants:

const ASSET_BASE = import.meta.env.VITE_ASSET_BASE_URL || ""
const CDN_HOST = import.meta.env.VITE_CDN_HOST || ASSET_BASE
  • ASSET_BASE — used for anything rendered inline inside the admin app itself (thumbnails, video/audio/image preview player). Same-origin, goes through this app's own nginx.
  • CDN_HOST — used only for copyable/shareable/downloadable links (the "URL" / "Thumbnail URL" rows, document download button). Falls back to ASSET_BASE until a real public CDN exists.

Both resolve to the same value today (VITE_CDN_HOST unset locally) — this is a zero-behavior-change addition, wiring the split ahead of the real CDN going live.


Environment Variables

Build-time (Vite — baked into JS bundle, requires image rebuild to change)

Variable Local value Role Status
VITE_ASSET_BASE_URL http://localhost:15173 Same-origin base URL for in-app media preview/thumbnails, proxied through this app's own nginx. Active
VITE_CDN_HOST "" (unset) Public CDN hostname for shareable/downloadable asset links. Falls back to VITE_ASSET_BASE_URL when empty. Active, pending real value — set to https://cdn.castis.io (or equivalent) once CDN/GSLB tier exists
VITE_CORE_API_URL http://localhost:3000 Base URL for axios clients in utils/api.js. Wired but consumer file (utils/api.js) is unimported/dead — no functional effect
VITE_AUTH_API_URL http://localhost:3002 Same as above. Same as above
VITE_TELLYID_URL passed as ${VITE_AUTH_URL} Fallback/default for TellyID auth service URL. Activeutils/auth.js
VITE_AUTH_URL from root .env Auth redirect flow. Activecomponents/sideBar/Sidebar.jsx
NPM_AUTH from root .env .npmrc auth for private @playtelly registry. Build-stage only. Active (build infra)

Runtime (container env — read by nginx via envsubst, no rebuild needed)

Variable Local value Role Status
COREAPI_URL http://coreapi:3000 Upstream for /api/ proxy block. Active
ASSET_SERVING_URL http://cproxy_vod:8080 Upstream for /assets/ proxy block. Active (new 2026-07-12, was ${COREAPI_URL} before)
TUSD_URL http://tusd:8080 Upstream for /files/ proxy block (tus resumable upload). Active
FORWARDED_HOST Was intended for forwarded-host header context. Dead — confirmed zero references anywhere in nginx template; removed

Historical / dead, not part of current architecture

  • ASSET_BASE_URL (CoreAPI-side env) — deliberately removed per 2026-06-19 refactor (see changelog below). CoreAPI no longer bakes any frontend host into API responses.
  • utils/api.js — contains references to VITE_CORE_API_URL/ VITE_AUTH_API_URL but the file itself is dead code (unimported, contains an undefined-variable bug). Not part of the media-serving path.

Prior changelog

2026-06-19 — Asset URL refactor, relative paths, unified /assets/ route

Why: Backend was baking ASSET_BASE_URL (frontend host) into API responses, coupling CoreAPI to wherever the frontend was deployed.

What changed:

models.goPublicURL()/ThumbURL() return relative paths:

before: http://localhost:15173/media-assets/jastv/banner/hero.jpg
after:  /assets/jastv/banner/hero.jpg

config.goAssetBaseURL field removed, ASSET_BASE_URL env no longer read by CoreAPI.

Route unified to /assets/* (previously mismatched with /media-assets/* returned by models.go).

nginx location /media-assets/ replaced with location /assets/.

Superseded by 2026-07-12 change above — bucket segment re-added to the path (/assets/<bucket>/<key>) to support cproxy/SeaweedFS's S3-gateway path requirements.