A high-performance, self-hosted media asset manager (MAM) designed for creative professionals and content managers. Centralize, archive, organize, and search multi-platform media content ingested from external sync agents with interactive playback and hybrid AI search.
Key Features • User Interface • Monorepo Workspace • Quick Start • Documentation
- 🎨 Card-on-Canvas Design System: Built on Apple-inspired spatial depth layers and Linear-class desktop refinement with clean HSL palettes.
- 📸 Native Live Photo & Interactive Media: Support for Live Photo interactive playback and browser-native HEIC/HEIF decoding.
- 🎬 Unified DASH Streaming: Audio/video split streams from multi-track media sources are parsed on-the-fly via dynamic
sidxSegmentBase extraction and streamed smoothly withdash.js. - 🏷️ Multi-Tenant Library Management: Physical asset isolation per Library, fine-grained RBAC (
VIEWER,EDITOR,ADMIN), and reconstructive tag normalization with alias mapping. - 🔍 Hybrid AI Search & Enrichment: Reciprocal Rank Fusion (RRF) combining SQL trigram text search, Gemini text embeddings (
text-embedding-004), and visual similarity vectors (multimodal-embedding-004). - ⚡ Durable Task Queue Engine: In-house PostgreSQL-backed task queue with atomic
SKIP LOCKEDlease locking, exponential backoff retries, and automatedJobSweepercleanup.
Presents content grouped by Posts. Each card displays author details, publication timestamps, tags, and a thumbnail of the primary media asset.
Slides out from the right when selecting any post. Features a Swiper-powered interactive media carousel alongside complete post metadata inspectors.
Directly displays individual Media assets with two flexible layout modes:
- Flat Mode: Displays all images and videos as independent cards for granular searching and asset inspection.
- Stacked Mode: Groups media belonging to the same post into a single card with stack badges (
+N).
Stationary is structured as a Bun Workspace Monorepo:
stationary/
├── apps/
│ ├── server/ # Bun + Hono API backend, Drizzle ORM, DB Task Queue Engine
│ ├── web/ # Nuxt 4 + Vue 3 SPA/SSR, Tailwind CSS v4, Swiper, Plyr
│ ├── flutter/ # Flutter multi-platform client application
│ └── apple/ # Native iOS 18+/iPadOS/macOS app (SwiftUI, Liquid Glass, Swift 6)
└── docs/ # Technical specifications & architecture blueprints
| Component | Stack | Responsibilities |
|---|---|---|
apps/server |
Bun, Hono, Drizzle ORM, PostgreSQL, Redis, @ai-sdk/google |
REST APIs, authentication (Better Auth), task execution engine, S3 asset handling |
apps/web |
Nuxt 4, Vue 3, Pinia, Vue Query, Tailwind CSS v4, dash.js | Web desktop client, Card-on-Canvas layout, DASH video player, HEIC renderer |
apps/flutter |
Flutter, Dart, Chewie, PhotoView | Mobile and desktop cross-platform application |
apps/apple |
SwiftUI, Swift 6, AVKit, Liquid Glass Theme | Native iOS/iPadOS/macOS multiplatform app with Liquid Glass UI, Post List & Detail |
- Bun:
v1.3.0or higher - PostgreSQL:
v15or higher (withpgvector&pg_trgmextensions enabled) - Redis: For KV caching and rate limiting
bun installSet up environment configuration files:
- Backend: Copy
apps/server/.env.exampletoapps/server/.envand update PostgreSQL, Redis, and S3 credentials. - Frontend: Copy
apps/web/.env.exampletoapps/web/.envand setNUXT_PUBLIC_API_BASE_URL(default:http://localhost:9400).
cd apps/server
bun run db:migrateFrom the repository root, start development servers concurrently:
bun run devFrontend and backend are merged into a single high-performance Docker image (Dockerfile). An embedded Caddy gateway transparently routes /api/* to the Hono backend and all other requests to the Nuxt frontend, exposing a single port (4000) with zero CORS issues:
# 1. Prepare environment file
cp .env.example .env
# Edit .env with your external DB_URL, REDIS_URL, S3 credentials, etc.
# 2. Build and start the unified container in the background
bun run docker:up # Or: docker compose up -d
# 3. View logs
bun run docker:logs # Or: docker compose logs -fAccess endpoint:
- Stationary App (Web & API):
http://localhost:4000
Stationary includes a complete GitOps deployment setup for Kubernetes / k3s:
- CI/CD: GitHub Actions (
.github/workflows/deploy.yaml) builds and pushes the single unified image to GHCR (ghcr.io/stariverr/stationary) and updates the Kustomize image tag. - GitOps: ArgoCD monitors
deploy/k8s/overlays/productionand automatically reconciles changes to the cluster. - Ingress: Uses Traefik (default in k3s) to route all incoming traffic directly to port 4000 on the unified
stationaryservice.
Apply the ArgoCD application to your cluster:
# 1. Create stationary secrets in k3s
kubectl create secret generic stationary-secrets -n stationary \
--from-literal=DB_URL="postgresql://..." \
--from-literal=REDIS_URL="redis://..." \
--from-literal=AUTH_SECRET="..." \
--from-literal=RESEND_API_KEY="..." \
--from-literal=RESEND_EMAIL_SENDER="..." \
--from-literal=S3_ENDPOINT="..." \
--from-literal=S3_ACCESS_KEY_ID="..." \
--from-literal=S3_SECRET_ACCESS_KEY="..." \
--from-literal=S3_BUCKET="..." \
--from-literal=CDN_BASE_URL="..."
# 2. Register ArgoCD Application
kubectl apply -f deploy/argocd/application.yamlDetailed specifications and architectural guides are available in the docs/ directory:
- 📐 System Design & Database Specification - Data models, relational schemas, deletion policies, and JobRunner queue specs.
- 🔌 Metadata Sync & API Contracts - Integration client schemas,
external_iddeduplication rules, and sync payloads. - 🔄 Metadata Ingestion Pipeline - Execution flow of
saveMetadata, change detection, and S3 soft-delete lifecycle. - 🔍 Multi-Space Hybrid Search Spec - Vector space segregation, pgvector HNSW indexing, and RRF rank fusion.
- ⚖️ Architectural Trade-offs - Design rationale behind Multi-Track schemas and DASH segment parsing.
- 🛠️ Task Engine Extension Guide - Strategy pattern guide for adding new background job handlers.
- 📜 TypeScript & Bun Guidelines - Mandatory standards for Temporal API, Web API streams, and
bun:File.
Private repository. All rights reserved.

