From f13c676139efb09a3c7e483b24d6d90bfd05bc64 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Sat, 14 Feb 2026 21:31:04 -0800 Subject: [PATCH] refactor: merge billing-service into platform-service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2 of service consolidation (5→2 services). Moved modules: - subscriptions (9 tests) - usage (7 tests) - plans (9 tests) - licenses (7 tests) - stripe (0 tests — webhook signature verified at runtime) Changes: - Copied 5 modules + stripe.ts lib from billing-service - Added billing env vars to config schema (Stripe, internal key, etc.) - Scoped billing routes with internal key auth guard (Gap 3) - When BILLING_INTERNAL_KEY is set, billing routes require x-internal-key header - When unset, billing routes are open (dev mode) - Stripe routes always outside scope (own webhook signature check) - Removed billing-service directory Tests: 115 passing (83 + 32 from billing = 115) ✅ Build: clean ✅ --- pnpm-lock.yaml | 49 ----------------- services/billing-service/.gitignore | 2 - services/billing-service/Dockerfile | 44 --------------- services/billing-service/package.json | 34 ------------ services/billing-service/src/lib/config.ts | 22 -------- .../billing-service/src/lib/cosmos-init.ts | 28 ---------- services/billing-service/src/lib/cosmos.ts | 4 -- services/billing-service/src/lib/errors.ts | 12 ----- .../billing-service/src/lib/product-config.ts | 9 ---- services/billing-service/src/server.ts | 53 ------------------- services/billing-service/tsconfig.json | 19 ------- services/billing-service/vitest.config.ts | 9 ---- services/platform-service/src/lib/config.ts | 9 ++++ .../src/lib/stripe.ts | 0 .../src/modules/licenses/licenses.test.ts | 0 .../src/modules/licenses/repository.ts | 0 .../src/modules/licenses/routes.ts | 0 .../src/modules/licenses/types.ts | 0 .../src/modules/plans/plans.test.ts | 0 .../src/modules/plans/repository.ts | 0 .../src/modules/plans/routes.ts | 0 .../src/modules/plans/types.ts | 0 .../src/modules/stripe/routes.ts | 0 .../src/modules/subscriptions/repository.ts | 0 .../src/modules/subscriptions/routes.ts | 0 .../subscriptions/subscriptions.test.ts | 0 .../src/modules/subscriptions/types.ts | 0 .../src/modules/usage/repository.ts | 0 .../src/modules/usage/routes.ts | 0 .../src/modules/usage/types.ts | 0 .../src/modules/usage/usage.test.ts | 0 services/platform-service/src/server.ts | 36 +++++++++++-- 32 files changed, 42 insertions(+), 288 deletions(-) delete mode 100644 services/billing-service/.gitignore delete mode 100644 services/billing-service/Dockerfile delete mode 100644 services/billing-service/package.json delete mode 100644 services/billing-service/src/lib/config.ts delete mode 100644 services/billing-service/src/lib/cosmos-init.ts delete mode 100644 services/billing-service/src/lib/cosmos.ts delete mode 100644 services/billing-service/src/lib/errors.ts delete mode 100644 services/billing-service/src/lib/product-config.ts delete mode 100644 services/billing-service/src/server.ts delete mode 100644 services/billing-service/tsconfig.json delete mode 100644 services/billing-service/vitest.config.ts rename services/{billing-service => platform-service}/src/lib/stripe.ts (100%) rename services/{billing-service => platform-service}/src/modules/licenses/licenses.test.ts (100%) rename services/{billing-service => platform-service}/src/modules/licenses/repository.ts (100%) rename services/{billing-service => platform-service}/src/modules/licenses/routes.ts (100%) rename services/{billing-service => platform-service}/src/modules/licenses/types.ts (100%) rename services/{billing-service => platform-service}/src/modules/plans/plans.test.ts (100%) rename services/{billing-service => platform-service}/src/modules/plans/repository.ts (100%) rename services/{billing-service => platform-service}/src/modules/plans/routes.ts (100%) rename services/{billing-service => platform-service}/src/modules/plans/types.ts (100%) rename services/{billing-service => platform-service}/src/modules/stripe/routes.ts (100%) rename services/{billing-service => platform-service}/src/modules/subscriptions/repository.ts (100%) rename services/{billing-service => platform-service}/src/modules/subscriptions/routes.ts (100%) rename services/{billing-service => platform-service}/src/modules/subscriptions/subscriptions.test.ts (100%) rename services/{billing-service => platform-service}/src/modules/subscriptions/types.ts (100%) rename services/{billing-service => platform-service}/src/modules/usage/repository.ts (100%) rename services/{billing-service => platform-service}/src/modules/usage/routes.ts (100%) rename services/{billing-service => platform-service}/src/modules/usage/types.ts (100%) rename services/{billing-service => platform-service}/src/modules/usage/usage.test.ts (100%) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1afb97e..808e19db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -174,55 +174,6 @@ importers: specifier: ^5.2.1 version: 5.7.4 - services/billing-service: - dependencies: - '@azure/cosmos': - specifier: ^4.2.0 - version: 4.9.1(@azure/core-client@1.10.1) - '@bytelyst/config': - specifier: workspace:* - version: link:../../packages/config - '@bytelyst/cosmos': - specifier: workspace:* - version: link:../../packages/cosmos - '@bytelyst/errors': - specifier: workspace:* - version: link:../../packages/errors - '@bytelyst/fastify-core': - specifier: workspace:* - version: link:../../packages/fastify-core - '@fastify/cors': - specifier: ^10.0.2 - version: 10.1.0 - '@fastify/swagger': - specifier: ^9.4.2 - version: 9.7.0 - fastify: - specifier: ^5.2.1 - version: 5.7.4 - fastify-metrics: - specifier: ^10.3.0 - version: 10.6.0(fastify@5.7.4) - stripe: - specifier: ^17.5.0 - version: 17.7.0 - zod: - specifier: ^3.24.2 - version: 3.25.76 - devDependencies: - '@types/node': - specifier: ^22.12.0 - version: 22.19.11 - tsx: - specifier: ^4.19.2 - version: 4.21.0 - typescript: - specifier: ^5.7.3 - version: 5.9.3 - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/node@22.19.11)(happy-dom@18.0.1)(jsdom@28.0.0)(tsx@4.21.0)(yaml@2.8.2) - services/extraction-service: dependencies: '@azure/cosmos': diff --git a/services/billing-service/.gitignore b/services/billing-service/.gitignore deleted file mode 100644 index b9470778..00000000 --- a/services/billing-service/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -dist/ diff --git a/services/billing-service/Dockerfile b/services/billing-service/Dockerfile deleted file mode 100644 index d7e017e3..00000000 --- a/services/billing-service/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# Build context: repo root (docker compose sets context: .) -FROM node:22-alpine AS builder -RUN npm install -g pnpm@10 -WORKDIR /app - -# Copy workspace config + lockfile for dependency resolution -COPY package.json pnpm-workspace.yaml pnpm-lock.yaml tsconfig.base.json ./ - -# Copy all package.json files (pnpm needs these for workspace resolution) -COPY packages/errors/package.json packages/errors/ -COPY packages/cosmos/package.json packages/cosmos/ -COPY packages/blob/package.json packages/blob/ -COPY packages/config/package.json packages/config/ -COPY packages/auth/package.json packages/auth/ -COPY packages/api-client/package.json packages/api-client/ -COPY packages/fastify-core/package.json packages/fastify-core/ -COPY packages/logger/package.json packages/logger/ -COPY packages/monitoring/package.json packages/monitoring/ -COPY packages/react-auth/package.json packages/react-auth/ -COPY packages/design-tokens/package.json packages/design-tokens/ -COPY packages/testing/package.json packages/testing/ -COPY services/billing-service/package.json services/billing-service/ - -# Install all workspace deps -RUN pnpm install --frozen-lockfile - -# Copy source -COPY packages/ packages/ -COPY services/billing-service/tsconfig.json services/billing-service/ -COPY services/billing-service/src/ services/billing-service/src/ - -# Build packages first, then service -RUN pnpm -r --filter @lysnrai/billing-service... build - -# Deploy to isolated directory (production deps only) -RUN pnpm --filter @lysnrai/billing-service deploy --legacy /app/deploy - -# ── Production ───────────────────────────────────────────── -FROM node:22-alpine -WORKDIR /app -COPY --from=builder /app/deploy ./ -ENV NODE_ENV=production -EXPOSE 4002 -CMD ["node", "dist/server.js"] diff --git a/services/billing-service/package.json b/services/billing-service/package.json deleted file mode 100644 index 409fb71f..00000000 --- a/services/billing-service/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@lysnrai/billing-service", - "version": "0.1.0", - "private": true, - "description": "Billing & Entitlement Service — subscriptions, payments, usage, licenses, plans", - "type": "module", - "scripts": { - "dev": "tsx watch src/server.ts", - "build": "tsc", - "start": "node dist/server.js", - "test": "vitest run", - "test:watch": "vitest", - "lint": "eslint src/" - }, - "dependencies": { - "@bytelyst/config": "workspace:*", - "@bytelyst/cosmos": "workspace:*", - "@bytelyst/errors": "workspace:*", - "@bytelyst/fastify-core": "workspace:*", - "@azure/cosmos": "^4.2.0", - "fastify": "^5.2.1", - "@fastify/cors": "^10.0.2", - "@fastify/swagger": "^9.4.2", - "fastify-metrics": "^10.3.0", - "stripe": "^17.5.0", - "zod": "^3.24.2" - }, - "devDependencies": { - "@types/node": "^22.12.0", - "tsx": "^4.19.2", - "typescript": "^5.7.3", - "vitest": "^3.0.5" - } -} diff --git a/services/billing-service/src/lib/config.ts b/services/billing-service/src/lib/config.ts deleted file mode 100644 index 852b9399..00000000 --- a/services/billing-service/src/lib/config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { z } from 'zod'; - -const envSchema = z.object({ - PORT: z.coerce.number().default(4002), - HOST: z.string().default('0.0.0.0'), - NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), - CORS_ORIGIN: z.string().optional(), - SERVICE_NAME: z.string().default('billing-service'), - BILLING_INTERNAL_KEY: z.string().optional(), - COSMOS_ENDPOINT: z.string().min(1, 'COSMOS_ENDPOINT is required'), - COSMOS_KEY: z.string().min(1, 'COSMOS_KEY is required'), - COSMOS_DATABASE: z.string().default('lysnrai'), - STRIPE_SECRET_KEY: z.string().min(1, 'STRIPE_SECRET_KEY is required'), - STRIPE_WEBHOOK_SECRET: z.string().optional(), - STRIPE_PRICE_PRO: z.string().optional(), - STRIPE_PRICE_ENTERPRISE: z.string().optional(), - BACKEND_URL: z.string().default('http://localhost:8000'), - PLAN_LIMITS_JSON: z.string().optional(), - USAGE_WARN_THRESHOLD: z.coerce.number().default(0.8), -}); - -export const config = envSchema.parse(process.env); diff --git a/services/billing-service/src/lib/cosmos-init.ts b/services/billing-service/src/lib/cosmos-init.ts deleted file mode 100644 index 065468aa..00000000 --- a/services/billing-service/src/lib/cosmos-init.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { initializeAllContainers, registerContainers } from '@bytelyst/cosmos'; -import type { ContainerConfig } from '@bytelyst/cosmos'; -import { config } from './config.js'; - -const CONTAINER_DEFS: Record = { - plans: { partitionKeyPath: '/id' }, - subscriptions: { partitionKeyPath: '/userId' }, - payments: { partitionKeyPath: '/userId' }, - licenses: { partitionKeyPath: '/userId' }, - usage_daily: { partitionKeyPath: '/userId', defaultTtl: 365 * 86400 }, -}; - -export async function initCosmosIfNeeded(): Promise { - registerContainers(CONTAINER_DEFS); - - const shouldInit = config.NODE_ENV !== 'production' || process.env.COSMOS_AUTO_INIT === 'true'; - if (!shouldInit) return; - - try { - await initializeAllContainers(); - // eslint-disable-next-line no-console - console.info('[billing-service] Cosmos containers ensured'); - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - // eslint-disable-next-line no-console - console.warn(`[billing-service] Cosmos init failed: ${msg}`); - } -} diff --git a/services/billing-service/src/lib/cosmos.ts b/services/billing-service/src/lib/cosmos.ts deleted file mode 100644 index e82cae59..00000000 --- a/services/billing-service/src/lib/cosmos.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Re-export from @bytelyst/cosmos — shared across all services. - */ -export { getContainer, getCosmosClient, getDatabase } from '@bytelyst/cosmos'; diff --git a/services/billing-service/src/lib/errors.ts b/services/billing-service/src/lib/errors.ts deleted file mode 100644 index dd79e9e9..00000000 --- a/services/billing-service/src/lib/errors.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Re-export from @bytelyst/errors — shared across all services. - */ -export { - ServiceError, - BadRequestError, - UnauthorizedError, - ForbiddenError, - NotFoundError, - ConflictError, - TooManyRequestsError, -} from '@bytelyst/errors'; diff --git a/services/billing-service/src/lib/product-config.ts b/services/billing-service/src/lib/product-config.ts deleted file mode 100644 index 32d322f0..00000000 --- a/services/billing-service/src/lib/product-config.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Re-export from @bytelyst/config — shared product identity. - */ -import { loadProductIdentity } from '@bytelyst/config'; - -const _id = loadProductIdentity(); -export const PRODUCT_ID = _id.productId; -export const DISPLAY_NAME = _id.displayName; -export const LICENSE_PREFIX = _id.licensePrefix; diff --git a/services/billing-service/src/server.ts b/services/billing-service/src/server.ts deleted file mode 100644 index 66f9b31a..00000000 --- a/services/billing-service/src/server.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Billing & Entitlement Service — Fastify server entry point. - * - * Modules: subscriptions, usage, plans, licenses. - * Port: 4002 (configurable via PORT env var). - */ - -import { createServiceApp, startService } from '@bytelyst/fastify-core'; -import { subscriptionRoutes } from './modules/subscriptions/routes.js'; -import { usageRoutes } from './modules/usage/routes.js'; -import { planRoutes } from './modules/plans/routes.js'; -import { licenseRoutes } from './modules/licenses/routes.js'; -import { stripeRoutes } from './modules/stripe/routes.js'; -import { initCosmosIfNeeded } from './lib/cosmos-init.js'; -import { config } from './lib/config.js'; - -await initCosmosIfNeeded(); - -const app = await createServiceApp({ - name: 'billing-service', - version: '0.1.0', - description: 'Subscriptions, payments, usage, licenses, plans, Stripe', - corsOrigin: config.CORS_ORIGIN, - swagger: { - title: 'Billing & Entitlement Service', - description: 'Subscriptions, payments, usage, licenses, plans, Stripe', - port: config.PORT, - }, - metrics: true, -}); - -// Internal API key auth (service-specific — skip health, webhook, and when key not configured) -const INTERNAL_KEY = config.BILLING_INTERNAL_KEY; -if (INTERNAL_KEY) { - app.addHook('onRequest', async (req, reply) => { - const path = req.url; - // Skip auth for health check and Stripe webhook (has its own signature verification) - if (path === '/health' || path.includes('/stripe/webhook')) return; - const key = req.headers['x-internal-key']; - if (key !== INTERNAL_KEY) { - reply.code(401).send({ error: 'Unauthorized — missing or invalid X-Internal-Key' }); - } - }); -} - -// Register route modules -await app.register(subscriptionRoutes, { prefix: '/api' }); -await app.register(usageRoutes, { prefix: '/api' }); -await app.register(planRoutes, { prefix: '/api' }); -await app.register(licenseRoutes, { prefix: '/api' }); -await app.register(stripeRoutes, { prefix: '/api' }); - -await startService(app, { port: config.PORT, host: config.HOST }); diff --git a/services/billing-service/tsconfig.json b/services/billing-service/tsconfig.json deleted file mode 100644 index d155b3cc..00000000 --- a/services/billing-service/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "outDir": "dist", - "rootDir": "src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "src/**/*.test.ts"] -} diff --git a/services/billing-service/vitest.config.ts b/services/billing-service/vitest.config.ts deleted file mode 100644 index 7dd13254..00000000 --- a/services/billing-service/vitest.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - test: { - globals: true, - environment: 'node', - include: ['src/**/*.test.ts'], - }, -}); diff --git a/services/platform-service/src/lib/config.ts b/services/platform-service/src/lib/config.ts index 287fa4b7..84c4af70 100644 --- a/services/platform-service/src/lib/config.ts +++ b/services/platform-service/src/lib/config.ts @@ -17,6 +17,15 @@ const envSchema = z.object({ // ── Growth (merged) ── WEBHOOK_INVITATION_REDEEMED_URL: z.string().optional(), WEBHOOK_REFERRAL_STATUS_URL: z.string().optional(), + // ── Billing (merged) ── + STRIPE_SECRET_KEY: z.string().optional(), + STRIPE_WEBHOOK_SECRET: z.string().optional(), + STRIPE_PRICE_PRO: z.string().optional(), + STRIPE_PRICE_ENTERPRISE: z.string().optional(), + BILLING_INTERNAL_KEY: z.string().optional(), + BACKEND_URL: z.string().default('http://localhost:8000'), + PLAN_LIMITS_JSON: z.string().optional(), + USAGE_WARN_THRESHOLD: z.coerce.number().default(0.8), }); export const config = envSchema.parse(process.env); diff --git a/services/billing-service/src/lib/stripe.ts b/services/platform-service/src/lib/stripe.ts similarity index 100% rename from services/billing-service/src/lib/stripe.ts rename to services/platform-service/src/lib/stripe.ts diff --git a/services/billing-service/src/modules/licenses/licenses.test.ts b/services/platform-service/src/modules/licenses/licenses.test.ts similarity index 100% rename from services/billing-service/src/modules/licenses/licenses.test.ts rename to services/platform-service/src/modules/licenses/licenses.test.ts diff --git a/services/billing-service/src/modules/licenses/repository.ts b/services/platform-service/src/modules/licenses/repository.ts similarity index 100% rename from services/billing-service/src/modules/licenses/repository.ts rename to services/platform-service/src/modules/licenses/repository.ts diff --git a/services/billing-service/src/modules/licenses/routes.ts b/services/platform-service/src/modules/licenses/routes.ts similarity index 100% rename from services/billing-service/src/modules/licenses/routes.ts rename to services/platform-service/src/modules/licenses/routes.ts diff --git a/services/billing-service/src/modules/licenses/types.ts b/services/platform-service/src/modules/licenses/types.ts similarity index 100% rename from services/billing-service/src/modules/licenses/types.ts rename to services/platform-service/src/modules/licenses/types.ts diff --git a/services/billing-service/src/modules/plans/plans.test.ts b/services/platform-service/src/modules/plans/plans.test.ts similarity index 100% rename from services/billing-service/src/modules/plans/plans.test.ts rename to services/platform-service/src/modules/plans/plans.test.ts diff --git a/services/billing-service/src/modules/plans/repository.ts b/services/platform-service/src/modules/plans/repository.ts similarity index 100% rename from services/billing-service/src/modules/plans/repository.ts rename to services/platform-service/src/modules/plans/repository.ts diff --git a/services/billing-service/src/modules/plans/routes.ts b/services/platform-service/src/modules/plans/routes.ts similarity index 100% rename from services/billing-service/src/modules/plans/routes.ts rename to services/platform-service/src/modules/plans/routes.ts diff --git a/services/billing-service/src/modules/plans/types.ts b/services/platform-service/src/modules/plans/types.ts similarity index 100% rename from services/billing-service/src/modules/plans/types.ts rename to services/platform-service/src/modules/plans/types.ts diff --git a/services/billing-service/src/modules/stripe/routes.ts b/services/platform-service/src/modules/stripe/routes.ts similarity index 100% rename from services/billing-service/src/modules/stripe/routes.ts rename to services/platform-service/src/modules/stripe/routes.ts diff --git a/services/billing-service/src/modules/subscriptions/repository.ts b/services/platform-service/src/modules/subscriptions/repository.ts similarity index 100% rename from services/billing-service/src/modules/subscriptions/repository.ts rename to services/platform-service/src/modules/subscriptions/repository.ts diff --git a/services/billing-service/src/modules/subscriptions/routes.ts b/services/platform-service/src/modules/subscriptions/routes.ts similarity index 100% rename from services/billing-service/src/modules/subscriptions/routes.ts rename to services/platform-service/src/modules/subscriptions/routes.ts diff --git a/services/billing-service/src/modules/subscriptions/subscriptions.test.ts b/services/platform-service/src/modules/subscriptions/subscriptions.test.ts similarity index 100% rename from services/billing-service/src/modules/subscriptions/subscriptions.test.ts rename to services/platform-service/src/modules/subscriptions/subscriptions.test.ts diff --git a/services/billing-service/src/modules/subscriptions/types.ts b/services/platform-service/src/modules/subscriptions/types.ts similarity index 100% rename from services/billing-service/src/modules/subscriptions/types.ts rename to services/platform-service/src/modules/subscriptions/types.ts diff --git a/services/billing-service/src/modules/usage/repository.ts b/services/platform-service/src/modules/usage/repository.ts similarity index 100% rename from services/billing-service/src/modules/usage/repository.ts rename to services/platform-service/src/modules/usage/repository.ts diff --git a/services/billing-service/src/modules/usage/routes.ts b/services/platform-service/src/modules/usage/routes.ts similarity index 100% rename from services/billing-service/src/modules/usage/routes.ts rename to services/platform-service/src/modules/usage/routes.ts diff --git a/services/billing-service/src/modules/usage/types.ts b/services/platform-service/src/modules/usage/types.ts similarity index 100% rename from services/billing-service/src/modules/usage/types.ts rename to services/platform-service/src/modules/usage/types.ts diff --git a/services/billing-service/src/modules/usage/usage.test.ts b/services/platform-service/src/modules/usage/usage.test.ts similarity index 100% rename from services/billing-service/src/modules/usage/usage.test.ts rename to services/platform-service/src/modules/usage/usage.test.ts diff --git a/services/platform-service/src/server.ts b/services/platform-service/src/server.ts index dea836a9..f5a9bfee 100644 --- a/services/platform-service/src/server.ts +++ b/services/platform-service/src/server.ts @@ -2,7 +2,8 @@ * Platform Service — Fastify server entry point. * * Modules: auth, audit, notifications, feature flags, blob, - * invitations, referrals, promos (merged from growth-service). + * invitations, referrals, promos (merged from growth-service), + * subscriptions, usage, plans, licenses, stripe (merged from billing-service). * Port: 4003 (configurable via PORT env var). */ @@ -16,6 +17,11 @@ import { blobRoutes } from './modules/blob/routes.js'; import { invitationRoutes } from './modules/invitations/routes.js'; import { referralRoutes } from './modules/referrals/routes.js'; import { promoRoutes } from './modules/promos/routes.js'; +import { subscriptionRoutes } from './modules/subscriptions/routes.js'; +import { usageRoutes } from './modules/usage/routes.js'; +import { planRoutes } from './modules/plans/routes.js'; +import { licenseRoutes } from './modules/licenses/routes.js'; +import { stripeRoutes } from './modules/stripe/routes.js'; import { initCosmosIfNeeded } from './lib/cosmos-init.js'; import { config } from './lib/config.js'; @@ -24,11 +30,11 @@ await initCosmosIfNeeded(); const app = await createServiceApp({ name: 'platform-service', version: '0.1.0', - description: 'Auth, audit, notifications, feature flags, rate limiting, invitations, referrals, promos', + description: 'Auth, audit, notifications, feature flags, rate limiting, invitations, referrals, promos, subscriptions, usage, plans, licenses, stripe', corsOrigin: config.CORS_ORIGIN, swagger: { title: 'Platform Service', - description: 'Auth, audit, notifications, feature flags, rate limiting, invitations, referrals, promos', + description: 'Auth, audit, notifications, feature flags, rate limiting, invitations, referrals, promos, subscriptions, usage, plans, licenses, stripe', port: config.PORT, }, metrics: true, @@ -45,5 +51,29 @@ await app.register(blobRoutes, { prefix: '/api' }); await app.register(invitationRoutes, { prefix: '/api' }); await app.register(referralRoutes, { prefix: '/api' }); await app.register(promoRoutes, { prefix: '/api' }); +// Billing modules (merged from billing-service) +// Scoped with internal key auth guard when BILLING_INTERNAL_KEY is set (Gap 3) +const BILLING_KEY = config.BILLING_INTERNAL_KEY; +if (BILLING_KEY) { + await app.register(async (billingScope) => { + billingScope.addHook('onRequest', async (req, reply) => { + const key = req.headers['x-internal-key']; + if (key !== BILLING_KEY) { + reply.code(401).send({ error: 'Unauthorized — missing or invalid X-Internal-Key' }); + } + }); + await billingScope.register(subscriptionRoutes, { prefix: '/api' }); + await billingScope.register(usageRoutes, { prefix: '/api' }); + await billingScope.register(planRoutes, { prefix: '/api' }); + await billingScope.register(licenseRoutes, { prefix: '/api' }); + }); +} else { + await app.register(subscriptionRoutes, { prefix: '/api' }); + await app.register(usageRoutes, { prefix: '/api' }); + await app.register(planRoutes, { prefix: '/api' }); + await app.register(licenseRoutes, { prefix: '/api' }); +} +// Stripe routes outside billing scope (webhook has its own signature verification) +await app.register(stripeRoutes, { prefix: '/api' }); await startService(app, { port: config.PORT, host: config.HOST });