Better YouTube Studio: current architecture

A repo-grounded map of the Cloudflare system, its request and data flows, and the highest-leverage polishing work.

Client surfaces
4
Web, mobile, CLI, MCP
Durable Object types
5
Each with private SQLite
Web route entrypoints
19
Pages, remotes, and HTTP routes
Test files
29
Web, Workers, mobile, and CLI
The architectural center is sound

The web Worker is the system of record, but authority, Google secrets, user preferences, device authorization, and channel analytics live in separate Durable Objects. That is a good security and scaling boundary. Polish around it; do not collapse it into one shared database.

1. System shape

This is a pnpm and Vite+ monorepo. apps/web is both the browser application and the backend; apps/mobile and apps/cli are authenticated consumers of its HTTP API; MCP clients use the same backend through a stateless Streamable HTTP endpoint. packages/shared carries the primary analytics response types and formatting helpers.

The request path, from user surface to external data
LayerWhat lives herePrimary responsibility
ClientsSvelteKit web, Expo mobile, Node CLI, MCP clientsPresent analytics and initiate authorization
Cloudflare edgeSvelteKit Worker, server routes, remote functions, static assetsAuthenticate requests, validate inputs, and expose product interfaces
Application servicesconnections.ts, dashboard.ts, MCP tool adapterResolve the active channel and orchestrate use cases
State and policyFive SQLite Durable Object classesOwn authorization, credentials, tokens, preferences, and cached channel data
External systemsClerk and three YouTube APIsIdentity, channel metadata, analytics, comments, and reach reports

The architectural sentence

A request proves a Clerk session or a channel-pinned machine credential, asks the organization catalog which Google grant may access the channel, obtains a short-lived token from that grant object, and then asks the channel object for cached or fresh analytics.

2. Request walkthrough

Browser dashboard

  1. hooks.server.ts authenticates the request with Clerk and records user, session, organization, and admin status in SvelteKit locals.
  2. The page calls SvelteKit remote queries in data.remote.ts. Those queries delegate to the dashboard application service instead of talking to Google directly.
  3. resolveEffectiveChannel reads the organization catalog from OrgDO and the browser-session preference from UserDO. A preference is scoped by session and organization, so separate browser sessions can select different channels.
  4. resolveAuthorizedChannel asks OrgDO for active grant sources, then asks the chosen GoogleGrantDO for a usable access token.
  5. dashboard.ts calls the per-channel ChannelDO. Fresh cache entries return immediately; stale or missing entries trigger YouTube API work.
  6. The response can contain both data and an error. That is intentional: known-good stale data remains visible during a Google outage.

Connecting Google

  1. An organization admin starts OAuth. The route creates encrypted state, PKCE material, a same-session nonce cookie, and an exact callback URL.
  2. The callback verifies user, session, organization, nonce, and return path before exchanging the authorization code.
  3. The app fetches the Google profile and all channels owned by that Google or Brand Account identity.
  4. A new GoogleGrantDO receives encrypted token material; OrgDO updates the grant-to-channel catalog; each discovered ChannelDO activates that organization and grant as a source.
  5. Reconnecting the same Google subject supersedes older active grants and deactivates their channel sources.

CLI, mobile, and MCP

Machine credentials use the routable dyt_v2 envelope. The locator identifies the owning organization but grants no authority: OrgDO stores only a hash of the full credential and rechecks kind, revocation, scope, and current channel membership on every request.

  • CLI: starts a ten-minute device flow, opens an approval page, polls, and stores the one-time returned credential in a mode-600 config file.
  • Mobile: uses a browser authorization handoff and returns a channel-pinned credential through an allowed deep-link scheme; the app stores it in SecureStore.
  • MCP: admins mint and revoke channel-pinned keys in /mcp/setup. The endpoint is stateless JSON-RPC over POST, with independent IP and locator rate limits.

3. State ownership

Durable Object identity is part of the authorization model, not just a storage choice. Each object validates that its stable name matches the entity it claims to represent.

Five object types and their invariants
ObjectIdentity keyOwnsImportant invariant
UserDOClerk userPer-session, per-organization selected channelPreference expires and never becomes a global user setting
OrgDOClerk organizationGrant catalog, channels, credentials, audit eventsThis is the authorization boundary for every channel and machine credential
GoogleGrantDOOrganization + grantEncrypted access/refresh tokens and discovered channel idsLong-lived Google secrets do not enter ChannelDO
ChannelDOYouTube channelMetadata, videos, reports, comments, reach, refresh coordinationEvery RPC proves an active organization/grant source before data access
DeviceFlowDOEphemeral flow idApproval state and encrypted one-time credential handoffA credential can be claimed once and the object cleans itself up by alarm
Why one ChannelDO can serve several organizations safely

The channel data is canonical and shareable, while channel_orgs and refresh_sources record which organization/grant pairs may use it. The caller supplies only a short-lived access token after OrgDO and GoogleGrantDO have approved the path.

4. Data lifecycle and freshness

  • Read-through cache: dashboard, summary, top-video, video, recent-video, and chronological comment snapshots have a 15-minute freshness window.
  • Stale-good behavior: an upstream failure returns cached data with an in-band warning whenever possible.
  • Deduplication: concurrent requests for the same report share one in-flight promise inside the object instance.
  • Generation ordering: refresh generations prevent a slower, older request from overwriting newer data.
  • Manual refresh: a 30-second durable cooldown is recorded before upstream I/O; complete snapshots are promoted atomically.
  • Background refresh: alarms refresh full-history data about every 45 minutes with jitter, and stop after repeated failures until an interactive request re-arms the loop.
  • Reach: YouTube Reporting jobs and CSV reports are ingested separately. Reach history is durable, can lag, and is explicitly not presented as YouTube Studio parity.
The main complexity concentration

ChannelDO is roughly 1,700 lines because it combines its RPC surface, authorization assertions, cache policy, refresh coordination, Google fan-out, persistence, reach ingestion, comments, alarms, and serialization guards. The object boundary is good; the implementation boundary is ready to be split.

5. Product surfaces

What each surface currently exposes
SurfaceAuthenticationPrimary capabilitiesCurrent edge
WebClerk session + organizationConnection management, channel switching, dashboard, reach, video analytics, MCP key setupFull control plane
Expo mobileAdmin-approved mobile credential in SecureStoreDashboard, date ranges, video analytics, native sharingFocused native reader
Node CLIDevice-flow credential in local configDashboard and video reports, human or JSON outputAutomation-friendly
MCPAdmin-minted, pinned MCP keySix read-only analytics and comment toolsAgent interface

The web app uses shared application services directly through SvelteKit remote functions. Mobile and CLI use REST routes. MCP adapts the same dashboard service into tool results. This convergence is a real strength: differences between surfaces are mostly transport and presentation, not separate data implementations.

6. Development and delivery

Local topology

Production exports all five Durable Object classes from the SvelteKit Worker. Local Vite development cannot host those classes through getPlatformProxy, so the repo starts a second Wrangler worker named byts-do on port 8788 and points the web bindings at it through Wrangler's dev registry. The repo scripts own startup, port checks, protocol choice, and cleanup.

New worktrees run pnpm setup:worktree to copy ignored local configuration safely, install dependencies, and verify generated bindings. Vite+ orchestrates formatting, checking, linting, and tests across packages, while the Expo app keeps its own Jest, ESLint, Metro, and TypeScript compatibility tooling.

Deployment topology

  1. A pull request runs install, check, lint, and test on Depot infrastructure.
  2. A push to main repeats the quality gate.
  3. The pipeline builds and deploys the staging Worker, then smoke-checks its homepage.
  4. Only after staging responds does it build and deploy the production Worker and smoke-check the custom domain.
Production runtime
Cloudflare Workers + Static Assets + SQLite Durable Objects
Production domain
byts.davis7.space
Staging runtime
Separate byts-staging Worker and object namespaces
Observability
Worker logs sampled at 100%; traces sampled at 10%

7. Recommended polish agenda

The sequence below favors visible coherence first, then reduces architectural friction without disturbing the state model.

Highest-leverage work in recommended order
PriorityWorkstreamWhy nowConcrete outcome
1Choose one product identityThe repo simultaneously says Better YouTube Studio, byts, and Deep YT Data.One naming system for app titles, package/bin names, OAuth copy, mobile metadata, MCP server info, and docs.
2Make the API contract executableMobile imports shared TypeScript types, but the CLI accepts unknown and reparses responses ad hoc.Shared Valibot schemas plus a small typed API client used by mobile and CLI; transport responses validated at runtime.
3Decompose ChannelDO internallyThe correct object boundary now hides too many implementation concerns in one file.Keep one exported Durable Object facade, but extract cache repository, refresh coordinator, reach importer, comments service, and RPC result mappers.
4Define cross-surface parityWeb, mobile, CLI, and MCP expose different subsets of reach, retention, comments, and credential management.A deliberate capability matrix that labels each gap as product choice, backlog, or unsupported.
5Remove config drift pathswrangler.dev.jsonc must be manually mirrored from production, and client base URLs are declared in more than one place.Generate or validate the dev config from a canonical binding manifest and centralize public origins per environment.
6Make freshness observableThe code has thoughtful cache, retry, and alarm behavior but operators cannot see the health model at a glance.Structured counters and dashboards for cache hits, stale serves, refresh age, Google quota/error classes, alarm failures, reach lag, and credential use.
7Strengthen deployment smoke testsThe pipeline currently proves that homepages respond, not that critical public contracts are wired.Unauthenticated checks for /api/viewer, MCP method handling, assets, headers, and environment-specific Durable Object bindings.
8Unify error and freshness languageStale-good behavior is excellent but each surface explains it differently.One shared vocabulary for fresh, cached, stale-with-warning, rebuilding, disconnected, unauthorized, and revoked states.
Best first polishing slice

Start with product identity + shared response schemas + a capability matrix. That work makes every later UI and backend polish decision easier, produces visible coherence quickly, and does not require a risky storage migration.

What to preserve

  • The separation between organization authority, Google secret custody, and channel data.
  • Channel-pinned machine credentials and reauthorization on every request.
  • Stale-good responses with explicit warnings.
  • Atomic promotion and generation ordering for refreshes.
  • The shared dashboard application service used by web, REST, and MCP.
  • Staging-before-production deployment and worktree-safe local setup.

8. Evidence map

This snapshot describes main at commit cfea7eb. The fastest files for re-orienting after future changes are:

  • README.md, root package.json, and pnpm-workspace.yaml for system intent and workspace orchestration.
  • apps/web/wrangler.jsonc, wrangler.dev.jsonc, and wrangler.channel-do.jsonc for production and local topology.
  • apps/web/src/hooks.server.ts, lib/server/connections.ts, and lib/server/dashboard.ts for the request path.
  • apps/web/src/lib/server/*-do/ for state ownership and RPC contracts.
  • apps/web/src/routes/data.remote.ts, routes/api/, and routes/mcp/ for the three server-facing transports.
  • packages/shared/src/types.ts, apps/mobile/lib/api.ts, and apps/cli/src/api.ts for client contracts.
  • .depot/workflows/ci.yml and .depot/workflows/deploy.yml for delivery.