import { describe, expect, it } from 'vitest'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; const schema = readFileSync(join(process.cwd(), 'prisma/schema.prisma'), 'utf8'); const migration = readFileSync(join(process.cwd(), 'prisma/migrations/20260621090000_init_v2_schema/migration.sql'), 'utf8'); const authMigration = readFileSync(join(process.cwd(), 'prisma/migrations/20260621093000_auth_sessions/migration.sql'), 'utf8'); const numberLibraryMigration = readFileSync(join(process.cwd(), 'prisma/migrations/20260624095000_number_library/migration.sql'), 'utf8'); const businessPrefixMigration = readFileSync( join(process.cwd(), 'prisma/migrations/20260624121000_business_prefix_gateway_rewrite/migration.sql'), 'utf8' ); describe('Prisma schema contract', () => { it('defines every V2 core business table', () => { const tables = [ 'customers', 'customer_gateways', 'customer_gateway_ips', 'business_prefixes', 'customer_gateway_business_prefixes', 'customer_gateway_caller_prefixes', 'customer_gateway_policies', 'customer_recharges', 'vendors', 'vendor_recharges', 'vendor_gateways', 'vendor_gateway_blocked_regions', 'vendor_gateway_forbidden_periods', 'vendor_gateway_codecs', 'vendor_gateway_prefix_rules', 'vendor_gateway_caller_rewrite_pool', 'landing_line_groups', 'landing_line_group_items', 'geo_cities', 'phone_number_segments', 'phone_area_codes', 'carrier_prefix_rules', 'raw_cdrs', 'rated_cdrs', 'recordings', 'quality_sampling_rules', 'quality_reviews', 'users', 'roles', 'permissions', 'user_roles', 'user_sessions', 'role_permissions', 'audit_logs', 'outbox_events', 'idempotency_keys' ]; for (const table of tables) { expect(schema).toContain(`@@map("${table}")`); expect(`${migration}\n${authMigration}\n${numberLibraryMigration}\n${businessPrefixMigration}`).toContain( `CREATE TABLE \`${table}\`` ); } }); it('keeps money and idempotent facts constrained', () => { expect(migration).toContain('DECIMAL(20, 6)'); expect(migration).toContain('UNIQUE INDEX `raw_cdrs_event_id_key`'); expect(migration).toContain('UNIQUE INDEX `raw_cdrs_call_id_ended_at_key`'); expect(migration).toContain('UNIQUE INDEX `customer_recharges_idempotency_key_key`'); expect(migration).toContain('UNIQUE INDEX `vendor_recharges_idempotency_key_key`'); expect(migration).toContain('UNIQUE INDEX `idempotency_keys_key_key`'); }); it('captures number library and CDR callee attribution fields', () => { expect(schema).toContain('model GeoCity'); expect(schema).toContain('model PhoneNumberSegment'); expect(schema).toContain('model CarrierPrefixRule'); expect(numberLibraryMigration).toContain('`segment7` CHAR(7) NOT NULL'); expect(numberLibraryMigration).toContain('`callee_city_code` VARCHAR(12) NULL'); expect(numberLibraryMigration).toContain('`callee_operator` ENUM'); expect(numberLibraryMigration).toContain('CREATE INDEX `raw_cdrs_callee_operator_started_at_idx`'); }); it('models phase-2 business prefix gateway matching and landing rewrites', () => { expect(schema).toContain('model BusinessPrefix'); expect(schema).toContain('model CustomerGatewayIp'); expect(schema).toContain('model CustomerGatewayBusinessPrefix'); expect(schema).toContain('model CustomerGatewayCallerPrefix'); expect(schema).toContain('model VendorGatewayCallerRewrite'); expect(schema).toContain('enum CustomerGatewayCallerMatchMode'); expect(schema).toContain('enum CustomerGatewayCalleeMatchMode'); expect(businessPrefixMigration).toContain('`billing_cycle_sec` INTEGER NOT NULL DEFAULT 60'); expect(businessPrefixMigration).toContain('`landing_callee_prefix` VARCHAR(64) NULL'); expect(businessPrefixMigration).toContain('`raw_callee` VARCHAR(64) NULL'); expect(businessPrefixMigration).toContain('`landing_caller` VARCHAR(64) NULL'); expect(businessPrefixMigration).toContain('CREATE INDEX `raw_cdrs_business_prefix_id_started_at_idx`'); }); it('models audit columns and outbox publishing state', () => { expect(schema).toContain('createdAt'); expect(schema).toContain('updatedAt'); expect(schema).toContain('version'); expect(schema).toContain('model OutboxEvent'); expect(schema).toContain('enum OutboxStatus'); }); it('stores refresh sessions as revocable token digests', () => { expect(schema).toContain('model UserSession'); expect(authMigration).toContain('`refresh_token_hash` CHAR(64) NOT NULL'); expect(authMigration).toContain('UNIQUE INDEX `user_sessions_refresh_token_hash_key`'); expect(authMigration).toContain('`revoked_at` DATETIME(3) NULL'); expect(authMigration).toContain('`rotated_from_id` VARCHAR(40) NULL'); }); });