검증 Catalog 의 백업·이전·보존 정책을 생명주기 영역 정책 읽기와 연결, VERSION_HISTORY 초안
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
68027b7bde
commit
deae7e31e0
@@ -50,8 +50,22 @@ export const operatorOf = (body) => String((body && body.operator) || 'operator'
|
||||
*/
|
||||
export function productPolicy(deps, productId, required = []) {
|
||||
const now = nowIso();
|
||||
const v = deps.store.get('SELECT * FROM product_versions WHERE product_id=? AND published=1 AND effective_from<=? AND (effective_to IS NULL OR effective_to>?) ORDER BY version DESC LIMIT 1', productId, now, now) || null;
|
||||
const limits = parseJson(v?.limits_json, {}) || {}; const policy = parseJson(v?.policy_json, {}) || {};
|
||||
let v = deps.store.get('SELECT * FROM product_versions WHERE product_id=? AND published=1 AND effective_from<=? AND (effective_to IS NULL OR effective_to>?) ORDER BY version DESC LIMIT 1', productId, now, now) || null;
|
||||
let limits = parseJson(v?.limits_json, {}) || {}; let policy = parseJson(v?.policy_json, {}) || {}; let derivedPrice = null;
|
||||
// [통합 보완] 상거래 영역의 Catalog 는 백업·이전·보존 정책을 "별도 상품" 이 아니라 기본 상품(basic/team)의 옵션(backup)과 policy(relocation·retention_days·lifecycle) 안에 둔다.
|
||||
// 전용 product_id 행이 없으면 활성 기본 상품에서 같은 뜻의 값을 유도한다(키 이름 대응은 아래). 전용 행이 있으면 그것이 우선한다(운영자가 나중에 분리 등록할 수 있음).
|
||||
if (!v && ['backup', 'relocation', 'retention'].includes(productId)) {
|
||||
const base = deps.store.get('SELECT * FROM product_versions WHERE kind=\'base\' AND published=1 AND effective_from<=? AND (effective_to IS NULL OR effective_to>?) ORDER BY version DESC, created_at DESC LIMIT 1', now, now);
|
||||
if (base) {
|
||||
const bp = parseJson(base.policy_json, {}) || {}; const opts = parseJson(base.options_json, []) || [];
|
||||
if (productId === 'backup') { const o = opts.find((x) => x.id === 'backup'); const q = (o && o.policy) || {}; limits = { storage_bytes: q.storage_bytes }; derivedPrice = o ? o.price : null;
|
||||
policy = { schedule: q.schedule, schedule_time_kst: q.schedule_time_kst, retention: q.retention, first_backup_within_hours: q.first_backup_within_hours, verify_method: q.verify_method ?? q.remote_copy_verification, restore_cost: q.restore_cost, restore_approval: q.restore_approval, restore_completion: q.restore_completion, protect_point_days: q.protect_point_days, revert_hours: q.revert_hours, expiry_retention_days: q.expiry_retention_days ?? q.expired_backup_retention_days, failure_notify_after: q.failure_notify_after ?? q.failure_alert_after, resume_after_pause: q.resume_after_pause, restore_downtime_minutes: q.restore_downtime_minutes }; }
|
||||
else if (productId === 'relocation') { const r = bp.relocation || {}; policy = { target_downtime_min: r.target_downtime_min ?? r.target_downtime_minutes, revert_hours: r.revert_hours ?? r.revert_window_hours, old_retention_days: r.old_retention_days ?? (r.old_location_retention_hours != null ? Math.ceil(r.old_location_retention_hours / 24) : undefined), customer_cost: r.customer_cost ?? r.customer_requested_fee, platform_cost: r.platform_reason_fee ?? 0, dns_wait_handling: r.dns_wait_handling, write_freeze: r.write_freeze }; }
|
||||
else { const rd = bp.retention_days || {}; const lc = bp.lifecycle || {}; policy = { site_days: rd.site, mail_days: rd.mail, source_days: rd.source, backup_days: rd.backup_after_expiry, readonly_retention_days: lc.readonly_retention_days, delete_after_days: lc.delete_after_days, pause_keeps_site_count: lc.pause_keeps_site_count, cancel_effective: lc.cancel_effective }; }
|
||||
for (const k of Object.keys(policy)) if (policy[k] === undefined) delete policy[k];
|
||||
v = { ...base, name: `${base.name} (${productId} 정책)`, price: derivedPrice ?? 0, derived_from: base.id };
|
||||
}
|
||||
}
|
||||
const deferred = required.filter((k) => { const [bag, key] = k.split('.'); const src = bag === 'limits' ? limits : policy; return src[key] === undefined || src[key] === null || src[key] === ''; });
|
||||
return { version: v, limits, policy, deferred, priceKrw: v ? v.price : null, currency: v ? v.currency : 'KRW', taxRate: v ? v.tax_rate : 0.1 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user