You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit dfbfe02
Browse filesBrowse the repository at this point in the historyBrowse files
authored and
Ben Thomas
committed
feat(hub): add production runtime and locked setup
Run the built frontend, API, and workers in one image. Keep schema and schedule setup in a separately locked operational script.
Co-authored-by: Ben Thomas <25218250+alliscode@users.noreply.github.com>
Co-authored-by: Nishiki <1121087+nshki@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: hub/README.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,9 +2,11 @@
2
2
3
3
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.
4
4
5
-
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.
5
+
The API has liveness and readiness routes. 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 product APIs.
6
6
7
-
Contributors can use PostgreSQL and Prisma locally or in the devcontainer. The [background-job foundation](docs/background-jobs.md) provides PostgreSQL-backed BullMQ queues and independent on-demand and scheduled workers, without product jobs yet. The database has no product models. Sign-in, saved product data, live updates, and deployment are not implemented.
7
+
Contributors can use PostgreSQL and Prisma locally or in the devcontainer. The [background-job foundation](docs/background-jobs.md) provides PostgreSQL-backed BullMQ queues and independent on-demand and scheduled workers, without product jobs yet. The database has no product models. Sign-in, saved product data, and live updates are not implemented.
8
+
9
+
The [production runtime](docs/deployment.md) packages the frontend, API, and workers in one image, with a separate release setup script.
8
10
9
11
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.
Copy file name to clipboardExpand all lines: hub/docs/architecture.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,13 +8,15 @@ The team has chosen TypeScript, Express for the API, React and Vite for the fron
8
8
9
9
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.
10
10
11
-
Contributors can use PostgreSQL and Prisma locally or in the devcontainer. The database has a provider-neutral identity transaction foundation and internal GitHub authentication proof primitives. No public authentication flow is exposed. Deployment and product APIs have not been built. This app cannot yet find repositories, import Builds, host previews, save product data, or support reviews.
11
+
Contributors can use PostgreSQL and Prisma locally or in the devcontainer. The database has a provider-neutral identity transaction foundation and internal GitHub authentication proof primitives, but it does not issue sessions or admit users to Hub. No public authentication flow or product API is exposed. This app cannot yet find repositories, import Builds, host previews, save product data, or support reviews.
12
+
13
+
The [production runtime](deployment.md) serves the built frontend and API and runs both workers in one image. Deployment runs database and job setup separately before starting that image.
12
14
13
15
## Backend
14
16
15
17
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.
16
18
17
-
`GET /api/health` returns `{ "status": "ok" }`. Authentication routes are not registered. Unknown paths return a JSON 404 response; invalid JSON is rejected before routing. `createApp()` builds the Express app without starting a server. `server/index.ts`starts it at a local address.
19
+
`GET /api/health` returns `{ "status": "ok" }`; `GET /api/ready` reports operational readiness. Authentication routes are not registered. Unknown API paths return a JSON 404 response; invalid JSON is rejected before routing. `createApp()` builds the Express app without starting a server. `server/index.ts`selects a runtime role and defaults to the local API.
18
20
19
21
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.
Copy file name to clipboardExpand all lines: hub/docs/backend-architecture.md
+9-7Lines changed: 9 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,13 +2,13 @@
2
2
3
3
Organize backend functions into routes, repositories, integrations, utilities, and domains. Each layer has a clear job and rules for which other layers it may use.
4
4
5
-
| Layer | Responsibility | Directory example |
6
-
| --- | --- | --- |
7
-
| Routes | Parse HTTP requests, call backend functions, and send responses. Directories follow URL paths and HTTP methods. |`routes/api/health/get/index.ts`|
8
-
| Repositories | Functions that interact with the database. Each repository directory represents one RESTful resource. |`repositories/user/get-user/index.ts`|
9
-
| Integrations | Functions that interact with an API or SDK. Each integration directory represents one API or SDK service. |`integrations/github/get-user/index.ts`|
10
-
| Utilities | General functions reusable elsewhere in the codebase. |`utils/format-timestamp/index.ts`|
11
-
| Domains | Business logic functions that may compose repositories, integrations, and utilities. |`domains/user/get-user-profile/index.ts`|
| Routes | Parse HTTP requests, call backend functions, and send responses. Directories follow URL paths and HTTP methods. |`routes/api/health/get/index.ts`|
8
+
| Repositories | Functions that interact with the database. Each repository directory represents one RESTful resource. |`repositories/user/get-user/index.ts`|
9
+
| Integrations | Functions that interact with an API or SDK. Each integration directory represents one API or SDK service. |`integrations/github/get-user/index.ts`|
10
+
| Utilities | General functions reusable elsewhere in the codebase. |`utils/format-timestamp/index.ts`|
11
+
| Domains | Business logic functions that may compose repositories, integrations, and utilities.|`domains/user/get-user-profile/index.ts`|
12
12
13
13
## Import boundaries
14
14
@@ -37,6 +37,8 @@ Export route handlers by HTTP method, such as `get()`, and alias them to descrip
37
37
38
38
Add directories when their functions are needed. Do not add empty implementations just to fill out the structure.
39
39
40
+
Operational entry points belong under `server/scripts/`. They may compose backend functions and run deployment tools, but routes and domains must not import them. Setup runs separately from the API and workers.
41
+
40
42
## Database access
41
43
42
44
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).
|`on-demand`| Work requested by an application action |`npm run worker:on-demand`|
12
12
|`scheduled`| Recurring work and work spawned by recurring sweeps |`npm run worker:scheduled`|
13
13
14
14
Each command starts one Node.js process consuming only its assigned queue. The API starts neither worker. Multiple processes may consume the same queue when more capacity is needed. Separate queues do not isolate PostgreSQL, CPU, or external service quotas.
@@ -17,7 +17,7 @@ Each command starts one Node.js process consuming only its assigned queue. The A
17
17
18
18
`server/workers/configuration.ts` is the composition point for processors and schedules. Its empty registrations are intentional until product domains exist. Worker startup logs readiness after connecting; unknown job names fail permanently rather than disappearing.
19
19
20
-
Workers stop accepting work on `SIGINT` or `SIGTERM` and wait for active jobs. After 30 seconds, the command exits unsuccessfully rather than waiting forever. Interrupted work can be retried by BullMQ's stalled-job recovery. Deployment stop timeouts must allow this shutdown window. Long-running domain work needs its own bounded execution and interruption policy; a queue lock is not a business lock.
20
+
Workers stop accepting work on `SIGINT` or `SIGTERM` and wait for active jobs. After `SHUTDOWN_TIMEOUT_MS` (30000 milliseconds by default), the command exits unsuccessfully rather than waiting forever. Interrupted work can be retried by BullMQ's stalled-job recovery. Deployment stop timeouts must allow this shutdown window. Long-running domain work needs its own bounded execution and interruption policy; a queue lock is not a business lock.
21
21
22
22
## Database and setup
23
23
@@ -42,7 +42,7 @@ npm run start:worker:on-demand
42
42
npm run start:worker:scheduled
43
43
```
44
44
45
-
Run the last three commands as separate services, not sequential commands in one shell. These roles can use one application image in a future Compose deployment, with PostgreSQL shared and only the web service exposed. Production frontend hosting, an application image, service health checks, and release orchestration are not implemented by this foundation.
45
+
Run the last three commands as separate services, not sequential commands in one shell. The [production image](deployment.md) instead defaults to a combined process that runs the API and both workers and coordinates their shutdown.
46
46
47
47
Each queue or worker owns a small query pool and BullMQ's additional notification connections. The query pool is limited to two connections; concurrency does not increase that limit. Budget database connections across all API, producer, and worker instances. Creation functions require an explicit URL so tests and other callers cannot accidentally inherit a previously imported database client.
48
48
@@ -52,14 +52,14 @@ Keep stable names, a Zod payload schema, and retry options in a job definition.
52
52
53
53
Use the functions under `server/integrations/bullmq/`:
54
54
55
-
| Function | Contract |
56
-
| --- | --- |
57
-
|`migrateJobDatabase(databaseUrl)`| Explicitly migrate BullMQ's schema and close the migration connection. |
58
-
|`createJobQueue(options)`| Open a client for one named PostgreSQL queue. The caller must close it. |
59
-
|`enqueueJob(queue, definition, payload, options)`| Validate JSON payload data and enqueue work with job-specific retries and optional delay, priority, or job ID. Failure rejects the call. |
|`createJobWorker(options)`| Construct a stopped consumer for registered processors. The caller starts and closes it. Duplicate processor names are rejected. |
62
-
|`upsertJobSchedule(queue, schedule)`| Validate and register an interval or timezone-explicit cron schedule on `scheduled`. |
|`migrateJobDatabase(databaseUrl)`| Explicitly migrate BullMQ's schema and close the migration connection.|
58
+
|`createJobQueue(options)`| Open a client for one named PostgreSQL queue. The caller must close it.|
59
+
|`enqueueJob(queue, definition, payload, options)`| Validate JSON payload data and enqueue work with job-specific retries and optional delay, priority, or job ID. Failure rejects the call. |
|`createJobWorker(options)`| Construct a stopped consumer for registered processors. The caller starts and closes it. Duplicate processor names are rejected.|
62
+
|`upsertJobSchedule(queue, schedule)`| Validate and register an interval or timezone-explicit cron schedule on `scheduled`.|
63
63
64
64
`runJobWorker()` owns process signals and consumer lifetime outside the integration. Integration code does not import domains, repositories, or the shared logger; worker composition injects processors and logging.
0 commit comments