/** * Contracts: MSA, DPA, SLA, order forms, capacity commitments. * * Two things about this market shape the design. * * First, contracts are not a closing formality on the demand side — legal sits * early in the pipeline, because a customer will not hand workloads to an * infrastructure provider before paper is in place. * * Second, and less obviously: **service levels are promised differently on each * side of the business**. A compute aggregator generally cannot offer a * conventional uptime guarantee on capacity it resells and does not control, * and says so publicly. What it offers self-serve customers instead is a * reliability tier plus a service-credits policy. Yet the same company * negotiates heavyweight SLAs upstream with providers, and bespoke ones * downstream with enterprise customers on dedicated clusters. * * All three shapes therefore coexist, and the schema holds them without * pretending any one is the others. See `slaKind` below. */ import { boolean, index, integer, jsonb, numeric, pgTable, text, timestamp, uuid, } from 'drizzle-orm/pg-core'; import { contractStatusEnum, contractTypeEnum, slaKindEnum, slaMetricEnum, } from './enums'; import { accounts } from './crm'; import { demandDeals } from './demand'; import { capacityCommitments, supplyDeals } from './supply'; import { users } from './identity'; export const contracts = pgTable( 'contracts', { id: uuid('id').primaryKey().defaultRandom(), accountId: uuid('account_id') .notNull() .references(() => accounts.id, { onDelete: 'cascade' }), type: contractTypeEnum('type').notNull(), status: contractStatusEnum('status').notNull().default('draft'), /** * Which side of the market this paper governs. The same account can hold * both — we may buy capacity from a neocloud under one MSA while selling * them managed training under another. */ side: text('side').notNull().default('demand'), title: text('title').notNull(), /** Counterparty's own reference, for reconciliation with their systems. */ externalReference: text('external_reference'), /** Optional links to whatever this contract is about. */ demandDealId: uuid('demand_deal_id').references(() => demandDeals.id, { onDelete: 'set null', }), supplyDealId: uuid('supply_deal_id').references(() => supplyDeals.id, { onDelete: 'set null', }), capacityCommitmentId: uuid('capacity_commitment_id').references( () => capacityCommitments.id, { onDelete: 'set null' }, ), /** * An order form or SLA usually hangs beneath a master agreement. Modelling * that hierarchy means "which MSA governs this order form?" is answerable, * which is the first question asked in any dispute. * * Note the order of precedence in real master agreements: **the order form * beats the MSA**, then exhibits and addenda, then the body of the * agreement, then documentation. So an order-form-level override is not an * annotation on the master terms — it supersedes them, and must be stored * as data rather than left in a notes field. */ parentContractId: uuid('parent_contract_id'), /** * The signing entity, where it differs from the account. * * Affiliates routinely execute their own order forms under a parent's * master agreement, binding themselves as if an original party. Assuming * one contract equals one legal entity misfiles the counterparty on * exactly the deals large enough to matter. */ contractingPartyName: text('contracting_party_name'), /** * Take-or-pay and prepayment terms. Together with `terminationTier` below * these are what make a backlog figure meaningful: contracted revenue * under a prepaid take-or-pay commitment and contracted revenue cancellable * on ninety days' notice are not the same asset, and summing them * unweighted overstates the book. */ takeOrPayFloorPct: numeric('take_or_pay_floor_pct', { precision: 6, scale: 2 }), prepaidPct: numeric('prepaid_pct', { precision: 6, scale: 2 }), /** * `1_prepaid` Take-or-pay with prepayment — the highest quality * `2_take_or_pay` Multi-year take-or-pay, no prepayment * `3_cancellable` Monthly billing with a short termination right */ terminationTier: text('termination_tier'), /** * Whether this contract may be assigned to a substitute operator on * default, and within how long. A negotiated step-in right can require * assignment of the customer agreement *and the underlying datacentre * agreement* within days — which only works if the link between the two * exists in a system somewhere. That link is `capacityCommitmentId` above. */ assignableOnDefault: boolean('assignable_on_default').notNull().default(false), assignmentDeadlineBusinessDays: integer('assignment_deadline_business_days'), effectiveAt: timestamp('effective_at', { withTimezone: true }), expiresAt: timestamp('expires_at', { withTimezone: true }), executedAt: timestamp('executed_at', { withTimezone: true }), terminatedAt: timestamp('terminated_at', { withTimezone: true }), isAutoRenew: boolean('is_auto_renew').notNull().default(false), /** Days of notice to prevent auto-renewal. Drives the renewal alarm. */ noticeDays: integer('notice_days'), valueCents: integer('value_cents'), currency: text('currency').notNull().default('USD'), governingLaw: text('governing_law'), /** Link to the executed document. PIG stores the pointer, not the paper. */ documentUrl: text('document_url'), ownerUserId: uuid('owner_user_id').references(() => users.id, { onDelete: 'set null' }), notes: text('notes'), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }, (t) => [ index('contracts_account_idx').on(t.accountId), index('contracts_type_idx').on(t.type), index('contracts_status_idx').on(t.status), index('contracts_expiry_idx').on(t.expiresAt), index('contracts_demand_deal_idx').on(t.demandDealId), ], ); /** * The service-level terms attached to a contract. * * `slaKind` is the important column: * * `none` Self-serve. No service commitment whatsoever. * `credits_policy` The common case for resold capacity — a reliability tier * plus service credits when a provider fails. Not an uptime * guarantee, and must not be displayed as one. * `negotiated` A real signed SLA with committed, measurable metrics. * * Recording a credits policy as though it were a negotiated SLA would let a * seller promise a customer something the business has not agreed to underwrite. */ export const slaTerms = pgTable( 'sla_terms', { id: uuid('id').primaryKey().defaultRandom(), contractId: uuid('contract_id') .notNull() .references(() => contracts.id, { onDelete: 'cascade' }), kind: slaKindEnum('kind').notNull().default('credits_policy'), /** Committed uptime, where one is genuinely committed. */ uptimeTargetPct: numeric('uptime_target_pct', { precision: 6, scale: 3 }), /** Hours to replace a failed node — often more negotiated than uptime. */ nodeReplacementHours: integer('node_replacement_hours'), mttrHours: integer('mttr_hours'), supportResponseHours: integer('support_response_hours'), /** 'monthly' | 'quarterly' — the window uptime is measured over. */ measurementWindow: text('measurement_window').notNull().default('monthly'), /** * What the target is measured against: `region`, `instance`, `node`, * `rack`, `cluster`, `endpoint`. * * Rack-scale systems are commonly sold with TWO simultaneous levels — for * example 99% per node alongside 95% per rack, where a rack counts as * healthy at 16 of 18 nodes. Recording only one of them misstates what was * promised, so additional levels go in `slaMetricTargets` and this column * names the basis of the headline figure. */ measurementUnit: text('measurement_unit').notNull().default('cluster'), /** * The remedy actually available. This is the field that matters most, and * the one a credits-only model gets wrong. * * `service_credit` A capped percentage of fees, claimed within a window * `fee_abatement` Payment obligations CANCELLED for the affected * capacity until service is restored — uncapped in * duration, and far more valuable than a credit * `termination_right` The customer may exit * * Fee abatement is real and negotiated: a leading provider's filed master * agreement cancels fees for services not performed once a hardware * failure persists two consecutive business days, and does not resume them * until the failure is resolved. */ remedyType: text('remedy_type').notNull().default('service_credit'), /** Consecutive duration triggering abatement, and its unit. */ abatementTriggerValue: integer('abatement_trigger_value'), abatementTriggerUnit: text('abatement_trigger_unit'), /** * Deadline to file a claim, and its unit — observed across the market from * ten days to two billing cycles. Miss it and the credit is simply * forfeit, which makes this an operational alarm, not a footnote. */ claimDeadlineValue: integer('claim_deadline_value'), claimDeadlineUnit: text('claim_deadline_unit').notNull().default('days'), /** Credits commonly expire if unused. */ creditExpiryMonths: integer('credit_expiry_months'), /** Whether credits are the sole and exclusive remedy. Usually yes. */ isSoleRemedy: boolean('is_sole_remedy').notNull().default(true), /** * Contractual spare-pool obligation — that the provider keeps enough * spares on hand to replace what cannot be remediated. Observed scoped to * **both compute nodes and network switches, per location**; switches are * routinely forgotten and are just as capable of stranding a cluster. */ sparePoolObligation: text('spare_pool_obligation'), sparePoolScope: jsonb('spare_pool_scope').$type().notNull().default([]), /** * Maintenance classes and their notice periods — planned, planned-critical * and emergency are typically distinct, with different notice and * different treatment in the uptime calculation. Some allowance of * maintenance hours is normally excluded from the measurement entirely. */ maintenanceClasses: jsonb('maintenance_classes') .$type< { class: string; noticeValue: number; noticeUnit: string; allowancePerPeriodHours?: number; excludedFromUptime: boolean; }[] >() .notNull() .default([]), /** * Days per year during which only "reasonable endeavours" apply and the * service levels are suspended. A real, negotiated carve-out that can span * months, and one that silently voids the guarantee being sold. */ reasonableEndeavoursDaysPerYear: integer('reasonable_endeavours_days_per_year'), /** Hours within which a root cause analysis is owed after a major incident. */ rcaDeliveryHours: integer('rca_delivery_hours'), /** * Credit schedule: bands of missed target mapped to the percentage of fees * credited back. Stored as JSON because every counterparty structures these * differently and normalising them loses the shape of the deal. */ creditSchedule: jsonb('credit_schedule') .$type<{ belowPct: number; creditPct: number }[]>() .notNull() .default([]), /** Maximum credits payable in a window, as a share of fees. */ creditCapPct: numeric('credit_cap_pct', { precision: 6, scale: 3 }), /** Carve-outs: maintenance windows, force majeure, customer-caused faults. */ exclusions: text('exclusions'), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }, (t) => [index('sla_terms_contract_idx').on(t.contractId)], ); /** An individual committed metric, where an SLA commits several. */ export const slaMetricTargets = pgTable( 'sla_metric_targets', { id: uuid('id').primaryKey().defaultRandom(), slaTermId: uuid('sla_term_id') .notNull() .references(() => slaTerms.id, { onDelete: 'cascade' }), metric: slaMetricEnum('metric').notNull(), targetValue: numeric('target_value', { precision: 12, scale: 3 }).notNull(), unit: text('unit'), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), }, (t) => [index('sla_metric_targets_term_idx').on(t.slaTermId)], ); /** * Dated obligations arising from a contract — renewal notice deadlines, * milestone deliverables, true-up dates, security reviews. * * These are what actually get missed. A contract row with an expiry date is * inert; an obligation with a due date can be alerted on, which is the point. */ export const contractObligations = pgTable( 'contract_obligations', { id: uuid('id').primaryKey().defaultRandom(), contractId: uuid('contract_id') .notNull() .references(() => contracts.id, { onDelete: 'cascade' }), title: text('title').notNull(), description: text('description'), /** 'renewal_notice' | 'milestone' | 'payment' | 'review' | 'true_up' */ kind: text('kind').notNull().default('milestone'), dueAt: timestamp('due_at', { withTimezone: true }).notNull(), completedAt: timestamp('completed_at', { withTimezone: true }), ownerUserId: uuid('owner_user_id').references(() => users.id, { onDelete: 'set null' }), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }, (t) => [ index('contract_obligations_contract_idx').on(t.contractId), index('contract_obligations_due_idx').on(t.dueAt), index('contract_obligations_owner_idx').on(t.ownerUserId), ], ); export type Contract = typeof contracts.$inferSelect; export type NewContract = typeof contracts.$inferInsert; export type SlaTerm = typeof slaTerms.$inferSelect; export type ContractObligation = typeof contractObligations.$inferSelect;