RUST MEDIA BACKEND / PERSONAL PROJECT

Canopy.

The Rust control plane behind PandaWave.

RustgRPCPostgreSQLTonic

Canopy owns durable backend state, identity and media policy. PandaEngine owns client playback state and queue behavior. Keeping that line explicit makes it possible to reason about what a caller may access without distributing backend policy into Android.

Architecture

Canopy separates transport adapters, domain services and repository ports. PostgreSQL is authoritative for identity, metadata, visibility and current playback policy. Nginx handles the authorized byte stream.

PandaEngine calls Canopy over gRPC. Identity, catalog, discovery, profile and playback services use repository ports backed by PostgreSQL. Android requests media from Nginx, which rechecks policy with Canopy before reading managed media.
Control decisions travel through gRPC. Audio bytes do not.
BoundaryResponsibility
canopy-protoFacade over the immutable generated canopy.v1 SDK
canopy-coreDomain values, errors and repository ports; no transport/database dependency
canopy-serverTonic adapters, application services, storage adapters and runtime wiring
PostgreSQLAuthoritative data and policy
NginxAuthorized byte-range delivery from managed media

Architecture and workspace boundaries →

Service surface

Catalog and discovery

Hierarchical browsing, text search, discovery, For You and recommendation feeds. Visibility policy is applied before counting and pagination.

Identity

Accounts, email verification, credentials, native device sessions, refresh rotation, revocation and recovery in PostgreSQL builds.

Profile-owned state

Profiles, preferences, history, library and playlists persist behind ownership-aware repository boundaries.

Playback

Resolve an eligible asset under current policy, issue a short-lived opaque capability, and reauthorize each media request.

System health and readiness complete the operational surface. Player commands, queue management, seeking and MediaSession state remain in PandaEngine.

Why Rust

Rust gives the backend explicit types for domain values, ownership for shared state and a practical async runtime through Tokio and Tonic. The goal is a backend whose policy and failure paths remain understandable as the service grows. The implementation keeps core repository ports independent of transport and database details.

Search belongs on the backend

  1. mettalica Illustrative input
  2. Normalize query One backend interpretation
  3. Trigram candidates PostgreSQL pg_trgm
  4. Rank → Metallica Illustrative candidate

This is an illustration of the search pipeline, not a captured production query result. Matching and ranking live alongside catalog data and visibility policy, so the Android client can submit intent and present results. PostgreSQL trigram search supports approximate matching without a second client-side search implementation.

Catalog/search implementation · Search and policy architecture

Identity and sessions

  1. Register → verify Account identity
  2. Sign in Native device session
  3. Rotate refresh token Session continuity
  4. Revoke / recover Explicit lifecycle paths

Authenticated operations resolve the active device session on the server. Optional identity does not mean permissive identity: invalid, malformed, expired or revoked authorization fails closed rather than silently becoming an anonymous request.

Authentication design →

Playback authorization

  1. Resolve playback PandaEngine → gRPC
  2. Select eligible asset Current PostgreSQL policy
  3. Issue opaque capability Short-lived stream URL
  4. HTTP Range request Android player → Nginx
  5. Revalidate policy Nginx → private Canopy authorizer
  6. Deliver bytes Nginx → Android player

Control decisions travel through gRPC. Audio bytes do not.

The capability contains an asset identity, audience, expiry, version and nonce — no storage key. The client uses the URL as an opaque value. Nginx asks Canopy to recheck current policy for each request before an internal media redirect permits delivery.

That makes policy changes effective even when a capability has not expired. Repository failures remain errors; they do not become a reason to relax visibility or fall back to a different audience.

Playback, policy and streaming details →

What to verify

BoundaryInvariantEvidence / test direction
Optional identityInvalid supplied identity fails closedMalformed, expired and revoked session cases
Catalog and profileInaccessible data stays inaccessibleVisibility filtering, ownership and pagination
Playback resolutionOnly eligible assets produce capabilitiesPublic, owner and non-owner policy matrix
Media deliveryCurrent policy is checked againExpired capability, policy change and Range request
Repository failureFailure cannot weaken authorizationStorage errors propagate as service failures

These are the verification boundaries documented by the repository, not a claim that a production availability target or load benchmark has been measured.

Current engineering focus

CURRENT IMPLEMENTATION
  • Tonic gRPC services and PostgreSQL repositories
  • Native identity and profile-owned state
  • Catalog/search and policy-aware playback resolution
  • Nginx authorization and ranged media delivery
NEXT HARDENING WORK
  • Operational validation and recovery behavior
  • Broader deployment and policy-boundary tests
  • Measured capacity and performance work
  • Future cache and sync experiments

Redis / JadeCache and RustFS are reserved infrastructure in the repository; they are not active playback dependencies. Current roadmap →