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:
@@ -0,0 +1,98 @@
|
||||
-- Optional services: resource profile + pricing matrix (same model as application runtimes)
|
||||
|
||||
CREATE TABLE IF NOT EXISTS optional_service_profiles (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
service VARCHAR NOT NULL UNIQUE,
|
||||
cpu_limit VARCHAR NOT NULL DEFAULT '200m',
|
||||
memory_limit VARCHAR NOT NULL DEFAULT '256Mi',
|
||||
storage_gi DECIMAL(10, 2) NOT NULL DEFAULT 0,
|
||||
log_shipper_cpu_limit VARCHAR,
|
||||
log_shipper_memory_limit VARCHAR,
|
||||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS optional_service_rates (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
service VARCHAR NOT NULL,
|
||||
resource_type VARCHAR NOT NULL,
|
||||
hourly_price DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
monthly_price DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
yearly_price DECIMAL(12, 2) NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (service, resource_type)
|
||||
);
|
||||
|
||||
INSERT INTO optional_service_profiles (service, cpu_limit, memory_limit, storage_gi, log_shipper_cpu_limit, log_shipper_memory_limit)
|
||||
VALUES
|
||||
('redis', '200m', '256Mi', 1, NULL, NULL),
|
||||
('rabbitmq', '500m', '512Mi', 2, NULL, NULL),
|
||||
('elasticsearch', '50m', '64Mi', 0, '50m', '64Mi')
|
||||
ON CONFLICT (service) DO NOTHING;
|
||||
|
||||
UPDATE optional_service_profiles SET
|
||||
log_shipper_cpu_limit = '50m',
|
||||
log_shipper_memory_limit = '64Mi'
|
||||
WHERE service = 'elasticsearch' AND log_shipper_cpu_limit IS NULL;
|
||||
|
||||
INSERT INTO optional_service_rates (service, resource_type, hourly_price, monthly_price, yearly_price)
|
||||
SELECT s.service, t.resource_type, 0, 0, 0
|
||||
FROM (VALUES ('redis'), ('rabbitmq'), ('elasticsearch')) AS s(service)
|
||||
CROSS JOIN (
|
||||
VALUES ('base_fee'), ('cpu_per_core'), ('memory_per_gb'), ('storage_per_gb')
|
||||
) AS t(resource_type)
|
||||
ON CONFLICT (service, resource_type) DO NOTHING;
|
||||
|
||||
-- Migrate legacy per-resource addon prices into optional_service_rates (if columns exist)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'addon_rates' AND column_name = 'cpu_hourly_price'
|
||||
) THEN
|
||||
UPDATE optional_service_rates osr SET
|
||||
hourly_price = COALESCE(ar.cpu_hourly_price, 0),
|
||||
monthly_price = COALESCE(ar.cpu_monthly_price, 0),
|
||||
yearly_price = COALESCE(ar.cpu_yearly_price, 0)
|
||||
FROM addon_rates ar
|
||||
WHERE ar.resource_type = 'redis_addon' AND osr.service = 'redis' AND osr.resource_type = 'cpu_per_core'
|
||||
AND (ar.cpu_hourly_price > 0 OR ar.cpu_monthly_price > 0);
|
||||
|
||||
UPDATE optional_service_rates osr SET
|
||||
hourly_price = COALESCE(ar.memory_hourly_price, 0),
|
||||
monthly_price = COALESCE(ar.memory_monthly_price, 0),
|
||||
yearly_price = COALESCE(ar.memory_yearly_price, 0)
|
||||
FROM addon_rates ar
|
||||
WHERE ar.resource_type = 'redis_addon' AND osr.service = 'redis' AND osr.resource_type = 'memory_per_gb'
|
||||
AND (ar.memory_hourly_price > 0 OR ar.memory_monthly_price > 0);
|
||||
|
||||
UPDATE optional_service_rates osr SET
|
||||
hourly_price = COALESCE(ar.storage_hourly_price, 0),
|
||||
monthly_price = COALESCE(ar.storage_monthly_price, 0),
|
||||
yearly_price = COALESCE(ar.storage_yearly_price, 0)
|
||||
FROM addon_rates ar
|
||||
WHERE ar.resource_type = 'redis_addon' AND osr.service = 'redis' AND osr.resource_type = 'storage_per_gb'
|
||||
AND (ar.storage_hourly_price > 0 OR ar.storage_monthly_price > 0);
|
||||
|
||||
UPDATE optional_service_profiles osp SET
|
||||
cpu_limit = COALESCE(ar.cpu_limit, osp.cpu_limit),
|
||||
memory_limit = COALESCE(ar.memory_limit, osp.memory_limit),
|
||||
storage_gi = COALESCE(ar.storage_gi, osp.storage_gi)
|
||||
FROM addon_rates ar WHERE ar.resource_type = 'redis_addon' AND osp.service = 'redis';
|
||||
|
||||
UPDATE optional_service_profiles osp SET
|
||||
cpu_limit = COALESCE(ar.cpu_limit, osp.cpu_limit),
|
||||
memory_limit = COALESCE(ar.memory_limit, osp.memory_limit),
|
||||
storage_gi = COALESCE(ar.storage_gi, osp.storage_gi)
|
||||
FROM addon_rates ar WHERE ar.resource_type = 'rabbitmq_addon' AND osp.service = 'rabbitmq';
|
||||
|
||||
UPDATE optional_service_profiles osp SET
|
||||
cpu_limit = COALESCE(ar.cpu_limit, osp.cpu_limit),
|
||||
memory_limit = COALESCE(ar.memory_limit, osp.memory_limit),
|
||||
log_shipper_cpu_limit = COALESCE(ar.log_shipper_cpu_limit, osp.log_shipper_cpu_limit),
|
||||
log_shipper_memory_limit = COALESCE(ar.log_shipper_memory_limit, osp.log_shipper_memory_limit)
|
||||
FROM addon_rates ar WHERE ar.resource_type = 'elasticsearch_addon' AND osp.service = 'elasticsearch';
|
||||
END IF;
|
||||
END $$;
|
||||
Reference in New Issue
Block a user