Skip to content

Backend at a glance — the three service shapes

The backend is a contract-first polyrepo: ~20 git submodules under backend/core/ (enumerated in .gitmodules). That sounds like a lot to hold in your head — but you don’t have to. Every service is one of exactly three physical shapes. Once you know which shape a service is, you know how it boots, how it’s reached over the wire, and how to debug it. This is the single most useful lens for the whole fleet.

Go data plane

A Connect/gRPC service over cleartext HTTP/2 (h2c). Speaks the DB contract. No TLS in-process. core-database, core-mcp.

Python service

A long-lived server with ingress — either grpc.aio or FastAPI+Hypercorn. Clients connect to it. core-gateway-consumer, core-identity, core-storage, core-billing, core-conversion.

Python queue worker

No ingress. A poller built on the soundverse-py WorkerFleet. It claims tasks off the queue, runs them, and drains on SIGTERM. All the core-tool-* repos.

Who: core-database and core-mcp.

How it serves. One HTTP port speaking h2c (cleartext HTTP/2) + Connect, wired with h2c.NewHandler(...). There is no TLS in-process — the platform (Azure Container Apps, or a local proxy) terminates TLS in front. Both listen on the port named by LISTEN_ADDR (:8080 in-container).

How it’s reached. Other services dial it by its published *_GRPC address (CORE_DATABASE_GRPC, CORE_MCP_GRPC) and present the shared secret INTERNAL_RPC_SECRET as a bearer token on every call. core-database is the single door to Postgres — it mounts every proto-defined DataService (chat, identity, storage, generation task + tool, billing, DNA, notifications, the compat trio, and more) behind one registry.RegisterAllDBServices(...) call, and nobody else opens a DB connection. core-mcp is the MCP tool registry the agent calls, and it runs the second billing pipeline.

How to debug it. GET /healthz. Boot lives in core-database/cmd/server/main.go and core-mcp/cmd/server/main.go. Run locally with go run ./cmd/server.

Shape Language Serves via Ingress? Reached by In the fleet
Go data plane Go Connect/gRPC over h2c Yes *_GRPC addr + INTERNAL_RPC_SECRET bearer core-database, core-mcp
Python gRPC service Python grpc.aio + gRPC health Yes *_GRPC addr (gateway = BFF entry) core-gateway-consumer, core-storage, core-conversion
Python HTTP service Python FastAPI + Hypercorn Yes GET /healthz, REST core-identity, core-billing
Python queue worker Python nothing — polls the queue No not reached; claims tasks every core-tool-*

core-migration is the one repo that isn’t a long-lived service at all. It’s a run-to-completion job (an ACA Job) that re-ingests 1.0 users, billing, and library content into 2.0, then exits. Think of it as a fourth, rare shape: it boots, does a bounded amount of work, and stops.

Several repos are load-bearing but aren’t any of the shapes above:

  • Directorybackend/core/
    • Directorysoundverse-proto/ the contract — proto + SQL-in-proto annotations (source of truth)
    • Directorysoundverse-proto-web/ the generated web/TypeScript SDK the frontend imports
    • Directorysoundverse-py/ the Python SDK every worker is built on (WorkerFleet + TaskContext)
    • Directorysoundverse-saas-2.0/ the Next.js studio + BFF (proxies consumer/v1, Logto auth)
    • DirectoryUI2.0/ a standalone, backend-less in-browser studio (package agent-synth)
    • Directorytemplate-core-tool/ the copy-me starter for a new queue worker

soundverse-py gets special mention: it’s not a service, but its WorkerFleet / TaskContext API is the contract every tool author lives inside — read the SDK deep-dive. The proto repos anchor the contract cascade that keeps all the shapes in sync.

Because the shape is the operational contract:

  • Boot & run — Go: go run ./cmd/server. Python service: make run / hypercorn. Worker: make run (it just starts polling).
  • Reached over the wire — data plane and gRPC services: a *_GRPC address (internal ones want INTERNAL_RPC_SECRET). Worker: never dialled — it pulls work.
  • Debugging first move — service: hit its health probe and read its logs. Worker: read its logs/traces and check it’s claiming tasks (an unpriced tool won’t; an unpriced tool fails callers with NotFound).