Skip to technology content
Back to home

Technology stack

HansaChat is an EU company chat with an operations layer for field teams, designed, built and run by one person. This page shows what each part is built with and why it was chosen.

Versions and counts reviewed in October 2026.

Counted in the repositories

ConnectRPC services with 179 RPCs, all defined in Protobuf
18
Go binaries from one codebase: API, worker, outbox relay, admin
4
platforms from one client: web, macOS, Windows, Linux, iOS, Android
6
languages on the public website
22
interface languages in the app
23
Playwright end-to-end specs on an isolated stack
70

How the pieces fit together

Three applications share one edge and one cluster. The website owns billing and the workspace registry, the Go backend owns everything inside a workspace, and the web app talks to the backend through generated ConnectRPC clients.

Clients

Browser

Website and web app

Tauri

Desktop and mobile shells

hansa CLI

Scripts and agents

Edge

Bunny.net CDN

TLS, caching, DDoS protection

IONOS Managed Kubernetes, Germany

Traefik

Ingress for every application

Web app Vue + Vite

Static Vue build

Chat API

Go with ConnectRPC

  • Worker
  • Outbox relay

Website Laravel + FrankenPHP

Billing, registry, provisioning

NATS JetStream

Durable commands and events

Centrifugo

WebSocket fan-out

Valkey Sentinel + HAProxy

Cache, presence, sessions

LiveKit

Call media

Managed data on IONOS

MariaDB

One database per workspace plus a central registry

Object Storage S3

Files and avatars

External services

ElevenLabs · LLM · Clef

Transcription, translation, triage

Creem · EmailLabs

Payments and email

Outside the cluster

Cloudflare Workers D1

External status checks

Bunny Storage restic

Encrypted backups in Frankfurt and Stockholm

The path of one message

  1. The client calls the message service over ConnectRPC.
  2. The API accepts the request only after NATS JetStream has durably stored the command.
  3. A worker writes the message and an outbox event to the workspace database in one transaction.
  4. The outbox relay publishes the committed event to NATS and Centrifugo.
  5. Every open client receives it over WebSocket; after a gap, clients reload the authoritative state from the API.

Chat backend

Everything that happens inside a workspace runs in Go: messages, channels, files, calls, realtime, imports and the cleaning operations pack. The website never touches workspace data.

Go 1.26

Four binaries from one modular codebase: the API, the message worker, the outbox relay and a guarded admin command. They ship as static binaries in one small image.

Why

A strong standard library, predictable performance and simple concurrency suit a backend made of long-running workers. One language for the whole workspace core keeps it maintainable by one person.

ConnectRPC + Protobuf connect-go 1.20 · buf 1.71

18 services and 179 RPCs are defined in Protobuf. buf generates the Go server and the TypeScript clients with local plugins, so no schema leaves the machine.

Why

One contract serves the web, desktop, mobile and command-line clients. There are no hand-written HTTP paths or response parsing, and a contract change shows up as a compile error rather than a runtime failure.

One database per workspace MariaDB · sqlc

Each workspace gets its own physical MariaDB database. The API resolves the workspace from its domain and opens the matching pool; workers resolve it again themselves and never trust a database name from a queue message. Queries are plain SQL compiled to typed Go with sqlc.

Why

Isolation is structural instead of a filter on every query. Export, import, restore and deletion work per company.

NATS JetStream 2.10

Durable streams for commands, jobs and events, plus a dead-letter stream. Message writes run in 64 ordered partitions.

Why

A message is accepted only after a durable acknowledgement. Messages in one channel stay in order while independent channels are processed in parallel.

Transactional outbox

Domain rows and the outgoing event are committed in the same transaction. A relay publishes committed events to NATS and Centrifugo, deduplicated by event ID, and records failures for retry.

Why

No lost or phantom events when a process stops between the database write and the publish.

Centrifugo v5

WebSocket delivery for messages, presence, typing and call state. Clients subscribe with short-lived per-channel tokens that the API issues only after checking workspace membership.

Why

A dedicated realtime server keeps long-lived connections out of the API process, and each token names both workspace and user, so identities from separate databases cannot collide.

S3-compatible object storage aws-sdk-go-v2

Files and avatars are stored in IONOS Object Storage in the EU and handed out through short-lived signed links.

Why

File storage scales independently of the databases and is encrypted at rest on the server side.

LiveKit 1.9

A self-hosted WebRTC media server for direct-message calls and audio-first channel calls with camera and screen sharing.

Why

Open source and self-hostable, so call media runs on infrastructure HansaChat operates.

ElevenLabs Scribe

Speech-to-text for voice messages. The transcript is attached to the message, searchable and translatable like any text.

Why

Field crews talk more than they type.

LLM translation

Per-reader translation through an OpenAI-compatible API. Each message is translated on demand, cached once per target language and skipped when the reader already shares the language.

Why

A mixed-language crew works in one conversation while every member reads in their own language. The provider stays replaceable behind one interface.

Cloudflare Clef

A decision model classifies operational messages by category, urgency and confidence. It returns probabilities for fixed questions, not generated text. Currently in pilot.

Why

There is no free-form output to parse. Supervisors see what needs attention; acting on it always stays a human decision.

go-pdf 0.9

A4 working-time sheets and service reports are generated on the server.

Why

A pure Go library keeps the backend image small and free of a headless browser.

Sentry + slog

Errors and traces go to Sentry, logs are structured JSON from the standard library, and workers expose metrics in the Prometheus text format.

Why

Few moving parts to operate, and every failure arrives with its context.

Apps and CLI

One Vue client serves the web and is packaged by Tauri for desktop and mobile. The command-line client uses the same public API as the apps.

Vue 3 + TypeScript Vue 3.5 · TS 5.9 · Pinia 3

A single client with 118 single-file components, Pinia stores, vue-router and vue-i18n in 23 interface languages, tested with Vitest.

Why

A mature, readable component model and strict TypeScript make a large client manageable for a very small team.

Vite + Tailwind CSS Vite 8 · Tailwind 4

The build tool and the styling layer: Tailwind CSS 4 with a light and a dark theme.

Why

Fast builds, and design tokens that follow the same documented palette as the website.

Tauri 2.10

Packages the same web client for macOS, Windows, Linux, iOS and Android, with native notifications, deep links and signed desktop updates.

Why

One interface everywhere, using the system webview instead of bundling a browser engine into every app.

Generated Connect clients connect-web 2.1 · protobuf-es 2

TypeScript clients generated from the backend’s Protobuf and copied into the web app. They are never edited by hand.

Why

A contract change becomes a type error in the client instead of a surprise in production.

centrifuge-js + livekit-client 5.7 · 2.20

The client libraries for Centrifugo realtime and LiveKit calls.

Why

Reconnection, recovery and media handling come from the projects that build the servers.

TipTap 3.22

The message composer, with mentions, links and syntax-highlighted code blocks.

Why

A structured editor instead of fragile string handling.

hansa CLI Go 1.26 · Cobra

A stateless command-line client for people, scripts and LLM agents. JSON output by default, credentials in the operating system keychain, and release checksums signed with Minisign.

Why

It consumes the same public API as the apps. Its Protobuf contracts are copied from the backend and locked with SHA-256 hashes, so drift is detected in CI.

Website, billing and registry

Laravel runs the public site, customer documentation, checkout, subscriptions and the central registry of workspaces. It creates a workspace by calling the Go backend over authenticated HTTP, with no shared code and no shared queues.

Laravel + PHP Laravel 12 · PHP 8.5

The public website, customer documentation, checkout, subscriptions, coupons, lifecycle notices and the central registry of workspaces and domains.

Why

Billing, mail, scheduling, queues and forms are where Laravel is strongest. The chat stays in Go, and the boundary between them is one authenticated HTTP interface.

FrankenPHP 1.13

The PHP application server inside the container image, built on a shared base image that pins PHP, its extensions and tooling by digest.

Why

One process serves the application, and rebuilding the same commit produces the same runtime.

Blade + Alpine.js + Tailwind CSS Alpine 3.15 · Tailwind 3.4 · Vite 7

Server-rendered pages with small Alpine.js components, styled with Tailwind CSS and bundled by Vite.

Why

Content pages load fast without shipping a single-page-app framework.

22 languages

Every public page exists in 22 EU languages with locale-prefixed URLs, hreflang links and a localized sitemap. A test fails if any language misses a key or ships English copy.

Why

A European product should be readable in the buyer’s language from the first page.

Creem

Checkout, tax, invoices and subscriptions, kept in sync through signed webhooks.

Why

Payment, tax and invoicing stay with a specialised provider, while the website keeps a reconciled copy of every subscription.

EmailLabs

Transactional and service email such as invitations, password links and notices.

Why

An EU email provider for an EU product.

Pest 4.4

More than 130 test files cover routes, billing, provisioning, translations and SEO, including browser tests.

Why

Fast, readable tests that run on every change.

Platform and operations

Production and preview run on IONOS in Germany. Every application ships as a container image with its own Helm chart and is deployed by a manually triggered GitLab job.

IONOS Managed Kubernetes

Production and preview clusters, managed MariaDB and S3-compatible Object Storage, all run by a German provider in Germany.

Why

A European provider under EU jurisdiction, not the EU region of a non-European cloud.

Helm + Traefik

Each application ships its own chart. Traefik routes traffic inside the cluster, and workspace database migrations run as a hook before every backend rollout.

Why

Every deployment is versioned, repeatable and easy to roll back.

Bunny.net

CDN, DNS and DDoS protection in front of the cluster, and the storage for encrypted backups.

Why

A European company runs the edge and holds the backup copies, so neither depends on a non-European cloud.

Valkey + Sentinel + HAProxy Valkey 9.1

Three replicas with Sentinel failover and an HAProxy proxy that always points to the current primary. It backs caching, sessions, presence and the realtime broker.

Why

A failover needs no application change, because every service keeps talking to the same address.

restic 0.18

Encrypted database backups every 6 hours to two EU locations, with weekly integrity checks and an automated monthly restore drill.

Why

A backup only counts once a restore has been proven.

GitLab CI

Tests, image builds and Helm chart checks run in CI. Deployments to preview and production are separate, manually triggered jobs.

Why

Automation does the repetitive work; a person decides when something reaches customers.

Around the product

The tools that keep a one-person company observable, reachable and explainable.

Cloudflare Workers + D1

An external status page that checks the app and the website every five minutes and records incidents.

Why

Availability is measured from outside the infrastructure it describes.

Umami 3.2

Self-hosted web analytics that only runs after a visitor has made a consent choice.

Why

Visitor data stays on HansaChat infrastructure instead of feeding an advertising network.

Remotion 4.0

The product videos are recorded from the real application by the end-to-end test runner and composed in code with an AI voice-over.

Why

When the interface changes, the video is re-rendered instead of re-filmed.

TwentyCRM + WireGuard

A self-hosted CRM that is reachable only through a private VPN.

Why

Sales data is not exposed to the public internet at all.

Engineering practices

The habits that let one person ship a multi-tenant product without a separate QA or operations team.

Contracts are generated, never hand-written

Protobuf is the single source for the Go server, the TypeScript clients and the CLI. Generators are pinned to exact versions, and the CLI records the hash of every contract file it uses.

Migrations keep a ledger

Every workspace database records which migrations it has applied. A deployment hook applies only the missing ones and checks again after the rollout. The website keeps its original baseline migrations so existing databases never run them twice.

End-to-end tests on an isolated stack

One command starts the databases, NATS, Valkey, Centrifugo and object storage on free ports, builds the Go binaries, starts the web app and runs 70 Playwright specs with a fresh workspace for every test.

Tests at every layer

478 Go test functions, including two-workspace isolation tests, 109 Vitest files in the client and more than 130 Pest files on the website.

Guardrails in CI

Formatting checks, a 1,000-line limit per Go file and Helm chart tests run in CI next to the test suites.

Manual deployment gates

CI builds and tests automatically, but preview and production deployments are separate manual jobs. Production deploys a release tag that is created only after the change is merged.

Backups proven by restores

Every backup run is monitored, and an automated drill restores the databases every month and validates tables and row counts.

One design system

The website and the app share one documented palette, type scale and component rules, with a light and a dark theme in the app.

AI-assisted, human-gated

AI coding agents work from an instruction file in every repository that points into one central engineering documentation repository. Repeatable workflows such as the end-to-end run are packaged as agent skills. Every change still passes the same tests, and deployments stay manual.

Security management in preparation

HansaChat is preparing for ISO/IEC 27001 certification with a risk register, an evidence register and a decision log. It is not certified today.

What this page claims and what it does not

Everything above describes what is implemented today and was counted from the source repositories. HansaChat does not claim a security certification. Message triage is in pilot, and push notifications for closed apps are not live yet.

Questions about the architecture?

Engineers evaluating HansaChat get direct answers from the person who built it.

Email the developer