This commit is contained in:
Eric Gullickson
2025-11-01 21:27:42 -05:00
parent 20953c6dee
commit 046c66fc7d
203 changed files with 5699 additions and 404943 deletions

View File

@@ -16,7 +16,6 @@ const configSchema = z.object({
name: z.string(),
port: z.number(),
environment: z.string(),
tenant_id: z.string(),
node_env: z.string(),
}),
@@ -49,19 +48,9 @@ const configSchema = z.object({
url: z.string(),
timeout: z.string(),
}),
tenants: z.object({
url: z.string(),
timeout: z.string(),
}),
}),
}),
// MinIO configuration
minio: z.object({
endpoint: z.string(),
port: z.number(),
bucket: z.string(),
}),
// External APIs configuration
external: z.object({
@@ -85,7 +74,6 @@ const configSchema = z.object({
// Frontend configuration
frontend: z.object({
tenant_id: z.string(),
api_base_url: z.string(),
auth0: z.object({
domain: z.string(),
@@ -144,9 +132,6 @@ const configSchema = z.object({
// Secrets schema definition
const secretsSchema = z.object({
postgres_password: z.string(),
minio_access_key: z.string(),
minio_secret_key: z.string(),
platform_vehicles_api_key: z.string(),
auth0_client_secret: z.string(),
google_maps_api_key: z.string(),
});
@@ -162,8 +147,7 @@ export interface AppConfiguration {
getDatabaseUrl(): string;
getRedisUrl(): string;
getAuth0Config(): { domain: string; audience: string; clientSecret: string };
getPlatformServiceConfig(service: 'vehicles' | 'tenants'): { url: string; apiKey: string };
getMinioConfig(): { endpoint: string; port: number; accessKey: string; secretKey: string; bucket: string };
getPlatformVehiclesUrl(): string;
}
class ConfigurationLoader {
@@ -197,9 +181,6 @@ class ConfigurationLoader {
const secretFiles = [
'postgres-password',
'minio-access-key',
'minio-secret-key',
'platform-vehicles-api-key',
'auth0-client-secret',
'google-maps-api-key',
];
@@ -257,24 +238,8 @@ class ConfigurationLoader {
};
},
getPlatformServiceConfig(service: 'vehicles' | 'tenants') {
const serviceConfig = config.platform.services[service];
const apiKey = service === 'vehicles' ? secrets.platform_vehicles_api_key : 'mvp-platform-tenants-secret-key';
return {
url: serviceConfig.url,
apiKey,
};
},
getMinioConfig() {
return {
endpoint: config.minio.endpoint,
port: config.minio.port,
accessKey: secrets.minio_access_key,
secretKey: secrets.minio_secret_key,
bucket: config.minio.bucket,
};
getPlatformVehiclesUrl(): string {
return config.platform.services.vehicles.url;
},
};

View File

@@ -4,12 +4,10 @@
*/
import { Pool } from 'pg';
import { logger } from '../logging/logger';
import { getTenantConfig } from './tenant';
const tenant = getTenantConfig();
import { appConfig } from './config-loader';
export const pool = new Pool({
connectionString: tenant.databaseUrl,
connectionString: appConfig.getDatabaseUrl(),
max: 10,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 10000,

View File

@@ -4,11 +4,9 @@
*/
import Redis from 'ioredis';
import { logger } from '../logging/logger';
import { getTenantConfig } from './tenant';
import { appConfig } from './config-loader';
const tenant = getTenantConfig();
export const redis = new Redis(tenant.redisUrl, {
export const redis = new Redis(appConfig.getRedisUrl(), {
retryStrategy: (times) => Math.min(times * 50, 2000),
});

View File

@@ -1,69 +0,0 @@
import axios from 'axios';
import { appConfig } from './config-loader';
// Simple in-memory cache for tenant validation
const tenantValidityCache = new Map<string, { ok: boolean; ts: number }>();
const TENANT_CACHE_TTL_MS = 60_000; // 1 minute
/**
* Tenant-aware configuration for multi-tenant architecture
*/
export interface TenantConfig {
tenantId: string;
databaseUrl: string;
redisUrl: string;
platformServicesUrl: string;
isAdminTenant: boolean;
}
export const getTenantConfig = (): TenantConfig => {
const tenantId = appConfig.config.server.tenant_id;
const databaseUrl = tenantId === 'admin'
? appConfig.getDatabaseUrl()
: `postgresql://${appConfig.config.database.user}:${appConfig.secrets.postgres_password}@${tenantId}-postgres:5432/${appConfig.config.database.name}`;
const redisUrl = tenantId === 'admin'
? appConfig.getRedisUrl()
: `redis://${tenantId}-redis:6379`;
const platformServicesUrl = appConfig.getPlatformServiceConfig('tenants').url;
return {
tenantId,
databaseUrl,
redisUrl,
platformServicesUrl,
isAdminTenant: tenantId === 'admin'
};
};
export const isValidTenant = async (tenantId: string): Promise<boolean> => {
// Check cache
const now = Date.now();
const cached = tenantValidityCache.get(tenantId);
if (cached && (now - cached.ts) < TENANT_CACHE_TTL_MS) {
return cached.ok;
}
let ok = false;
try {
const baseUrl = appConfig.getPlatformServiceConfig('tenants').url;
const url = `${baseUrl}/api/v1/tenants/${encodeURIComponent(tenantId)}`;
const resp = await axios.get(url, { timeout: 2000 });
ok = resp.status === 200;
} catch { ok = false; }
tenantValidityCache.set(tenantId, { ok, ts: now });
return ok;
};
export const extractTenantId = (options: {
envTenantId?: string;
jwtTenantId?: string;
subdomain?: string;
}): string => {
const { envTenantId, jwtTenantId, subdomain } = options;
return envTenantId || jwtTenantId || subdomain || 'admin';
};