Claude-skill-registry-data migrate-service-to-container
Guides migration from old_code/ to containers/ following SERVICE_MIGRATION_GUIDE.md. Transforms imports to use @coder/shared, adds tenantId to database queries, replaces hardcoded URLs with config, updates routes with auth/tenant enforcement, sets up event publishers/consumers, and transforms service communication. Use when migrating existing services, transforming old code patterns, or refactoring legacy code to new architecture.
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/migrate-service-to-container" ~/.claude/skills/majiayu000-claude-skill-registry-data-migrate-service-to-container && rm -rf "$T"
data/migrate-service-to-container/SKILL.mdMigrate Service to Container
Guides migration from
old_code/ to containers/ following SERVICE_MIGRATION_GUIDE.md and ModuleImplementationGuide.md standards.
Pre-Migration Analysis
Before migrating, analyze:
- Dependencies: What services does this depend on?
- Database: What Cosmos DB containers does it use?
- Events: What events does it publish/consume?
- External APIs: What external services does it call?
- Configuration: What configuration values does it need?
- Routes: What API endpoints does it expose?
- Business Logic: What are the core services/classes?
Migration Steps
Step 1: Create Module Structure
Use
create-container-module skill or manually create:
mkdir -p containers/<service-name>/{config,src/{config,routes,services,types,utils,events,middleware},tests/{unit,integration}}
Step 2: Transform Imports
Old Pattern:
import { config } from '../config/env.js'; import { CosmosClient } from '@azure/cosmos';
New Pattern:
import { CosmosDBClient } from '@coder/shared'; import { loadConfig } from '../config';
Reference: ModuleImplementationGuide.md Section 5 (Dependency Rules)
Step 3: Transform Database Queries
Old Pattern:
async getData(id: string) { const query = `SELECT * FROM c WHERE c.id = @id`; // ❌ No tenantId }
New Pattern:
async getData(tenantId: string, id: string) { const container = this.db.getContainer('service_data'); const query = `SELECT * FROM c WHERE c.tenantId = @tenantId AND c.id = @id`; const parameters = [ { name: '@tenantId', value: tenantId }, { name: '@id', value: id } ]; // ✅ tenantId required, uses shared client }
Reference: SERVICE_MIGRATION_GUIDE.md Step 6, ModuleImplementationGuide.md Section 8
Step 4: Replace Hardcoded URLs
Old Pattern:
const response = await fetch('http://localhost:3021/api/users/123');
New Pattern:
import { ServiceClient } from '@coder/shared'; const client = new ServiceClient({ baseUrl: config.services.auth.url, // From config timeout: 5000, }); const response = await client.get('/api/v1/users/123', { headers: { 'X-Tenant-ID': tenantId, 'Authorization': `Bearer ${serviceToken}`, }, });
Reference: SERVICE_MIGRATION_GUIDE.md Step 7, ModuleImplementationGuide.md Section 5.3
Step 5: Transform Routes
Old Pattern:
fastify.get('/api/my-service/data', async (request, reply) => { const service = new MyService(); const data = await service.getData(request.params.id); return reply.send(data); });
New Pattern:
import { authenticateRequest, tenantEnforcementMiddleware } from '@coder/shared'; fastify.get<{ Params: { id: string } }>( '/api/v1/data/:id', { preHandler: [authenticateRequest(), tenantEnforcementMiddleware()], }, async (request, reply) => { // ✅ tenantId available from tenantEnforcementMiddleware const tenantId = request.user!.tenantId; const data = await service.getData(tenantId, request.params.id); return reply.send({ data }); } );
Reference: SERVICE_MIGRATION_GUIDE.md Step 5
Step 6: Update Error Handling
Old Pattern:
throw new Error('Something went wrong');
New Pattern:
import { AppError } from '@coder/shared'; throw new AppError('Something went wrong', 400, 'BAD_REQUEST');
Reference: ModuleImplementationGuide.md Section 10 (Error Handling)
Step 7: Set Up Event Publishing
New Pattern:
import { EventPublisher } from '@coder/shared'; const publisher = new EventPublisher(config.rabbitmq); await publisher.publish('service.resource.created', { id: resource.id, tenantId: tenantId, timestamp: new Date().toISOString(), });
Reference: ModuleImplementationGuide.md Section 9 (Event-Driven Communication)
Step 8: Transform Service Initialization
Old Pattern:
const service = new MyService(cosmosClient, redis, monitoring);
New Pattern:
import { getDatabaseClient, getCacheClient } from '@coder/shared'; const db = getDatabaseClient(); const cache = getCacheClient(); const service = new MyService(db, cache);
Migration Checklist
Pre-Migration
- Analyze dependencies
- Map database containers
- Identify events (published/consumed)
- List API endpoints
- Document configuration needs
Code Migration
- Create module directory structure
- Copy service files
- Transform imports (use @coder/shared)
- Add tenantId to all database queries
- Replace hardcoded URLs with config
- Transform routes (add auth, tenant enforcement)
- Update error handling (use AppError)
- Add event publishing/consuming
Configuration
- Create config/default.yaml
- Create config/schema.json
- Create config/index.ts loader
- Add environment variable documentation
Validation
- No hardcoded ports/URLs
- All queries include tenantId
- Service-to-service auth implemented
- Follows ModuleImplementationGuide.md