Files
Primora/README.md
T
Tomas DvorakandDevin 591dedab2f docs: restructure README, add logo and app screenshots
Containr-style layout: centered mark, tagline, nav, CI/release/license
badges. New screenshots section with six captures from demo mode
(overview, storage, telemetry, collections, automation, audit).
Configuration and port tables added; existing install/dev/CLI content
preserved.

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 16:16:38 +02:00

9.2 KiB

Primora

Primora

Self-hosted backend platform for building products.
Auth, Postgres-backed APIs, object storage, and audit logs on your own hardware.

Quick Start · Documentation · Releases · Contributing

CI Release License

What is Primora?

Primora is a self-hosted backend platform: organizations, projects, auth, S3-style object storage, JSON document collections, scoped API keys, and a full audit log behind one dashboard. Inspired by the UX of Appwrite and Supabase, with no hosted tier - your data stays on your hardware.

Screenshots

Overview Storage
Project overview Object storage
Telemetry Collections
Telemetry and component health JSON document collections
Automation Audit log
Scheduled jobs and live events Audit log with export

Features

  • Organizations & projects - top-level workspaces containing projects, members, and scoped roles (owner/admin/member org roles, admin/developer/viewer project roles).
  • Auth - email/password plus optional GitHub, Google, Discord, and Microsoft OAuth via Better Auth. JWTs minted by the auth service are verified by the Go API against JWKS.
  • Storage - S3-style buckets and objects backed by your local filesystem, with public/private visibility and downloadable URLs.
  • Collections - schema-flexible JSON documents stored in Postgres JSONB.
  • API keys - prm_<prefix>_<secret> credentials; secrets are shown once.
  • Audit log - every mutating request recorded with actor, resource, request ID, and timestamp; CSV/JSON export from the dashboard.
  • Generated client - the TypeScript client is generated from apps/backend/openapi/openapi.yaml, so the API contract is the source of truth.
  • Demo mode - a fully client-side workspace (?demo=true or VITE_DEMO_MODE=true) for trying the UI without a backend.

Architecture

Browser ──▶ Nginx ──▶ Frontend (SolidJS + Vite)
                 ├──▶ Auth service (Better Auth + Hono)
                 └──▶ API (Go + Gin) ──▶ PostgreSQL
                                     ──▶ DragonflyDB (Redis-compatible cache)
                                     ──▶ Local filesystem object storage
Service Port Purpose
nginx 80 (NGINX_PORT) Reverse proxy - only public entrypoint
backend 8080 (internal) Go + Gin API
auth 3001 (internal) Better Auth service
postgres 5432 (POSTGRES_PORT) Primary datastore
dragonfly 6379 (DRAGONFLY_PORT) Redis-compatible cache
mailpit (dev) 8025 (MAILPIT_HTTP_PORT) Email capture with docker-compose.dev.yml

Quick Start

Prerequisites: Docker with the Compose plugin.

One-liner (no clone)

curl -fsSL https://raw.githubusercontent.com/Dvorinka/Primora/master/install.sh | bash

Installs into ./primora, generates secrets, and starts the stack on port 80. Non-interactive - configure with env vars:

DOMAIN=example.com NGINX_PORT=8080 PRIMORA_DIR=/opt/primora bash install.sh

The installer pulls prebuilt images from GHCR when they are published; otherwise it downloads the source tarball and builds locally.

From a clone

git clone https://github.com/Dvorinka/Primora.git && cd Primora
./scripts/setup.sh          # creates .env, generates secrets, starts the stack

or manually:

cp .env.example .env        # fill JWT_SECRET and BETTER_AUTH_SECRET
docker compose up -d        # builds the three app images from source

To run published images instead of building:

docker pull ghcr.io/dvorinka/primora-{backend,auth,frontend}:latest
docker compose up -d --no-build

Then open http://localhost (or append ?demo=true to explore a seeded workspace without signing up). For local email capture, add the dev overlay (-f docker-compose.dev.yml) and Mailpit is at http://localhost/mailpit/.

Useful commands

docker compose ps                  # service status + health
docker compose logs -f backend     # follow one service
docker compose pull && docker compose up -d   # update to latest release
docker compose down                # stop (data persists in volumes)
docker compose down -v             # stop and delete all data

Verify the install

Check Endpoint
Frontend http://localhost/
Backend liveness http://localhost/api/v1/health/liveness
Backend readiness http://localhost/api/v1/health/readiness
Auth health http://localhost/auth-health
OpenAPI spec http://localhost/api/v1/openapi.yaml

Configuration

All configuration lives in .env (see .env.example for the full list):

Variable Default Purpose
NGINX_PORT 80 Public HTTP port
POSTGRES_PORT 5432 Host binding for Postgres
DRAGONFLY_PORT 6379 Host binding for Dragonfly
JWT_SECRET - Signs API tokens (required)
BETTER_AUTH_SECRET - Signs auth sessions (required)
COOKIE_DOMAIN localhost Cookie scope for auth sessions
PRIMORA_ENCRYPTION_KEY - AES-256 key encrypting secrets at rest

Only host bindings change when you move ports - the internal network stays the same. OAuth providers, SMTP, and storage limits are documented in .env.example and QUICK_START.md.

Local development

docker compose up -d postgres dragonfly mailpit   # infrastructure only
cd apps/backend && go run ./cmd/server            # API on :8080
npm run dev:auth                                  # auth on :3001
npm run dev:frontend                              # dashboard (Vite)

Point the frontend at the stack by adding to apps/frontend/.env.local:

VITE_API_BASE_URL=http://localhost/api/v1
VITE_AUTH_BASE_URL=http://localhost/auth

Or skip all of it: http://localhost:<vite-port>/?demo=true runs entirely in the browser.

CLI

npm run build --workspace @primora/cli   # → apps/cli/dist/cli.js
node apps/cli/dist/cli.js login          # or: npx primora login once published

Supports session sign-in (primora login) and API-key mode (primora login --api-key prm_… or PRIMORA_API_KEY). Context lives in ~/.config/primora/config.json; primora use picks org + project interactively. Commands: orgs, projects, buckets, objects (list/upload/download/rm), keys, audit list --follow. Every command accepts --json.

Desktop & phone

  • Desktop - apps/desktop is a Tauri 2 shell (Linux/Windows/macOS). First run asks for your deployment URL, then renders the same dashboard in a webview with a system-tray presence. Nothing is bundled; your server does the work. See apps/desktop/README.md.
  • Phone / PWA - the dashboard ships a web manifest and service worker. Open your deployment in a mobile browser and "Add to Home Screen"; the shell is precached, API traffic always goes to the network. Chromium desktop browsers get an in-app install banner.

Quality gate

npm run check        # backend tests + frontend typecheck + build + generated-code drift check
npm test             # workspace tests
npm run generate:sqlc    # regenerate sqlc after changing queries/schema
npm run generate:client  # regenerate the TS client after changing openapi.yaml

Repository layout

apps/
  backend/     Go + Gin API, sqlc, migrations, object storage
  auth/        Better Auth on Hono (sessions, JWT, OAuth, mail)
  frontend/    SolidJS + Tailwind dashboard
  cli/         `primora` CLI - login, context, projects, buckets, objects, keys, audit
  mcp/         `@primora/mcp` - MCP stdio server exposing `primora_*` tools
  desktop/     Tauri 2 shell - connects to a deployment URL, tray presence
packages/
  api-client/  OpenAPI-generated TypeScript client (do not hand-edit)
  shared-types/
infra/nginx/   Reverse proxy config
scripts/       setup.sh, verify-production-ready.sh

Documentation

Contributing

See CONTRIBUTING.md for the development workflow.

Security

See SECURITY.md for reporting vulnerabilities.

License

MIT