Skip to main content

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:

  1. Create the service repository with the 4-package structure
  2. Add it as a git submodule
  3. Add a createApp() factory to the API package
  4. Mount it in the gateway
  5. Add the dev port to scripts/dev.ts
  6. Update the CLAUDE.md topology table
  7. Add to tsconfig.json project 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 --json and --quiet flags 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 RangePurpose
4001-4010Service API ports
4101-4110Service 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:

  1. Add table definitions to convex/schema.ts with your service prefix (e.g., mysvc_items)
  2. Create Convex functions in convex/my-service.ts
  3. Implement the ConvexStore in packages/shared/src/store/convex.ts
  4. Remember the sid bridging pattern: app uses id (nanoid), Convex uses _id, and sid is 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.json project references updated
  • Convex tables and functions added (if using Convex)
  • bun run check passes
  • bun run test passes