---
title: TALA engineering docs
description: How TALA is built — a NestJS 11 REST API and a React 19 SPA in two independent repositories, and the contract between them.
---

TALA is a governed digital-asset management platform. Assets live in S3 behind CloudFront; everything about who owns them, who may see them, and what happened to them lives in Postgres behind a NestJS API.

These are internal engineering docs. They cover the shape of the system, the contract between its two halves, and the parts that are built but not yet reachable from the UI. They are not user documentation and not a product spec.

**[Run it locally](/quickstart)**

Both halves up in about ten minutes, including the Postgres traps.

**[API reference](/reference)**

Every operation, generated from the backend's live Swagger document.

**[Architecture](/architecture)**

Modules, the data model, and the request pipeline.

**[What's wired](/status/integration)**

Which endpoints the SPA actually calls, and which it doesn't.

Beyond those: [API conventions](/api) covers the envelope, errors and pagination
that the generated reference does not state; [Frontend](/frontend) covers the SPA's
routing and API client; and [Operations](/operations) covers branching, environments
and the deployment plan.

## The two repositories

TALA is one product in two independent git repositories, checked out side by side under a parent folder that is **not** itself a repository.

<FileTree>

- TALA/
  - backend/ — NestJS 11 REST API · `TalaHqq/tala-backend`
  - frontend/ — React 19 SPA · `TalaHqq/tala-frontend`
  - docs/ — this Blume site
  - CLAUDE.md

</FileTree>

Changes to one repo do not affect the other. There is no shared package, no generated client, and no compile-time link between them — the only contract is HTTP, which is why the [API reference](/reference) is generated from the running server rather than written by hand.

:::warning[Two untracked snapshots]
`backend-v1-integration/` and `frontend-original-integration/` also sit under `TALA/`. Neither is a git repository and neither has a remote. Anything in them that is not also in `backend/` or `frontend/` exists on exactly one machine.
:::

## What the system is made of

| | Backend | Frontend |
| --- | --- | --- |
| Framework | NestJS 11, TypeScript 5.7 | React 19, Vite 7, TypeScript 5.9 |
| Runtime | Node v22.16.0 (`.nvmrc`) | — |
| Data | PostgreSQL via TypeORM 0.3 | none; server is the source of truth |
| Storage | AWS S3 multipart, CloudFront | presigned `PUT` direct to S3 |
| Auth | JWT (HS256) inside AES-256-GCM, rotating refresh tokens | tokens in `localStorage` |
| Styling | — | Tailwind CSS v4, shadcn/ui, @base-ui/react |
| State | — | component `useState` and bespoke hooks |
| Tests | Jest, unit + e2e | Vitest |

## Where the numbers come from

Every count in these docs was read from source, not from an older document.

| | |
| --- | --- |
| Backend modules | 14 feature modules plus the app root |
| HTTP routes declared | 74 |
| Operations in the published spec | 73 — `GET /api/seeder` carries `@ApiExcludeController` |
| Entities | 19, plus 3 join tables |
| Migrations | 4 |
| SPA routes | 17 |
| Routes with a frontend caller | 55 of 74 |

:::note[`CLAUDE.md` is stale]
`CLAUDE.md` in the parent folder predates the Core MVP collaboration work and is wrong in about ten specific places, among them OAuth, route guards, mock data, the module list, and the migration count. Where the two disagree, these docs were read from source more recently. See [Documentation drift](/status/drift).
:::
