What we work with
and why exactly this.
A page for whoever will read our code or maintain the system after us. Every layer comes with the reasoning behind it.
Frontend
Next.js on the App Router: server rendering where the first paint matters, and client islands only where interactivity is needed. TypeScript in strict mode, because an error caught at build time costs less than a bug the client finds.
Backend
Go for services that have to hold load and start in milliseconds. One static binary, predictable memory use, readable code without magic. Python where the data and AI ecosystem is needed.
Data
PostgreSQL by default: it can do more than people expect of it and almost always settles the question of a second store. Redis for queues, caching and rate limits. A separate vector database appears only when document search genuinely calls for one.
Infrastructure
Docker and Compose as the base: the project has to come up with one command on someone else's machine. Kubernetes only when there is someone to operate it. Metrics and alerts go in on launch day, before the first incident rather than after it.
AI
A model is one component of the system, and a replaceable one. We keep prompts and data separate from the code, measure quality on labelled sets and keep the option of changing provider. Observability is not optional: without a log of its conversations an agent cannot be fixed.
A typical project
in one diagram.
This is what the system we deploy most often looks like. Kubernetes appears here only when the client has someone to operate it.
┌──────────────┐user ──▶ │ Caddy / TLS │└──────┬───────┘┌────────┴────────┐▼ ▼┌─────────────┐ ┌─────────────┐│ Next.js │ │ Go API ││ SSR / ISR │ │ chi/v5 │└─────────────┘ └──────┬──────┘┌───────┼───────┐▼ ▼ ▼┌────────┐ ┌─────┐ ┌───────┐│Postgres│ │Redis│ │ MinIO │└────────┘ └──┬──┘ └───────┘▼┌─────────────┐│ worker ││ email · TG │└─────────────┘
Four decisions,
made in advance.
Boring technology by default
We take something new when it solves our specific problem better than what already exists. A tie is settled in favour of the tool already running in our production.
Your stack matters more than ours
If you have a working team on another stack, we write in yours. Leaving behind a system nobody can maintain costs more than any saving on development.
One command to start it
The project has to come up on a clean machine with docker compose up. If starting it takes a person with special knowledge, that is a defect, and we fix it before handover.
Observability from day one
Metrics, logs and alerts are set up before launch. A system whose state you learn about from the client cannot be called working.
Want to discuss
the architecture before the brief?
Write to us, and we will go through your diagram and tell you where its bottleneck is. It is free and commits you to nothing.