feat: Add billing and feature-flags entities

- Added plan-feature entity for billing
- Added flag-evaluation entity for feature flags
- Updated module configurations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rckrdmrd 2026-01-16 12:13:18 -06:00
parent ca07b4268d
commit e846b715c1
6 changed files with 119 additions and 2 deletions

View File

@ -53,6 +53,7 @@ export class BillingUsageModule {
require('./entities/usage-tracking.entity').UsageTracking, require('./entities/usage-tracking.entity').UsageTracking,
require('./entities/invoice.entity').Invoice, require('./entities/invoice.entity').Invoice,
require('./entities/invoice-item.entity').InvoiceItem, require('./entities/invoice-item.entity').InvoiceItem,
require('./entities/plan-feature.entity').PlanFeature,
]; ];
} }
} }

View File

@ -6,3 +6,4 @@ export { Invoice, InvoiceStatus } from './invoice.entity';
export { InvoiceItem, InvoiceItemType } from './invoice-item.entity'; export { InvoiceItem, InvoiceItemType } from './invoice-item.entity';
export { BillingPaymentMethod, PaymentProvider, PaymentMethodType } from './payment-method.entity'; export { BillingPaymentMethod, PaymentProvider, PaymentMethodType } from './payment-method.entity';
export { BillingAlert, BillingAlertType, AlertSeverity, AlertStatus } from './billing-alert.entity'; export { BillingAlert, BillingAlertType, AlertSeverity, AlertStatus } from './billing-alert.entity';
export { PlanFeature } from './plan-feature.entity';

View File

@ -0,0 +1,61 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
Index,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { SubscriptionPlan } from './subscription-plan.entity.js';
/**
* PlanFeature Entity
* Maps to billing.plan_features DDL table
* Features disponibles por plan de suscripcion
* Propagated from template-saas HU-REFACT-005
*/
@Entity({ schema: 'billing', name: 'plan_features' })
@Index('idx_plan_features_plan', ['planId'])
@Index('idx_plan_features_key', ['featureKey'])
export class PlanFeature {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'uuid', nullable: false, name: 'plan_id' })
planId: string;
@Column({ type: 'varchar', length: 100, nullable: false, name: 'feature_key' })
featureKey: string;
@Column({ type: 'varchar', length: 255, nullable: false, name: 'feature_name' })
featureName: string;
@Column({ type: 'varchar', length: 100, nullable: true })
category: string | null;
@Column({ type: 'boolean', default: true })
enabled: boolean;
@Column({ type: 'jsonb', default: {} })
configuration: Record<string, any>;
@Column({ type: 'text', nullable: true })
description: string | null;
@Column({ type: 'jsonb', default: {} })
metadata: Record<string, any>;
// Relaciones
@ManyToOne(() => SubscriptionPlan, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'plan_id' })
plan: SubscriptionPlan;
// Timestamps
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
updatedAt: Date;
}

View File

@ -0,0 +1,53 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
Index,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { Flag } from './flag.entity.js';
/**
* FlagEvaluation Entity
* Maps to flags.flag_evaluations DDL table
* Historial de evaluaciones de feature flags para analytics
* Propagated from template-saas HU-REFACT-005
*/
@Entity({ schema: 'flags', name: 'flag_evaluations' })
@Index('idx_flag_evaluations_flag', ['flagId'])
@Index('idx_flag_evaluations_tenant', ['tenantId'])
@Index('idx_flag_evaluations_date', ['evaluatedAt'])
export class FlagEvaluation {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'uuid', nullable: false, name: 'flag_id' })
flagId: string;
@Column({ type: 'uuid', nullable: false, name: 'tenant_id' })
tenantId: string;
@Column({ type: 'uuid', nullable: true, name: 'user_id' })
userId: string | null;
@Column({ type: 'boolean', nullable: false })
result: boolean;
@Column({ type: 'varchar', length: 100, nullable: true })
variant: string | null;
@Column({ type: 'jsonb', default: {}, name: 'evaluation_context' })
evaluationContext: Record<string, any>;
@Column({ type: 'varchar', length: 100, nullable: true, name: 'evaluation_reason' })
evaluationReason: string | null;
@Column({ type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP', name: 'evaluated_at' })
evaluatedAt: Date;
// Relaciones
@ManyToOne(() => Flag, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'flag_id' })
flag: Flag;
}

View File

@ -1,2 +1,3 @@
export { Flag } from './flag.entity'; export { Flag } from './flag.entity';
export { TenantOverride } from './tenant-override.entity'; export { TenantOverride } from './tenant-override.entity';
export { FlagEvaluation } from './flag-evaluation.entity';

View File

@ -2,7 +2,7 @@ import { Router } from 'express';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import { FeatureFlagsService } from './services'; import { FeatureFlagsService } from './services';
import { FeatureFlagsController } from './controllers'; import { FeatureFlagsController } from './controllers';
import { Flag, TenantOverride } from './entities'; import { Flag, TenantOverride, FlagEvaluation } from './entities';
export interface FeatureFlagsModuleOptions { export interface FeatureFlagsModuleOptions {
dataSource: DataSource; dataSource: DataSource;
@ -39,6 +39,6 @@ export class FeatureFlagsModule {
} }
static getEntities(): Function[] { static getEntities(): Function[] {
return [Flag, TenantOverride]; return [Flag, TenantOverride, FlagEvaluation];
} }
} }