Adding a Service
This guide walks through adding a new service to the platform, from creating the service repository to mounting it in the gateway.
Overview
Adding a service involves these steps:
- Create the service repository with the 4-package structure
- Add it as a git submodule
- Add a
createApp()factory to the API package - Mount it in the gateway
- Add the dev port to
scripts/dev.ts - Update the CLAUDE.md topology table
- Add to
tsconfig.jsonproject references
Step 1: Create the Service Repository
Each service follows a four-package layout. Use an existing service (like yellowpages) as a template:
my-service/
packages/
shared/
src/
types.ts # Service data types
repository.ts # Store interface
store/
file.ts # File-based store implementation
convex.ts # Convex store implementation
factory.ts # createStore() factory based on SHIFT_STORAGE
package.json
api/
src/
index.ts # createApp() factory exporting a Hono app
routes.ts # Route handlers
package.json
cli/
src/
index.ts # Commander.js CLI entry point
commands/ # CLI command handlers
package.json
web/
src/
App.tsx # React SPA entry
pages/ # Page components
package.json
biome.json # Biome config (same as platform root)
package.json # Workspace root
tsconfig.json
Key patterns to follow
- shared/types.ts -- Define your data types with
id: string(nanoid(8)), timestamps, and all fields. - shared/repository.ts -- Define a store interface (e.g.,
MyServiceStore) with CRUD methods. - api/src/index.ts -- Export a
createApp()function that returns a Hono app. The gateway imports this. - cli -- Use Commander.js. Support
--jsonand--quietflags on every command. - web -- Vite + React SPA. Built into static files served by the gateway.
Step 2: Add as Submodule
cd /path/to/platform
git submodule add https://github.com/the-shift-dev/my-service.git my-service
Step 3: Add createApp() Factory
In your service's packages/api/src/index.ts:
import { Hono } from "hono";
import { errorHandler } from "@shift/platform-core/api/error-handler";
import { healthRoute } from "@shift/platform-core/api/health";
export function createApp() {
const app = new Hono();
app.use("*", errorHandler());
app.route("/healthz", healthRoute("my-service"));
// Add your routes
app.get("/items", async (c) => {
// ...
});
return app;
}
Step 4: Mount in Gateway
Edit packages/gateway/src/index.ts to import and mount your service:
import { createApp as createMyServiceApi } from "../../my-service/packages/api/src/index.js";
// In the gateway setup:
gw.route("/api/v1/my-service", createMyServiceApi());
Step 5: Add Dev Port
Edit scripts/dev.ts to add your service's development port. Each service gets an API port (400x) and optionally a web port (410x):
| Port Range | Purpose |
|---|---|
| 4001-4010 | Service API ports |
| 4101-4110 | Service web UI ports |
Pick the next available port number in the sequence.
Step 6: Update CLAUDE.md
Add your service to the topology table in CLAUDE.md:
| My Service | `my-service/` | CLI + API + Web | 40xx (API), 41xx (Web) | `.my-service/` |
Step 7: Add Project References
Add your service's packages to the root tsconfig.json project references:
{
"references": [
// ... existing references
{ "path": "my-service/packages/shared" },
{ "path": "my-service/packages/api" },
{ "path": "my-service/packages/cli" },
{ "path": "my-service/packages/web" }
]
}
Convex Integration
If your service uses Convex storage:
- Add table definitions to
convex/schema.tswith your service prefix (e.g.,mysvc_items) - Create Convex functions in
convex/my-service.ts - Implement the ConvexStore in
packages/shared/src/store/convex.ts - Remember the
sidbridging pattern: app usesid(nanoid), Convex uses_id, andsidis the bridge field
Checklist
- Service repo created with 4-package structure
- Added as git submodule
-
createApp()factory exports a Hono app - Mounted in gateway at
/api/v1/<prefix> - Dev port added to
scripts/dev.ts - CLAUDE.md topology table updated
-
tsconfig.jsonproject references updated - Convex tables and functions added (if using Convex)
-
bun run checkpasses -
bun run testpasses