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 CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ 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 database setup, addresses, and commands. A GitHub App is not required.
This starts the frontend. Before starting the API, apply migrations and [configure identity](hub/docs/identity.md#configure-credentials). Run `cd hub && npm run dev:api` in a second terminal. See [Hub development](hub/docs/development.md) for database setup, addresses, and commands.

### Replica Starter

Expand Down
4 changes: 3 additions & 1 deletion hub/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ DATABASE_URL=postgresql://replica:replica@127.0.0.1:5432/replica
# Only database-enabled tests require this URL and CREATEDB permission.
TEST_DATABASE_URL=postgresql://replica:replica@127.0.0.1:5432/postgres

# Select the credential provider. See docs/identity.md.
# API startup checks the database and this selected credential provider.
HUB_ORIGIN=http://127.0.0.1:5173
HUB_CREDENTIAL_PROVIDER=database

# Generate separate values outside the database. See docs/identity.md.
# HUB_CREDENTIAL_KEY=<openssl rand -hex 32>
# HUB_BOOTSTRAP_SECRET=<at least 32 random characters>

# The environment provider is read-only and requires every GitHub setting below.
# GITHUB_APP_ID=
Expand Down
3 changes: 2 additions & 1 deletion hub/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ Hub is being rebuilt in TypeScript. The app starts locally, but its product feat
- [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.
- [Identity](docs/identity.md) defines GitHub sign-in, credential providers, sessions, and repository permission checks.
- [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 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.
Run Node commands from `hub/`, locally or inside the devcontainer. PostgreSQL and Prisma store the initial identity records. Agree on the design before adding product models, deployment, sign-in providers, or product API routes.

`npm test` does not require PostgreSQL. Use `npm run test:database` for `.db.test.ts` and `.db.test.tsx` cases in Node.js or jsdom. Follow the database isolation and reset rules in [testing](docs/testing-and-operations.md).

Expand Down
6 changes: 3 additions & 3 deletions hub/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Replica Hub

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.
Hub uses TypeScript, Express, React, Vite, and Vitest.

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 API provides `GET /api/health` and a [GitHub-first identity boundary](docs/identity.md) for setup, sign-in, sessions, and repository permission checks. 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.

Contributors can use PostgreSQL and Prisma locally or in the devcontainer. The database has no product models yet. Sign-in, saved data, live updates, background jobs, and deployment are not implemented.
Contributors can use PostgreSQL and Prisma locally or in the devcontainer. Identity records are persisted, but product data, live updates, background jobs, and deployment are not implemented.

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
2 changes: 1 addition & 1 deletion hub/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Hub is being rebuilt. The [Hub overview](../README.md) describes what the baseli
- [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.
- [Identity](identity.md): credential storage, sign-in rules, and session access.
- [Identity](identity.md): GitHub sign-in, credential providers, sessions, and repository authorization.
- [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
10 changes: 4 additions & 6 deletions hub/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@ Hub contributors are rebuilding the app on `build/hub/new` before merging it int

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.
The API responds to a health check and provides the [identity API](identity.md). The frontend displays the logo with light and dark themes. Storybook keeps the existing components and pages available for reuse.

Contributors can use PostgreSQL and Prisma locally or in the devcontainer. Identity models store credentials, users, sessions, sign-in attempts, and security records. [Credential providers](identity.md) use encrypted database values or read-only environment settings. Sign-in routes, 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.
Contributors can use PostgreSQL and Prisma locally or in the devcontainer. Identity models store credentials, users, sessions, one-use OAuth attempts, and security records. Deployment, background jobs, and product APIs have not been built. This app cannot yet list repositories in the frontend, 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.
API code lives under `server/`. [Routes](backend-architecture.md#routes) mirror URL paths and HTTP methods. They parse requests, call backend functions, and send responses. The [code conventions](backend-architecture.md) define the backend layers and their import boundaries.

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.
`GET /api/health` returns `{ "status": "ok" }`. The [identity guide](identity.md#api-operations) lists the other API operations. Unknown paths return a JSON 404 response. `createApp()` builds the Express app without starting a server. `server/index.ts` configures the selected credential provider and starts the API 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.

The [identity service](identity.md) implements GitHub sign-in, sessions, repository permission checks, and administration rules. Its domain contracts and errors stay separate from the GitHub integration and do not assign HTTP statuses.

## Frontend

```mermaid
Expand Down
27 changes: 20 additions & 7 deletions hub/docs/backend-architecture.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,58 @@
# Code architecture conventions

Organize backend functions into repositories, integrations, utilities, and domains. Each layer has a clear job and rules for which other layers it may use.
Organize backend functions into routes, domains, repositories, integrations, and utilities.

| Layer | Responsibility | Directory example |
| --- | --- | --- |
| Routes | Parse HTTP input, call backend functions, and send responses. | `routes/api/session/get/index.ts` |
| Repositories | Functions that interact with the database. Each repository directory represents one RESTful resource. | `repositories/user/get-user/index.ts` |
| Integrations | Functions that interact with an API or SDK. Each integration directory represents one API or SDK service. | `integrations/github/get-user/index.ts` |
| Integrations | Functions tied to an API, SDK, or framework. Group them by service or framework. | `integrations/express/respond-not-found/index.ts` |
| Utilities | General functions reusable elsewhere in the codebase. | `utils/format-timestamp/index.ts` |
| Domains | Business logic functions that may compose repositories, integrations, and utilities. | `domains/user/get-user-profile/index.ts` |

## Import boundaries

```mermaid
flowchart LR
Routes --> Domains
Routes --> Repositories
Routes --> Integrations
Routes --> Utilities
Domains --> Repositories
Domains --> Integrations
Domains --> Utilities
Repositories --> Utilities
Integrations --> Utilities
```

Repositories and integrations may import only utilities from elsewhere in the backend. Utilities may import only other utilities. Domains may import any of these layers, including other domains. Each layer may also use built-in libraries and npm packages.
Routes may import domains, repositories, integrations, and utilities. Repositories and integrations may import only utilities from other layers. Utilities may import only other utilities. Domains may import repositories, integrations, utilities, and other domains. Each layer may also use built-in libraries and npm packages.

These rules apply to imported types as well as functions. A repository must not call another repository or an integration. An integration must not call a repository. Keep business decisions in domains rather than moving them into utilities to get around these rules.

## Directory structure

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.

Keep function implementations flat. Extract helpers into their own function directories rather than nesting them in a factory. A composition factory may bind imported functions to dependencies, but must not contain their implementations. Put schemas and constants in a colocated `constants.ts`, and types in `types.ts`.

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

Keep function implementations flat. A composition factory may bind imported functions to dependencies, but must not contain their implementations. Put schemas and constants in a colocated `constants.ts`, and types in `types.ts`.
## Routes

Mirror the URL below `server/routes/`, then add a directory for the lowercase HTTP method. Use brackets for dynamic path segments. For example, `GET /api/repositories/:owner/:repository/access` lives in `routes/api/repositories/[owner]/[repository]/access/get/index.ts`.

Export handlers as `get()`, `post()`, `put()`, or `delete`. Import them with descriptive `handle*` aliases in `routes/index.ts`. That file exports `routes()` and explicitly registers handlers and middleware.

Keep Express middleware, identity cookies, and request readers in `integrations/express/`. Put Hub access and CSRF policy in domains. Keep only general helpers, such as secret hashing and comparison, in utilities. GitHub credential validation and encryption belong in `integrations/github/`.

Keep domain contracts with their domains, GitHub types and errors with that integration, and database inputs with their repositories. Keep only general helpers in utilities.
Keep domain contracts and errors under `domains/identity/`, GitHub types and errors with that integration, and database inputs with their repositories. Routes map error codes to HTTP statuses and pass that mapping and the Hub origin check to Express helpers. Lower layers do not import domains.

Domain and GitHub errors contain a code and a safe message, not an HTTP status. Keep Hub access and CSRF policy in domains. GitHub credential validation and encryption belong in `integrations/github/`.
Validate request bodies with schemas in each route's `constants.ts`. Rotation and revocation require `confirmed: true`; strings and other values do not count as confirmation. Domain revocation also checks confirmation for callers outside HTTP.

## 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).

Compose repository functions in domains. The identity store binds standalone queries to a database client or transaction there; a repository must not import its neighboring queries to build that store.

`staticSettingsRecordId` identifies Hub's single settings row, not a person or GitHub installation. Its fixed UUID lets every process lock the same row. Keep it with the identity-state repository.
`staticSettingsRecordId` identifies Hub's single settings row, not a person or GitHub installation. Its fixed UUID lets every process lock the same row during setup, rotation, and revocation. Keep it with the identity-state repository.
6 changes: 3 additions & 3 deletions hub/docs/development.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Hub development

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.
Use the Hub devcontainer for Node.js and PostgreSQL, or run Node.js locally with the same database service. Configure [GitHub identity](identity.md) before starting the API. Production deployment is not configured.

## Devcontainer

Expand All @@ -20,7 +20,7 @@ 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.
The example URL connects to PostgreSQL on `127.0.0.1:5432`. To use another development database, set `DATABASE_URL` in `.env` instead. Apply migrations with `npm run db:deploy`, then set `HUB_CREDENTIAL_KEY` and `HUB_BOOTSTRAP_SECRET` as described in [Identity](identity.md#configure-credentials). Do not commit credentials. The health and frontend routes do not query the database, but API startup checks the selected credential provider and database.

## Start the app

Expand All @@ -36,7 +36,7 @@ In a second terminal, also from `hub/`, start Vite:
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.
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. Use the same proxy for the [identity API](identity.md#api-operations). 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. The editor forwards ports 3001, 5173, and 6006 from the devcontainer. API startup reads `.env` when present; Compose's environment takes precedence.

Expand Down
Loading