Add optional service pricing matrix and fix admin catalog save.

Users pick per-service CPU/memory/storage at deploy; admins manage unit rates and deploy defaults. PATCH sends only fields accepted by the pricing-catalog DTO.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-05-15 19:16:20 +03:30
parent bb27c90ae4
commit 055e7a7c8d
21 changed files with 1746 additions and 257 deletions
@@ -24,6 +24,14 @@ export const RUNTIME_PRICING_RESOURCES: PricingResourceType[] = [
PricingResourceType.DATABASE_ADDON,
];
/** Same billing rows as apps, without database (not applicable to Redis/RabbitMQ/ES). */
export const OPTIONAL_SERVICE_BILLING_RESOURCES: PricingResourceType[] = [
PricingResourceType.BASE_FEE,
PricingResourceType.CPU_PER_CORE,
PricingResourceType.MEMORY_PER_GB,
PricingResourceType.STORAGE_PER_GB,
];
/** Maps optional service → flat addon row in addon_rates. */
export const OPTIONAL_SERVICE_PRICING_TYPE: Record<OptionalService, PricingResourceType> = {
[OptionalService.REDIS]: PricingResourceType.REDIS_ADDON,
@@ -32,10 +40,11 @@ export const OPTIONAL_SERVICE_PRICING_TYPE: Record<OptionalService, PricingResou
};
export function getBillableAddonResourceTypes(): PricingResourceType[] {
return [
...Object.values(OPTIONAL_SERVICE_PRICING_TYPE),
PricingResourceType.CUSTOM_DOMAIN_ADDON,
];
return [PricingResourceType.CUSTOM_DOMAIN_ADDON];
}
export function getAllOptionalServices(): OptionalService[] {
return Object.values(OptionalService);
}
export const OPTIONAL_SERVICE_LABELS: Record<OptionalService, string> = {
@@ -47,11 +56,35 @@ export const OPTIONAL_SERVICE_LABELS: Record<OptionalService, string> = {
/** Deploy footprint aligned with helm/cloudhost-app defaults (limits used for billing). */
export const OPTIONAL_SERVICE_DEPLOY_SPECS: Record<
OptionalService,
{ cpuLimit: string; memoryLimit: string; storageGi: number }
{
cpuRequest: string;
memoryRequest: string;
cpuLimit: string;
memoryLimit: string;
storageGi: number;
}
> = {
[OptionalService.REDIS]: { cpuLimit: '200m', memoryLimit: '256Mi', storageGi: 1 },
[OptionalService.RABBITMQ]: { cpuLimit: '500m', memoryLimit: '512Mi', storageGi: 2 },
[OptionalService.ELASTICSEARCH]: { cpuLimit: '50m', memoryLimit: '64Mi', storageGi: 0 },
[OptionalService.REDIS]: {
cpuRequest: '50m',
memoryRequest: '64Mi',
cpuLimit: '200m',
memoryLimit: '256Mi',
storageGi: 1,
},
[OptionalService.RABBITMQ]: {
cpuRequest: '100m',
memoryRequest: '256Mi',
cpuLimit: '500m',
memoryLimit: '512Mi',
storageGi: 2,
},
[OptionalService.ELASTICSEARCH]: {
cpuRequest: '50m',
memoryRequest: '64Mi',
cpuLimit: '50m',
memoryLimit: '64Mi',
storageGi: 0,
},
};
/** Fluent Bit sidecar per workload when Elasticsearch logging is enabled. */