feat(lifecycle): add billing lifecycle with auto-suspend/delete
- New AppLifecycleService with cron-based scanner (60s interval) - State machine: ACTIVE → SUSPENDED → PENDING_DELETION → DELETED - Auto-renew hourly plans from wallet - Admin-configurable grace periods via PlatformSettings table - New LifecycleController (GET/PATCH /lifecycle/settings) - PlatformSetting entity for runtime admin config - BillingService: calculateCostForApp, deductWallet - Application entity: planId, billingCycle, lifecycleStatus, planExpiresAt - New enums: AppLifecycleStatus, BillingCycle
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { AppRuntime, DatabaseType } from '../../common/enums';
|
||||
import { AppRuntime, DatabaseType, BillingCycle, AppLifecycleStatus } from '../../common/enums';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
import { Deployment } from '../../deployments/entities/deployment.entity';
|
||||
|
||||
@@ -59,6 +59,9 @@ export class Application {
|
||||
@Column({ nullable: true })
|
||||
codePath: string; // Path to uploaded zip
|
||||
|
||||
@Column({ nullable: true })
|
||||
dbDumpPath: string; // Path to uploaded SQL dump file
|
||||
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
envVars: Record<string, string>;
|
||||
|
||||
@@ -105,6 +108,25 @@ export class Application {
|
||||
@Column({ nullable: true })
|
||||
subdomain: string; // <subdomain>.apps.cloudhost.local
|
||||
|
||||
// ── Billing & Lifecycle ─────────────────────────────
|
||||
@Column({ nullable: true })
|
||||
planId: string; // FK to ServicePlan
|
||||
|
||||
@Column({ type: 'enum', enum: BillingCycle, nullable: true })
|
||||
billingCycle: BillingCycle; // The cycle this app was purchased under
|
||||
|
||||
@Column({ type: 'enum', enum: AppLifecycleStatus, default: AppLifecycleStatus.ACTIVE })
|
||||
lifecycleStatus: AppLifecycleStatus;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
planExpiresAt: Date; // When the current billing period ends
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
suspendedAt: Date; // When the app was suspended (pods scaled to 0)
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
scheduledDeletionAt: Date; // When the app will be permanently deleted
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user