Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/hub-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
fail-fast: false
matrix:
node: [24, 26]
command: [lint, typecheck, test, build, storybook:build]
command: [lint, typecheck, test, build, storybook:build, "db:validate"]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
Expand Down
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ Each Node.js project's `engines.node` declares its supported versions. Hub, Star

### Replica Hub

Hub has a TypeScript Express API and React + Vite frontend. Hosting and review features are not built yet. The database, sign-in, and deployment choices are still open. Use npm and a Node.js version matching `engines.node` in [hub/package.json](hub/package.json):
Hub has a TypeScript Express API, React + Vite frontend, and PostgreSQL with Prisma. Hosting and review features are not built yet. Use the [Hub devcontainer](hub/docs/development.md#devcontainer), or npm and a Node.js version matching `engines.node` in [hub/package.json](hub/package.json):

```sh
cd hub
npm ci
npm run dev
```

This starts the frontend. In a second terminal, run `cd hub && npm run dev:api` to start the API. See [Hub development](hub/docs/development.md) for their addresses and commands. No container or GitHub App setup is required.
This starts the frontend. In a second terminal, run `cd hub && npm run dev:api` to start the API. See [Hub development](hub/docs/development.md) for database setup, addresses, and commands. A GitHub App is not required.

### Replica Starter

Expand Down Expand Up @@ -100,6 +100,7 @@ Follow the [shared testing and review guide](docs/testing-and-review.md). For Hu
```sh
npm ci
npm run lint
npm run db:validate
npm run typecheck
npm test
npm run build
Expand Down
2 changes: 1 addition & 1 deletion docs/testing-and-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Run the checks for the behavior you changed. For example, a shared Controls change needs checks for Hub previews and the Copilot plugin. Include screenshot capture when its adapter changes. A documentation-only change needs a prose and link review rather than application tests.

Use [Contributing](../CONTRIBUTING.md#set-up-the-development-environment) to find each project's environment and commands. Hub runs directly on Node.js with npm; no container or external services are needed.
Use [Contributing](../CONTRIBUTING.md#set-up-the-development-environment) to find each project's environment and commands. Hub supports local Node.js or its devcontainer; database work uses PostgreSQL.

## Choose the relevant checks

Expand Down
7 changes: 7 additions & 0 deletions hub/.devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:24-bookworm-slim

RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git openssl \
&& rm -rf /var/lib/apt/lists/*

USER node
34 changes: 34 additions & 0 deletions hub/.devcontainer/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
command: sleep infinity
init: true
working_dir: /workspaces/replica/hub
volumes:
- ../..:/workspaces/replica:cached
environment:
DATABASE_URL: postgresql://replica:replica@db:5432/replica
depends_on:
db:
condition: service_healthy

db:
image: postgres:18.6-bookworm
environment:
POSTGRES_USER: replica
POSTGRES_PASSWORD: replica
POSTGRES_DB: replica
ports:
- "127.0.0.1:5432:5432"
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U replica -d replica"]
interval: 5s
timeout: 5s
retries: 10

volumes:
postgres-data:
10 changes: 10 additions & 0 deletions hub/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Replica Hub",
"dockerComposeFile": "compose.yaml",
"service": "app",
"workspaceFolder": "/workspaces/replica/hub",
"remoteUser": "node",
"shutdownAction": "stopCompose",
"forwardPorts": [3001, 5173, 6006],
"postCreateCommand": "npm ci --engine-strict"
}
3 changes: 3 additions & 0 deletions hub/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# Optional API port. The Vite development proxy expects the default.
PORT=3001

# Local development only. The devcontainer supplies its own database hostname.
DATABASE_URL=postgresql://replica:replica@127.0.0.1:5432/replica
1 change: 1 addition & 0 deletions hub/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
/coverage
/dist
/node_modules
/server/generated
/storybook-static
1 change: 1 addition & 0 deletions hub/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ log
.storybook/instances
.storybook/settings.json
node_modules
server/generated
public
dist
storybook-static
Expand Down
3 changes: 2 additions & 1 deletion hub/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ Hub is being rebuilt in TypeScript. The app starts locally, but its product feat
- [Architecture](docs/architecture.md) explains the chosen tools, what works, and what has not been built.
- [Code architecture conventions](docs/backend-architecture.md) define repositories, integrations, utilities, domains, and allowed imports.
- [Coding conventions](docs/coding-conventions.md) explain frontend layers, formatting, and interface rules.
- [Database conventions](docs/database.md) define Prisma files, model section order, UUID keys, timestamps, and database naming.
- [Development](docs/development.md) and [testing](docs/testing-and-operations.md) own local and CI commands.
- [Storybook](docs/storybook.md#ui-changes-and-pull-request-evidence) owns presentation coverage, cleanup, and PR screenshots.

Run Node commands directly from `hub/`. Agree on the design before adding a database, sign-in, deployment, or product API routes.
Run Node commands from `hub/`, locally or inside the devcontainer. PostgreSQL and Prisma are configured without product models. Agree on the design before adding models, sign-in, deployment, or product API routes.

Keep the top-level `HubThemeProvider` around Hub and Storybook content. It synchronizes the resolved light/dark mode to `<html data-color-mode>` so portals inherit Brand and `--hub-*` tokens. Do not add a fixed light theme to an overlay.

Expand Down
2 changes: 1 addition & 1 deletion hub/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Hub is being rebuilt on `build/hub/new` using TypeScript, Express, React, Vite, and Vitest. This branch lets contributors start the new app locally. It is not ready to replace the existing Hub.

The API has one route: `GET /api/health`. The frontend displays the existing Replica logo and supports light and dark themes. Existing components, features, and pages are kept in Storybook, but they are not connected to the new API. The old backend, sign-in, saved data, live updates, background jobs, and deployment setup have been removed without replacements.
The API has one route: `GET /api/health`. The frontend displays the existing Replica logo and supports light and dark themes. Existing components, features, and pages are kept in Storybook, but they are not connected to the new API. PostgreSQL, Prisma, and a slim-based devcontainer provide a development foundation without product models. The old backend, sign-in, saved data, live updates, background jobs, and deployment setup have been removed without replacements.

Use [Development](docs/development.md) to start the API and frontend. Review [Architecture](docs/architecture.md), [code architecture conventions](docs/backend-architecture.md), and [coding conventions](docs/coding-conventions.md) before adding behavior.

Expand Down
1 change: 1 addition & 0 deletions hub/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Hub is being rebuilt. The [Hub overview](../README.md) describes what the baseli
- [Code architecture conventions](backend-architecture.md): repositories, integrations, utilities, and domains.
- [Coding conventions](coding-conventions.md): frontend layers and interface rules.
- [Development](development.md): local API and frontend setup.
- [Database](database.md): Prisma schema conventions, migrations, and the shared client.
- [Testing and operations](testing-and-operations.md): baseline checks and their limits.
- [Storybook](storybook.md): retained presentation, fixtures, and screenshot evidence.
- [Prototype canvas](prototype-canvas.md): the separately retained extension.
Expand Down
6 changes: 4 additions & 2 deletions hub/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@

## What works now

Hub contributors are rebuilding the app on `build/hub/new` before merging it into `main`. That branch starts at `main` with no new commits. Review the code conventions first, then the app setup in a second PR based on the first.
Hub contributors are rebuilding the app on `build/hub/new` before merging it into `main`. Infrastructure changes use task branches and pull requests targeting that feature branch.

The team has chosen TypeScript, Express for the API, React and Vite for the frontend, and Vitest for tests. The old backend and the frontend code that connected to it have been removed rather than rewritten.

The API responds to a health check, and the frontend displays the logo with light and dark themes. Storybook keeps the existing components and pages available for reuse. Sign-in, the database, deployment, background jobs, and product APIs have not been chosen or built. This app cannot yet find repositories, import Builds, host previews, save data, or support reviews.
The API responds to a health check, and the frontend displays the logo with light and dark themes. Storybook keeps the existing components and pages available for reuse. PostgreSQL, Prisma, and a devcontainer provide the database development foundation without product models. Sign-in, deployment, background jobs, and product APIs have not been built. This app cannot yet find repositories, import Builds, host previews, save product data, or support reviews.

## Backend

API code lives under `server/`. As features are added, route handlers will read requests, call domains, and return responses. The [code conventions](backend-architecture.md) explain repositories, integrations, utilities, domains, and which layers may import others. Put these directories under `server/` when they are needed; do not add empty implementations.

The only route is `GET /api/health`, which returns `{ "status": "ok" }`. Every other path returns a JSON 404 response. `createApp()` builds the Express app without starting a server. `server/index.ts` starts it at a local address.

The [database guide](database.md) defines the multi-file Prisma schema and shared client in integrations. The health route remains a process check, not a database readiness check.

## Frontend

```mermaid
Expand Down
4 changes: 4 additions & 0 deletions hub/docs/backend-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ These rules apply to imported types as well as functions. A repository must not
Put each function in a directory named with lowercase words and hyphens, such as `get-user`. Keep `index.ts`, its tests, and its types together. Group repository functions by resource and integration functions by API or SDK service, as shown above. Import from each function's directory, not from a shared file that re-exports its neighbors.

Add directories when their functions are needed. Do not add empty implementations just to fill out the structure.

## Database access

The [shared Prisma client](database.md#shared-client) lives in `server/integrations/prisma/index.ts`. Domains may pass it to repositories for database queries without letting repositories import integrations. Keep model definitions, naming, and migrations consistent with the [database conventions](database.md#schema-conventions).
2 changes: 2 additions & 0 deletions hub/docs/coding-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Follow the [shared coding conventions](../../docs/coding-conventions.md) and the [code architecture conventions](backend-architecture.md) for repositories, integrations, utilities, and domains.

Follow the [database conventions](database.md#schema-conventions) for Prisma model sections, file names, UUID keys, timestamps, and database mappings.

## TypeScript

- Use TypeScript for new application code and tests.
Expand Down
56 changes: 56 additions & 0 deletions hub/docs/database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Hub database

Hub uses PostgreSQL and Prisma. The development image is pinned in [Compose](../.devcontainer/compose.yaml); Prisma packages are pinned together in [package.json](../package.json) and follow the [seven-day dependency policy](../../docs/testing-and-review.md#update-dependencies). Product models and migrations have not been added.

Choose the newest stable PostgreSQL major available from both Azure Database for PostgreSQL and Amazon RDS or Aurora. Managed services can offer different patch releases; the local image tracks a stable patch of that shared major. Check provider availability again when changing the major, rather than assuming that an upstream release is available everywhere.

## Schema conventions

[prisma7.config.ts](../prisma7.config.ts) points Prisma at the entire `prisma/` directory. Keep the generator and datasource in `prisma/schema.prisma`, one model per kebab-case `.prisma` file, and one enum per kebab-case `.enum.prisma` file. Store migrations in `prisma/migrations/` and commit them with their schema changes.

Use singular PascalCase model and enum names. Map every model to a plural `snake_case` table with `@@map`. Use camelCase Prisma fields and `@map` for database columns whose names differ, including foreign keys. Give every table a UUID `id` primary key and `created_at` and `updated_at` timestamp columns. Use PostgreSQL's native UUID type for primary and foreign keys.

Order each model's sections as ID columns, relations, attribute columns, and timestamp columns, with the table mapping last. Keep the section comments when the section is present. For example, a future self-referencing folder model would follow this structure:

```prisma
model Folder {
// ID columns
id String @id @default(uuid()) @db.Uuid
parentId String? @map("parent_id") @db.Uuid

// Relations
parent Folder? @relation("FolderTree", fields: [parentId], references: [id])
children Folder[] @relation("FolderTree")

// Attribute columns
name String

// Timestamp columns
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(3)

@@map("folders")
}
```

`uuid()` generates UUIDs through Prisma. `@updatedAt` updates timestamps on Prisma writes, not through a database trigger. Raw SQL writers must supply UUIDs and maintain `updated_at` themselves. Use timezone-aware timestamps for stored instants.

## Shared client

Import `prisma` from `server/integrations/prisma/index.ts` rather than constructing clients in each caller. It uses the PostgreSQL driver adapter and Prisma's [documented global cache pattern](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs#avoiding-multiple-prisma-client-instances): development module reloads reuse one client, while production uses the module instance without writing a development global.

The integration requires `DATABASE_URL` and reads `.env` when present. Do not import server database code into the frontend. Keep queries in repositories and follow the [import boundaries](backend-architecture.md#import-boundaries). Domains may pass the shared client into repository functions; repositories must not import integrations directly.

## Schema changes

Run these commands from `hub/`:

```sh
npm run db:validate
npm run db:migrate -- --name describe_the_change
npm run db:generate
```

`npm ci` also generates the client. Generated TypeScript lives under the ignored `server/generated/prisma/` directory and compiles with the API. Schema validation and generation do not require a running database or `DATABASE_URL`; migration and database commands require both. Generate again after changing a schema.

Use `db:migrate` only with a local development database. It needs permission to create a shadow database to calculate migrations. `npm run db:deploy` applies committed migrations without creating new ones; it is not a production deployment setup. `npm run db:studio` opens Prisma's database editor and should be used only with an intended development database.
37 changes: 34 additions & 3 deletions hub/docs/development.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
# Hub development

Use npm and a Node.js version supported by `engines.node` in `hub/package.json`. Run these commands from `hub/`:
Use the Hub devcontainer for Node.js and PostgreSQL, or run Node.js locally with the same database service. Sign-in and production deployment are not configured.

## Devcontainer

Install a Docker-compatible runtime with Docker Compose and an editor with Dev Containers support. Open the repository's `hub/` directory in the editor and reopen it in the container using `.devcontainer/devcontainer.json`.

Compose starts the app container after PostgreSQL is healthy. The app uses a Node.js `bookworm-slim` base and runs as the non-root `node` user. The official PostgreSQL `bookworm` image also uses a Debian slim base; it has no separate `slim` tag. Container creation runs `npm ci --engine-strict`, including Prisma Client generation.

The repository is mounted at `/workspaces/replica`, with `hub/` as the working directory. Compose supplies `DATABASE_URL` with the `db` service hostname. Local database credentials in Compose are for development only. The database port is published only on host loopback.

## Local Node.js

Use npm and a Node.js version supported by `engines.node` in `hub/package.json`. From `hub/`, start only the database and copy the local configuration:

```sh
docker compose -f .devcontainer/compose.yaml up -d db
cp .env.example .env
npm ci --engine-strict
```

The example URL connects to PostgreSQL on `127.0.0.1:5432`. To use another development database, set `DATABASE_URL` in `.env` instead. Do not commit credentials. The existing health and frontend routes do not query the database.

## Start the app

Run these commands from `hub/`, inside the devcontainer or with local Node.js:

```sh
npm ci
npm run dev:api
```

Expand All @@ -15,7 +38,15 @@ npm run dev

Open <http://127.0.0.1:5173>. Vite serves the frontend and forwards `/api` requests to Express at <http://127.0.0.1:3001>. `GET /api/health` returns JSON; other API routes have not been built. Both servers accept connections only from this machine. Stop each with Ctrl+C.

The API reads an optional `PORT` environment variable, defaulting to 3001. If you change it, update the local Vite proxy target to match. No environment file, credentials, database, or external service is required.
The API reads an optional `PORT` environment variable, defaulting to 3001. If you change it, update the local Vite proxy target to match. The editor forwards ports 3001, 5173, and 6006 from the devcontainer. API startup reads `.env` when present; Compose's environment takes precedence.

## Database lifecycle

PostgreSQL stores data in a named Compose volume. Stopping or rebuilding the devcontainer preserves it. For a local Node.js setup, stop the database with `docker compose -f .devcontainer/compose.yaml down`; this also preserves data. Do not add `--volumes` unless you intend to permanently delete the local database.

If port 5432 is already in use, stop the conflicting local service or explicitly change the Compose port and the host `.env` URL together. The devcontainer continues to use `db:5432` internally. Startup failures appear in `docker compose -f .devcontainer/compose.yaml logs db`.

Follow the [database guide](database.md) for schema conventions, migrations, and the shared client.

## Build the app

Expand Down
5 changes: 4 additions & 1 deletion hub/docs/testing-and-operations.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Hub testing and operations

The new Hub has no deployment setup, database, sign-in, or product APIs yet. These checks cover the new app setup and the frontend code we kept. They do not prove that the old Hub's features work.
The new Hub has a PostgreSQL and Prisma foundation but no product models, deployment setup, sign-in, or product APIs yet. These checks cover the new app setup and the frontend code we kept. They do not prove that the old Hub's features work.

Run commands directly from `hub/` after `npm ci`:

```sh
npm run lint
npm run db:validate
npm run typecheck
npm test
npm run build
Expand All @@ -16,6 +17,8 @@ Vitest uses a Node project for API and pure utility tests and a jsdom project fo

The API health check proves only that Express responds. Routes that have not been built must return 404 rather than pretending to work.

Installation generates Prisma Client without a database connection. Client lifecycle tests cover reuse across development reloads, production global behavior, and missing configuration. Database queries and migrations need the PostgreSQL service described in [Development](development.md); the ordinary Vitest suite does not connect to it.

## Shared code

The extension and build action still use Hub's Controls and canvas code. Keep their checks working:
Expand Down
Loading
Loading