AmitableDocuments with AI
← All articles

Article · Engineering

Building Amitable: architecture and engineering principles

The engineering ideas behind Amitable: explicit boundaries, typed data, repository APIs, and observable workflows.

Published August 27, 20262 min readAuthor: Creator and developer of Amitable
Read in another language: RU

Building Amitable means working on both a product model and the infrastructure that keeps that model understandable. The repository currently demonstrates a NestJS GraphQL API, PostgreSQL persistence, Socket.IO updates, and a static Astro site around that core.

Keep boundaries visible

Workspaces are the primary boundary for records, memberships, permissions, and realtime updates. A collection belongs to a workspace, and references between fields are checked against that same boundary. This keeps a useful product rule close to the code that enforces it: connected data should not accidentally become cross-workspace data.

The API is split into feature modules. Resolvers describe the GraphQL surface, services hold business operations, and repositories make persistence choices explicit. That structure leaves room to test a workflow without making every test boot the whole application.

Use typed data where the product has meaning

Document records have system metadata in typed PostgreSQL columns. User-defined values live in JSONB because their shape is configured by the collection. The two layers are deliberately separate:

type DocumentRecord = {
  id: string
  workspaceId: string
  documentCollectionId: string
  values: Record<string, unknown>
  version: number
}

GraphQL validation prevents clients from writing system metadata as business values. Field definitions describe whether a value is a string, number, boolean, or reference, and reference rules are validated before persistence.

Make changes observable

Record changes are versioned and distributed through the authenticated realtime namespace. A client can catch up from a known cursor instead of treating every connection as a blank slate. This matters for a product where several people may edit the same collection while they are also importing, filtering, or reviewing records.

The same principle applies to background work: a job should have a visible state, an idempotent identity, and a failure that can be investigated without guessing what happened.

Prefer boring, explicit operations

The project favors repository and entity-manager APIs for persistence. A feature should make its transaction, authorization boundary, and external side-effects easy to locate. When a workflow crosses PostgreSQL, realtime delivery, or an integration, explicit steps are easier to retry and verify than a hidden chain of callbacks.

These principles are still being tested in the product. The architecture is not a promise that every decision is finished; it is a way to keep the next decision local, typed, and reversible.