134 lines
5.7 KiB
TypeScript
134 lines
5.7 KiB
TypeScript
import "dotenv/config";
|
|
|
|
function required(name: string, fallback?: string): string {
|
|
const v = process.env[name] ?? fallback;
|
|
if (!v) {
|
|
throw new Error(`Missing required env var: ${name}`);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
export const config = {
|
|
port: Number(process.env.PORT ?? 4000),
|
|
logLevel: process.env.LOG_LEVEL ?? "info",
|
|
nodeEnv: process.env.NODE_ENV ?? "development",
|
|
|
|
// Postgres metadata DB (users, registry, container mappings).
|
|
databaseUrl:
|
|
process.env.DATABASE_URL ??
|
|
"***************************************/growqr",
|
|
|
|
// Clerk auth.
|
|
clerkSecretKey: process.env.CLERK_SECRET_KEY ?? "",
|
|
clerkPublishableKey: process.env.CLERK_PUBLISHABLE_KEY ?? "",
|
|
// Optional: lock service-to-service calls (actor → backend).
|
|
serviceToken: process.env.SERVICE_TOKEN ?? "",
|
|
a2aAllowedKey: process.env.A2A_ALLOWED_KEY ?? "dev-a2a-key",
|
|
|
|
// Service → backend event stream. Redis is optional; HTTP /events/ingest/service is always available.
|
|
growEventsRedisUrl: process.env.GROW_EVENTS_REDIS_URL ?? process.env.REDIS_URL ?? "",
|
|
growEventsStream: process.env.GROW_EVENTS_STREAM ?? "grow.events.raw",
|
|
growEventsConsumerGroup: process.env.GROW_EVENTS_CONSUMER_GROUP ?? "growqr-backend",
|
|
growEventsConsumerName: process.env.GROW_EVENTS_CONSUMER_NAME ?? `backend-${process.pid}`,
|
|
|
|
// Legacy service Redis surfaces. These let backend observe existing service A2A traffic
|
|
// without changing the services. Defaults fall back to GROW_EVENTS_REDIS_URL/REDIS_URL.
|
|
interviewRedisUrl: process.env.INTERVIEW_REDIS_URL ?? process.env.GROW_EVENTS_REDIS_URL ?? process.env.REDIS_URL ?? "",
|
|
roleplayRedisUrl: process.env.ROLEPLAY_REDIS_URL ?? process.env.GROW_EVENTS_REDIS_URL ?? process.env.REDIS_URL ?? "",
|
|
resumeRedisUrl: process.env.RESUME_REDIS_URL ?? process.env.GROW_EVENTS_REDIS_URL ?? process.env.REDIS_URL ?? "",
|
|
legacyServiceTaskObserverGroup: process.env.LEGACY_SERVICE_TASK_OBSERVER_GROUP ?? "growqr-backend-observer",
|
|
|
|
// LLM gateway for the unified user agent.
|
|
llmProvider: process.env.LLM_PROVIDER ?? "opencode",
|
|
llmApiKey:
|
|
process.env.LLM_API_KEY ??
|
|
process.env.OPENCODE_API_KEY ??
|
|
"",
|
|
llmBaseUrl:
|
|
process.env.LLM_BASE_URL ??
|
|
process.env.OPENCODE_BASE_URL ??
|
|
"https://opencode.ai/zen/v1",
|
|
opencodeApiKey: process.env.OPENCODE_API_KEY ?? "",
|
|
agentModel:
|
|
process.env.GROW_AGENT_MODEL ??
|
|
process.env.LLM_MODEL ??
|
|
"kimi-k2.6",
|
|
|
|
// Rivet Kit engine endpoint (self-hosted in docker-compose).
|
|
rivetEndpoint: process.env.RIVET_ENDPOINT ?? "http://localhost:6420",
|
|
rivetClientEndpoint:
|
|
process.env.RIVET_CLIENT_ENDPOINT ??
|
|
`http://127.0.0.1:${Number(process.env.PORT ?? 4000)}/api/rivet`,
|
|
|
|
// Product microservices exposed as sub-agent surfaces.
|
|
interviewServiceUrl:
|
|
process.env.INTERVIEW_SERVICE_URL ?? "http://localhost:8007",
|
|
interviewPublicUrl:
|
|
process.env.INTERVIEW_PUBLIC_URL ?? process.env.INTERVIEW_SERVICE_URL ?? "http://localhost:8007",
|
|
roleplayServiceUrl:
|
|
process.env.ROLEPLAY_SERVICE_URL ?? "http://localhost:8008",
|
|
roleplayPublicUrl:
|
|
process.env.ROLEPLAY_PUBLIC_URL ?? process.env.ROLEPLAY_SERVICE_URL ?? "http://localhost:8008",
|
|
qscoreServiceUrl:
|
|
process.env.QSCORE_SERVICE_URL ?? "http://localhost:8000",
|
|
resumeServiceUrl:
|
|
process.env.RESUME_SERVICE_URL ?? "http://localhost:8002",
|
|
userServiceUrl:
|
|
process.env.USER_SERVICE_URL ?? "http://localhost:8003",
|
|
resumePublicUrl:
|
|
process.env.RESUME_PUBLIC_URL ?? process.env.RESUME_SERVICE_URL ?? "http://localhost:8002",
|
|
matchmakingServiceUrl:
|
|
process.env.MATCHMAKING_SERVICE_URL ?? "http://localhost:8006",
|
|
socialBrandingServiceUrl:
|
|
process.env.SOCIAL_BRANDING_SERVICE_URL ?? "http://localhost:8005",
|
|
workflowsDashboardUrl:
|
|
process.env.WORKFLOWS_DASHBOARD_URL ??
|
|
process.env.FRONTEND_ORIGIN ??
|
|
"http://localhost:3000",
|
|
|
|
// ── Central Gitea (one org-wide instance, changes.md §2A) ──
|
|
// Public URL is what Git remotes should use and what OpenCode containers see.
|
|
// Internal URL is only for backend-to-Gitea API calls on a private network.
|
|
giteaPublicUrl:
|
|
process.env.GITEA_PUBLIC_URL ??
|
|
process.env.GITEA_URL ??
|
|
"http://127.0.0.1:3001",
|
|
giteaInternalUrl:
|
|
process.env.GITEA_INTERNAL_URL ??
|
|
process.env.GITEA_URL ??
|
|
process.env.GITEA_PUBLIC_URL ??
|
|
"http://127.0.0.1:3001",
|
|
giteaAdminUser: process.env.GITEA_ADMIN_USER ?? "growqr-admin",
|
|
giteaAdminPassword: process.env.GITEA_ADMIN_PASSWORD ?? "growqr-admin-dev",
|
|
giteaAdminToken: process.env.GITEA_ADMIN_TOKEN ?? "",
|
|
giteaOrgName: process.env.GITEA_ORG_NAME ?? "growqr",
|
|
|
|
// ── Shared OpenCode runtime image (built once, changes.md §3) ──
|
|
opencodeImage:
|
|
process.env.OPENCODE_IMAGE ?? "growqr/opencode:dev",
|
|
// Version tracking for rollout (changes.md §9)
|
|
opencodeImageVersion: process.env.OPENCODE_IMAGE_VERSION ?? "dev",
|
|
migrationVersion: process.env.MIGRATION_VERSION ?? "1",
|
|
promptVersion: process.env.PROMPT_VERSION ?? "4",
|
|
|
|
// Host that user containers expose ports on (the host running Docker).
|
|
userContainerHost: process.env.USER_CONTAINER_HOST ?? "127.0.0.1",
|
|
userDataRoot: process.env.USER_DATA_ROOT ?? "./.data/users",
|
|
// Port range for per-user OpenCode containers only (Gitea is shared).
|
|
userPortRangeStart: Number(process.env.USER_PORT_RANGE_START ?? 20000),
|
|
userPortRangeEnd: Number(process.env.USER_PORT_RANGE_END ?? 29999),
|
|
|
|
// CORS for the Next.js frontend.
|
|
frontendOrigin:
|
|
process.env.FRONTEND_ORIGIN ?? "http://localhost:3000",
|
|
adminUserIds: (process.env.ADMIN_USER_IDS ?? "")
|
|
.split(",")
|
|
.map((s) => s.trim())
|
|
.filter(Boolean),
|
|
|
|
// Used by LLM requests.
|
|
maxAgentTokens: Number(process.env.MAX_AGENT_TOKENS ?? 4096),
|
|
|
|
required, // exported so other modules can fail fast on boot
|
|
} as const;
|