Skip to main content

System overview

Scryon is a single Spring Boot service that wraps three external providers — pyannoteAI (diarization + voice), Lemonfox (transcription), and OpenAI (analysis) — behind a clean REST API. State lives in Postgres; artifacts live in S3-compatible object storage.

Component diagram

External providers (HTTP, configurable):

ProviderUsed forRequired
Lemonfox / WhisperWord-level transcriptionyes
pyannoteAISpeaker diarization + voice embeddingoptional, opt-in
OpenAI (or compatible)LLM analysisyes
Firebase AdminAuth (production)recommended
SentryError trackingoptional
OTLP collector (Tempo / Grafana Agent / etc.)Distributed tracingoptional

Runtime topology

Scryon is designed to run as a single horizontally-scalable instance. The async pipeline does not require a queue broker — Postgres FOR UPDATE SKIP LOCKED is sufficient at current scale. State machines are idempotent so restarting mid-pipeline is always safe.

ConcernApproach
AuthFirebase JWT (api/**), API-key (api-internal/**).
StatePostgres single database. Flyway-managed schema.
ArtifactsS3-compatible object storage; provider abstraction supports local FS for dev.
AsyncSpring TaskExecutor workers + a stale-job sweeper.
MetricsMicrometer → Prometheus scrape endpoint.
LogsStructured key=value lines with MDC correlation.
TracingMicrometer Observation API → OTLP.
ErrorsSentry with a privacy-safe beforeSend filter.

Process flow

A request enters the system on the web layer, is short-circuited to async on the call-analyze path, and continues on a background worker until terminal state. See Call processing pipeline for the step-by-step.

Why this shape

  • Provider abstraction. Every external provider sits behind an interface (DiarizationClient, TranscriptionClient, AnalysisClient, VoiceEmbeddingProvider). Swapping providers is configuration + one Spring @Conditional.
  • No queue broker yet. A broker adds operational surface area we don't need at current call volumes. Postgres + sweeper handles the load fine; we can introduce SQS or RabbitMQ later without changing the public API.
  • Single binary. Easier to deploy, debug, and reason about. There is no separate worker process — the service is the worker.

Deployment shapes

ModeSuitable for
Single container on Railway/Fly/RenderMVP, low-mid traffic.
Single container + external Postgres + S3Production.
Multi-replica with shared Postgres + S3High traffic. Workers safely share queue via SKIP LOCKED.

See Deployment for concrete examples.