/** * Platform Service — Fastify server entry point. * * Modules: auth, audit, notifications, feature flags, blob, * invitations, referrals, promos (merged from growth-service), * subscriptions, usage, plans, licenses, stripe (merged from billing-service), * items, comments, votes, public (merged from tracker-service). * Port: 4003 (configurable via PORT env var). */ // Resolve secrets from configured provider BEFORE config parsing import { resolveSecrets, LYSNR_SECRETS } from '@bytelyst/config'; await resolveSecrets([ LYSNR_SECRETS.COSMOS_KEY, LYSNR_SECRETS.COSMOS_ENDPOINT, LYSNR_SECRETS.JWT_SECRET, LYSNR_SECRETS.STRIPE_SECRET_KEY, LYSNR_SECRETS.STRIPE_WEBHOOK_SECRET, LYSNR_SECRETS.AZURE_BLOB_CONNECTION_STRING, LYSNR_SECRETS.AZURE_BLOB_ACCOUNT_KEY, ]); import { createServiceApp, registerOptionalJwtContext, startService } from '@bytelyst/fastify-core'; import { productRoutes } from './modules/products/routes.js'; import { loadProductCache } from './modules/products/cache.js'; import { authRoutes } from './modules/auth/routes.js'; import { oauthRoutes } from './modules/auth/oauth/routes.js'; import { mfaRoutes } from './modules/auth/mfa/routes.js'; import { passkeyRoutes } from './modules/auth/passkeys/routes.js'; import { deviceRoutes } from './modules/auth/devices/routes.js'; import { loginEventRoutes } from './modules/auth/login-events/routes.js'; import { pushApprovalRoutes } from './modules/auth/push-approvals/routes.js'; import { qrAuthRoutes } from './modules/auth/qr-auth/routes.js'; import { enterpriseRoutes } from './modules/auth/enterprise/routes.js'; import { magicLinkRoutes } from './modules/auth/magic-link/routes.js'; import { auditRoutes } from './modules/audit/routes.js'; import { notificationRoutes } from './modules/notifications/routes.js'; import { flagRoutes } from './modules/flags/routes.js'; import { rateLimitRoutes } from './modules/ratelimit/routes.js'; import { blobRoutes } from './modules/blob/routes.js'; import { invitationRoutes } from './modules/invitations/routes.js'; import { referralRoutes } from './modules/referrals/routes.js'; import { referralMigrationAdminRoutes } from './modules/referrals/migration-admin-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 { settingsRoutes } from './modules/settings/routes.js'; import { itemRoutes } from './modules/items/routes.js'; import { commentRoutes } from './modules/comments/routes.js'; import { voteRoutes } from './modules/votes/routes.js'; import { publicRoutes } from './modules/public/routes.js'; import { tokenRoutes } from './modules/tokens/routes.js'; import { themeRoutes } from './modules/themes/routes.js'; import { waitlistRoutes } from './modules/waitlist/routes.js'; import { telemetryRoutes } from './modules/telemetry/routes.js'; import { diagnosticsRoutes } from './modules/diagnostics/routes.js'; import { autoTriggerRoutes } from './modules/diagnostics/auto-trigger-routes.js'; import { crashTriggerRoutes } from './modules/diagnostics/crash-trigger.js'; import { sessionReplayRoutes } from './modules/diagnostics/session-replay-routes.js'; import { performanceProfileRoutes } from './modules/diagnostics/performance-profile-routes.js'; import { startTriggerEvaluationJob } from './modules/diagnostics/trigger-job.js'; import { broadcastRoutes } from './modules/broadcasts/routes.js'; import { surveyRoutes } from './modules/surveys/routes.js'; import { jobRoutes } from './modules/jobs/routes.js'; import { statusRoutes } from './modules/status/routes.js'; import { deliveryRoutes } from './modules/delivery/routes.js'; import { sessionRoutes } from './modules/sessions/routes.js'; import { maintenanceRoutes } from './modules/maintenance/routes.js'; import { exportRoutes } from './modules/exports/routes.js'; import { ipRuleRoutes } from './modules/ip-rules/routes.js'; import { experimentRoutes } from './modules/experiments/routes.js'; import { abTestingRoutes } from './modules/ab-testing/routes.js'; import { analyticsRoutes } from './modules/analytics/routes.js'; import { feedbackRoutes } from './modules/feedback/routes.js'; import { impersonationRoutes } from './modules/impersonation/routes.js'; import { changelogRoutes } from './modules/changelog/routes.js'; import { webhookRoutes } from './modules/webhooks/routes.js'; import { marketplaceRoutes } from './modules/marketplace/routes.js'; import { predictiveAnalyticsRoutes } from './modules/predictive-analytics/routes.js'; import { initCosmosIfNeeded } from './lib/cosmos-init.js'; import { config } from './lib/config.js'; import type { JwtPayload } from './lib/request-context.js'; import { seedDefaultFlags } from './modules/flags/seed.js'; import { runPendingMigrations } from './migrations/runner.js'; import { registerDiagnosticsSubscribers } from './modules/diagnostics/subscribers.js'; import { registerDeliverySubscribers } from './modules/delivery/subscribers.js'; import { verifyToken } from './modules/auth/jwt.js'; await initCosmosIfNeeded(); await loadProductCache(); // Run pending database migrations (idempotent, best-effort — failures don't block startup) runPendingMigrations().catch(() => {}); // Seed default feature flags (idempotent, best-effort) seedDefaultFlags({ info: (msg: string) => process.stdout.write(`[flags-seed] ${msg}\n`) }).catch( () => {} ); const app = await createServiceApp({ name: 'platform-service', version: '0.1.0', 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, subscriptions, usage, plans, licenses, stripe', port: config.PORT, }, metrics: true, }); await registerOptionalJwtContext(app, { verifyToken: async token => (await verifyToken(token)) as JwtPayload, }); // Register route modules await app.register(productRoutes, { prefix: '/api' }); await app.register(authRoutes, { prefix: '/api' }); await app.register(oauthRoutes, { prefix: '/api' }); await app.register(mfaRoutes, { prefix: '/api' }); await app.register(passkeyRoutes, { prefix: '/api' }); await app.register(deviceRoutes, { prefix: '/api' }); await app.register(loginEventRoutes, { prefix: '/api' }); await app.register(pushApprovalRoutes, { prefix: '/api' }); await app.register(qrAuthRoutes, { prefix: '/api' }); await app.register(enterpriseRoutes, { prefix: '/api' }); await app.register(magicLinkRoutes, { prefix: '/api' }); await app.register(auditRoutes, { prefix: '/api' }); await app.register(notificationRoutes, { prefix: '/api' }); await app.register(flagRoutes, { prefix: '/api' }); await app.register(rateLimitRoutes, { prefix: '/api' }); await app.register(blobRoutes, { prefix: '/api' }); // Growth modules (merged from growth-service) await app.register(invitationRoutes, { prefix: '/api' }); await app.register(referralRoutes, { prefix: '/api' }); await app.register(referralMigrationAdminRoutes, { prefix: '/api/admin' }); await app.register(promoRoutes, { prefix: '/api' }); // Billing modules (merged from billing-service) 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' }); // Settings module (user-level global settings + per-device overrides) await app.register(settingsRoutes, { prefix: '/api' }); // Tracker modules (merged from tracker-service) await app.register(itemRoutes, { prefix: '/api' }); await app.register(commentRoutes, { prefix: '/api' }); await app.register(voteRoutes, { prefix: '/api' }); // API tokens module await app.register(tokenRoutes, { prefix: '/api' }); // Themes module await app.register(themeRoutes, { prefix: '/api' }); // Waitlist module (pre-launch signups — public + admin routes) await app.register(waitlistRoutes, { prefix: '/api' }); // Telemetry module (client ingest + admin query + policies) await app.register(telemetryRoutes, { prefix: '/api' }); // Diagnostics module (remote debug sessions — see docs/devops/REMOTE_DIAGNOSTICS_ROADMAP.md) await app.register(diagnosticsRoutes, { prefix: '/api' }); // Auto-trigger routes for automated debug sessions (Phase 4) await app.register(autoTriggerRoutes, { prefix: '/api' }); // Crash-trigger routes for crash-triggered auto-sessions (Phase 4) await app.register(crashTriggerRoutes, { prefix: '/api' }); // Session replay routes (Phase 4) await app.register(sessionReplayRoutes, { prefix: '/api' }); // Performance profiling routes (Phase 4) await app.register(performanceProfileRoutes, { prefix: '/api' }); // Public routes — no auth, registered at top level await app.register(publicRoutes, { prefix: '/api' }); // Scheduled jobs module (admin: list, trigger, view runs) await app.register(jobRoutes, { prefix: '/api' }); // Public status page + incident management await app.register(statusRoutes, { prefix: '/api' }); // Transactional email delivery await app.register(deliveryRoutes, { prefix: '/api' }); // Session management await app.register(sessionRoutes, { prefix: '/api' }); // Maintenance mode await app.register(maintenanceRoutes, { prefix: '/api' }); // Data exports await app.register(exportRoutes, { prefix: '/api' }); // IP allow/deny rules await app.register(ipRuleRoutes, { prefix: '/api' }); // P2 — Product Intelligence await app.register(experimentRoutes, { prefix: '/api' }); await app.register(abTestingRoutes, { prefix: '/api' }); await app.register(analyticsRoutes, { prefix: '/api' }); await app.register(feedbackRoutes, { prefix: '/api' }); await app.register(impersonationRoutes, { prefix: '/api' }); await app.register(changelogRoutes, { prefix: '/api' }); // Webhook subscriptions (replaces lib/webhooks.ts fire-and-forget) await app.register(webhookRoutes, { prefix: '/api' }); // Generic Marketplace module await app.register(marketplaceRoutes, { prefix: '/api' }); // Predictive Analytics (Churn & Health Scoring) await app.register(predictiveAnalyticsRoutes, { prefix: '/api' }); // Broadcast Messaging & Surveys (see docs/roadmaps/not-started/platform_BROADCAST_SURVEY_ROADMAP.md) await app.register(broadcastRoutes, { prefix: '/api' }); await app.register(surveyRoutes, { prefix: '/api' }); // Register event bus subscribers registerDiagnosticsSubscribers(app.log); registerDeliverySubscribers(app.log); // Start diagnostic trigger evaluation job (Phase 4) startTriggerEvaluationJob(app.log); await startService(app, { port: config.PORT, host: config.HOST });