Skip to main content

Enterprise Plan — Full Design & Backend Requirements

Phase Status:

  • Phase 1 (CURRENT): Simple request → admin approve/reject → POSTPAID with unlimited access → monthly Stripe invoicing. See ENTERPRISE_PLAN_BACKEND.md for what's actually implemented.
  • Phase 2 (FUTURE): Questionnaire, custom limits, proposals, contract signing. Everything below is the Phase 2 design — the backend does NOT support these entities yet.

Overview (Phase 2 Vision)

When a user selects the Enterprise plan, instead of an instant checkout, they go through a questionnaire-based request flow. The questionnaire collects their desired feature limits, organization details, and billing preferences. The request lands in the Super Admin panel for verification, custom pricing, and approval. Once the admin sends a proposal and the customer accepts, a contract is generated and must be signed by both parties before the subscription activates. The enterprise customer then operates on a POSTPAID billing model with invoiced billing.


1. User-Facing Flow

1.1 Entry Point (Existing — Modified)

Where: PlansTab.tsx enterprise card → "Request Access" button

Current behavior: Calls REQUEST_ENTERPRISE_SUBSCRIPTION with just { planId, companyId } and shows "Pending Approval".

New behavior: Instead of immediately submitting, opens a multi-step Enterprise Request Modal that collects questionnaire data before submitting.

1.2 Enterprise Request Modal — Steps

Step 1: Organization Details

FieldTypeRequiredNotes
Organization Legal NametextYesMust match official registration
Organization NumbertextYesBusiness registration / VAT / EIN number
CountryselectYesDropdown with country list
IndustryselectYesPre-defined industry list
Company SizeselectYes1-10, 11-50, 51-200, 201-500, 500+
WebsiteurlNoCompany website for verification
Billing EmailemailYesWhere invoices will be sent (pre-filled from user email)
Billing AddresstextareaYesFull billing address for invoices
VAT NumbertextNoFor EU VAT handling

Step 2: Feature Requirements (The Questionnaire)

Each feature limit from the plan model is presented as a choice. The user picks either a specific limit or Unlimited for each category.

Layout: Grouped by the existing FEATURE_CATEGORIES (Workspace, Team & Outreach, Hiring, Talent CRM, AI & Content).

For each feature:

  • Radio/toggle: Standard (show the Pro plan default) | Custom (number input) | Unlimited
  • When "Custom" is selected, a number input appears
FeatureDefault (Pro baseline)Custom InputUnlimited
Companies1numbercheckbox
Team Members10numbercheckbox
Collaboration Invitesnumbercheckbox
Connections / monumbercheckbox
Jobsnumbercheckbox
Pipelinesnumbercheckbox
Interviews / monumbercheckbox
Meetings / monumbercheckbox
Talent Poolsnumbercheckbox
Contactsnumbercheckbox
Contact Notesnumbercheckbox
CV Collectionsnumbercheckbox
Shared Listsnumbercheckbox
CV Parses / monumbercheckbox
AI Messages / monumbercheckbox
Text Rewrites / monumbercheckbox
News Posts / monumbercheckbox
Monthly Creditsnumbercheckbox

Step 3: Billing Preferences

FieldTypeRequiredNotes
Billing CycleselectYesMonthly / Quarterly / Annually
Payment Method PreferenceselectYesInvoice (bank transfer) / Credit Card / Direct Debit
Estimated Monthly BudgetselectNo< $500 / $500-2000 / $2000-5000 / $5000+ / Prefer not to say
Purchase Order RequiredtoggleNoWhether they need PO numbers on invoices
PO NumbertextIf PO requiredTheir purchase order number
Additional NotestextareaNoFree-form for special requirements

Step 4: Review & Submit

  • Summary of all entered information across all steps
  • Organization details summary
  • Feature requirements table showing their selections
  • Billing preferences summary
  • Terms acceptance checkbox: "I confirm the organization details are accurate and I'm authorized to make this request"
  • Submit Request button

1.3 Post-Submission State

After submission:

  • Toast: "Enterprise request submitted. We'll review your application and get back within 2 business days."
  • Plan card shows "Pending Approval" badge (existing behavior)
  • User can see their request status in a new Enterprise Request Status section on the billing page
  • Status progression: SUBMITTEDUNDER_REVIEWPROPOSAL_SENTCONTRACT_PENDINGCONTRACT_SIGNEDACTIVE / REJECTED

1.4 Enterprise Request Status View (New Component)

When the user has a pending enterprise request, show a status tracker above the plan cards:

┌──────────────────────────────────────────────────────────────────────────┐
│ Enterprise Plan Request │
│ │
│ ● Submitted → ○ Under Review → ○ Proposal → ○ Contract → ○ Active │
│ │
│ Status: Submitted on Apr 20, 2026 │
│ Organization: Acme Corp (NO-123456789) │
│ │
│ [View Details] [Cancel Request] │
│ │
│ ─── Admin Response (when available) ─── │
│ Custom pricing proposal: $X,XXX/mo │
│ [Accept Proposal] [Request Changes] │
│ │
│ ─── Contract (when proposal accepted) ─── │
│ Enterprise Service Agreement — generated Apr 22, 2026 │
│ Status: Awaiting your signature │
│ [View Contract] [Sign Contract] │
└──────────────────────────────────────────────────────────────────────────┘

1.5 Proposal Acceptance Flow

When admin sends a pricing proposal:

  1. User receives email notification with proposal summary
  2. In-app: the status tracker updates to "Proposal Sent"
  3. Shows the proposed pricing, custom limits, and contract terms
  4. User can Accept Proposal or Request Changes (sends message back to admin)
  5. Accepting the proposal does NOT activate the subscription yet — it triggers contract generation

1.6 Contract Signing Flow

After the user accepts a proposal, a contract must be signed before the subscription activates.

1.6.1 Contract Generation

When the user accepts a proposal (or admin approves directly), the backend generates a contract PDF containing:

  • Parties: AiQlick (provider) and the customer organization (legal name, org number, address)
  • Service Description: Enterprise plan with all approved feature limits listed
  • Pricing Terms: Base fee, credit rate, billing cycle, minimum spend, discounts
  • Contract Duration: Start date, end date (based on contractTermMonths), renewal terms
  • Payment Terms: Net 30 (or custom), payment method, invoicing schedule
  • Service Level Agreement (SLA): Uptime guarantees, support response times
  • Data Processing: GDPR/data handling terms, data residency
  • Termination Clause: Notice period, early termination fees (if any)
  • Liability & Indemnification: Standard liability caps
  • Signatures: Digital signature fields for both parties

1.6.2 Signing Process

Step 1 — Customer Signs:

  1. Status changes to CONTRACT_PENDING
  2. Customer receives email: "Your enterprise contract is ready for signing"
  3. In-app: status tracker shows "Contract" step as active
  4. Customer clicks [View Contract] to preview the full PDF
  5. Customer clicks [Sign Contract] which opens a signing modal:
    • Displays contract summary (key terms at a glance)
    • Full contract PDF viewer (scrollable)
    • Signatory Details form:
      • Full Name (of the authorized signer)
      • Job Title
      • Email (of the signer, may differ from billing email)
    • Signature capture: Type name (rendered as signature font) OR draw signature on canvas OR upload signature image
    • Checkbox: "I am authorized to sign this agreement on behalf of [Organization Legal Name]"
    • Checkbox: "I have read and agree to the terms of this Enterprise Service Agreement"
    • [Sign & Submit] button
  6. On signing: signature + timestamp + IP address are embedded into the contract PDF
  7. Status changes to CUSTOMER_SIGNED (waiting for AiQlick countersignature)

Step 2 — Admin Countersigns:

  1. Admin receives notification: "[Company] has signed the enterprise contract"
  2. In admin Enterprise Request Detail → new Contract Tab:
    • View signed contract PDF with customer's signature
    • Review signatory details
    • [Countersign & Activate] button (or [Countersign] if manual activation preferred)
  3. Admin countersigns (using their admin credentials as the AiQlick representative)
  4. Final signed contract PDF is generated with both signatures
  5. Status changes to CONTRACT_SIGNED → subscription activates → status becomes ACTIVE

Step 3 — Post-Signing:

  1. Both parties receive the fully executed contract PDF via email
  2. Contract PDF is stored and accessible from:
    • Customer: billing page → "View Contract" link
    • Admin: enterprise request detail → Contract tab
  3. Subscription is now active with all approved limits

1.6.3 Contract Status Display (User Side)

Contract Status States:
─────────────────────────────────────────────
CONTRACT_PENDING → "Contract ready — awaiting your signature"
[View Contract] [Sign Contract]

CUSTOMER_SIGNED → "You've signed — awaiting AiQlick countersignature"
[View Signed Contract]
"Typically completed within 1 business day"

CONTRACT_SIGNED → "Contract fully executed on [date]"
[Download Contract PDF]

ACTIVE → "Enterprise plan active since [date]"
[View Contract] [View Invoices]

1.6.4 Direct Approval Path (Trusted Orgs)

When admin uses "Approve Directly" for trusted/known organizations:

  1. Contract is still generated with the approved terms
  2. Admin can pre-sign (countersign first)
  3. Customer receives a pre-signed contract that only needs their signature
  4. Once customer signs → subscription activates immediately (no second admin step)

2. Super Admin Panel Flow

2.1 Enhanced Enterprise Tab

The existing EnterpriseTab.tsx needs significant enhancement.

2.1.1 Enterprise Request Queue

Replace the simple table with a request detail view:

List View columns:

ColumnContent
CompanyOrganization name + logo
RequesterUser name + email
Org NumberBusiness registration number
StatusChip: SUBMITTED / UNDER_REVIEW / PROPOSAL_SENT / APPROVED / REJECTED
SubmittedDate
Estimated ValueBudget range from questionnaire
ActionsReview / Quick Actions dropdown

Filters: Status, date range, company size, industry

2.1.2 Enterprise Request Detail Modal

When admin clicks "Review" on a request:

Tab 1: Organization Verification

SectionContentAdmin Action
Company DetailsLegal name, org number, country, industry, size, website
Verification StatusPending / Verified / FailedMark as Verified / Flag Issue
Org Number CheckDisplay org number with "Verify" buttonOpens external registry lookup (link to country-specific business registry)
Email VerificationBilling email, domain match checkSend verification email
Website CheckCompany website screenshot/statusLink to open website
Existing AccountShow if company already exists in system, their current plan, usage history
Risk AssessmentAuto-calculated: new company, email domain match, org number format validationLow / Medium / High risk badge

Tab 2: Requested Features

Display the questionnaire responses in a table:

FeatureRequestedPro LimitRecommendationOverride
CompaniesUnlimited110[input]
Team Members501050[input]
JobsUnlimited-1[input]
...............

Admin can override each limit before sending the proposal.

Tab 3: Pricing & Proposal

FieldDescription
Base PriceMonthly base price in cents (auto-suggested based on feature selections)
Credit RatePrice per credit (default from billing config, can override)
Billing CycleMonthly / Quarterly / Annually (from customer preference)
Contract TermMonth-to-month / 6 months / 12 months / 24 months
Minimum SpendOptional monthly minimum
Discount %Volume discount percentage
Setup FeeOne-time setup fee (optional)
Custom NotesFree-form notes visible to customer in the proposal
Internal NotesAdmin-only notes (not visible to customer)

Actions:

  • Send Proposal — Generates a proposal with the pricing and sends notification to customer
  • Approve Directly — Skip proposal, activate immediately (for known/trusted customers)
  • Reject — With reason (sent to customer via email)
  • Request More Info — Send message to customer asking for additional details

Tab 4: Contract Management

SectionContentAdmin Action
Contract StatusCurrent state: Draft / Pending Customer Signature / Customer Signed / Fully ExecutedStatus chip
Contract PDFPreview of the generated/signed contract[View PDF] [Download]
Signatory InfoCustomer signer: name, title, email, signed at, IP addressRead-only
AiQlick SignerAdmin who will countersignAuto-filled from logged-in admin
CountersignAvailable when customer has signed[Countersign & Activate] button
Pre-signFor direct approval path — admin signs first[Pre-sign Contract] button
Contract HistoryAudit log: generated, sent, viewed, signed datesTimeline view
RegenerateIf terms change before signing[Regenerate Contract] (invalidates previous)
Contract TemplateSelect template variant (standard / custom)Dropdown

Tab 5: Billing & Invoicing

SectionContent
Payment MethodInvoice / Card / Direct Debit — set by admin
Billing ContactEmail, name, address (from questionnaire)
Invoice HistoryList of all invoices for this enterprise account
Generate InvoiceDate range picker → calculate usage → generate
Bank DetailsAiQlick's bank details to include on invoices
Outstanding BalanceTotal unpaid amount

2.1.3 Enterprise Dashboard Widgets (Revenue Stats Tab)

Add to existing Revenue Statistics:

WidgetContent
Pending RequestsCount of SUBMITTED + UNDER_REVIEW requests
Active EnterpriseCount of active enterprise subscriptions
Enterprise MRRMonthly recurring revenue from enterprise accounts
Avg Enterprise ValueAverage monthly spend per enterprise customer
Outstanding InvoicesTotal unpaid enterprise invoice amount
Overdue InvoicesCount + amount of past-due invoices

3. Data Model Changes

3.1 New: EnterpriseRequest Entity

EnterpriseRequest {
id: UUID (PK)
userId: UUID (FK → User)
companyId: UUID (FK → Company, nullable)
subscriptionId: UUID (FK → Subscription, nullable, set after approval)

// Status
status: SUBMITTED | UNDER_REVIEW | PROPOSAL_SENT | CONTRACT_PENDING | CUSTOMER_SIGNED | CONTRACT_SIGNED | APPROVED | REJECTED | CANCELLED

// Organization Details (Step 1)
organizationLegalName: String
organizationNumber: String
country: String
industry: String
companySize: String (enum: "1-10" | "11-50" | "51-200" | "201-500" | "500+")
website: String (nullable)
billingEmail: String
billingAddress: String (JSON or text)
vatNumber: String (nullable)

// Feature Requirements (Step 2) — stored as JSON
requestedLimits: JSON {
maxCompanies: number | -1 (unlimited)
maxUsersPerCompany: number | -1
maxJobs: number | -1
maxContacts: number | -1
maxPipelines: number | -1
maxTalentPools: number | -1
maxInterviewsPerMonth: number | -1
maxMeetingsPerMonth: number | -1
maxCvCollections: number | -1
maxSharedTalentLists: number | -1
maxCollaborationInvites: number | -1
maxConnectionRequestsPerMonth: number | -1
maxNewsPerMonth: number | -1
maxContactNotes: number | -1
maxCvParsesPerMonth: number | -1
maxAgentMessagesPerMonth: number | -1
maxTextRewritesPerMonth: number | -1
creditsPerMonth: number | -1
}

// Billing Preferences (Step 3)
billingCycle: MONTHLY | QUARTERLY | ANNUALLY
paymentMethodPreference: INVOICE | CREDIT_CARD | DIRECT_DEBIT
estimatedBudget: String (nullable)
purchaseOrderRequired: Boolean (default false)
purchaseOrderNumber: String (nullable)
additionalNotes: String (nullable)

// Admin Fields
reviewedBy: UUID (FK → User, nullable)
reviewedAt: DateTime (nullable)
rejectionReason: String (nullable)
internalNotes: String (nullable)

// Verification
orgVerified: Boolean (default false)
orgVerifiedBy: UUID (FK → User, nullable)
orgVerifiedAt: DateTime (nullable)
emailVerified: Boolean (default false)
riskLevel: LOW | MEDIUM | HIGH (nullable, auto-calculated)

// Timestamps
createdAt: DateTime
updatedAt: DateTime
}

3.2 New: EnterpriseProposal Entity

EnterpriseProposal {
id: UUID (PK)
enterpriseRequestId: UUID (FK → EnterpriseRequest)

// Pricing
basePrice: Int (in cents, monthly)
creditRate: Float (price per credit, nullable)
billingCycle: MONTHLY | QUARTERLY | ANNUALLY
contractTermMonths: Int (0 = month-to-month)
minimumSpend: Int (cents, nullable)
discountPercent: Float (nullable)
setupFee: Int (cents, nullable)
currency: String (default "USD")

// Approved Limits (admin may adjust from requested)
approvedLimits: JSON (same structure as requestedLimits)

// Communication
proposalNotes: String (nullable, visible to customer)
internalNotes: String (nullable, admin-only)

// Status
status: DRAFT | SENT | ACCEPTED | DECLINED | EXPIRED
sentAt: DateTime (nullable)
respondedAt: DateTime (nullable)
expiresAt: DateTime (nullable, e.g., 30 days after sent)

// Timestamps
createdAt: DateTime
updatedAt: DateTime
}

3.3 New: EnterpriseContract Entity

EnterpriseContract {
id: UUID (PK)
enterpriseRequestId: UUID (FK → EnterpriseRequest)
proposalId: UUID (FK → EnterpriseProposal)

// Contract Document
contractPdfUrl: String (nullable, S3 path — unsigned draft)
signedPdfUrl: String (nullable, S3 path — fully executed version)
templateId: String (nullable, if using contract template variants)
version: Int (default 1, incremented on regeneration)

// Contract Terms (snapshot from proposal at generation time)
terms: JSON {
parties: {
provider: { name, address, orgNumber, representative }
customer: { name, address, orgNumber, representative }
}
service: {
planName: String
featureLimits: JSON (approved limits)
billingCycle: String
basePrice: Int (cents)
creditRate: Float
minimumSpend: Int (cents, nullable)
discountPercent: Float (nullable)
setupFee: Int (cents, nullable)
currency: String
}
duration: {
startDate: DateTime
endDate: DateTime (nullable for month-to-month)
contractTermMonths: Int
autoRenew: Boolean (default true)
renewalNoticeDays: Int (default 30)
}
payment: {
paymentTermDays: Int (default 30, i.e., Net 30)
paymentMethod: String
purchaseOrderNumber: String (nullable)
}
termination: {
noticePeriodDays: Int (default 30)
earlyTerminationFee: Int (cents, nullable)
}
}

// Customer Signature
customerSignedAt: DateTime (nullable)
customerSignerName: String (nullable)
customerSignerTitle: String (nullable)
customerSignerEmail: String (nullable)
customerSignatureData: String (nullable, base64 encoded signature image or typed name)
customerSignatureMethod: TYPED | DRAWN | UPLOADED (nullable)
customerSignerIp: String (nullable)

// AiQlick Countersignature
adminSignedAt: DateTime (nullable)
adminSignerId: UUID (FK → User, nullable)
adminSignerName: String (nullable)
adminSignerTitle: String (nullable)
adminSignatureData: String (nullable)

// Status
status: DRAFT | SENT | CUSTOMER_SIGNED | FULLY_EXECUTED | EXPIRED | VOIDED
sentAt: DateTime (nullable)
expiresAt: DateTime (nullable, e.g., 14 days after sent)

// Audit
viewedByCustomerAt: DateTime (nullable)

// Timestamps
createdAt: DateTime
updatedAt: DateTime
}

3.4 Subscription Extension

Add to existing Subscription model:

Subscription (existing) {
...existing fields...

// New enterprise fields
enterpriseRequestId: UUID (FK → EnterpriseRequest, nullable)
contractId: UUID (FK → EnterpriseContract, nullable)
billingCycle: MONTHLY | QUARTERLY | ANNUALLY (nullable, for enterprise invoicing schedule)
contractTermMonths: Int (nullable)
contractStartDate: DateTime (nullable)
contractEndDate: DateTime (nullable)
basePrice: Int (nullable, cents — custom enterprise pricing)
creditRate: Float (nullable)
minimumSpend: Int (nullable, cents)
discountPercent: Float (nullable)
purchaseOrderNumber: String (nullable)
billingEmail: String (nullable)
billingAddress: String (nullable, JSON)
}

3.4 Invoice Extension

Add to existing Invoice model:

Invoice (existing) {
...existing fields...

// New fields
purchaseOrderNumber: String (nullable)
billingAddress: String (nullable, JSON)
vatNumber: String (nullable)
billingEmail: String (nullable, override for where to send)
lineItems: JSON (nullable) {
// Detailed breakdown
items: [{
description: String,
quantity: number,
unitPrice: number (cents),
total: number (cents)
}]
}
notes: String (nullable, shown on invoice)
dueInDays: Int (default 30)
sentAt: DateTime (nullable)
paidAt: DateTime (nullable)
paymentMethod: String (nullable, "bank_transfer" | "card" | "direct_debit")
bankReference: String (nullable, for bank transfer tracking)
}

4. Backend API Requirements

4.1 New GraphQL Types

enum EnterpriseRequestStatus {
SUBMITTED
UNDER_REVIEW
PROPOSAL_SENT
CONTRACT_PENDING # Proposal accepted, contract generated, awaiting customer signature
CUSTOMER_SIGNED # Customer signed, awaiting admin countersignature
CONTRACT_SIGNED # Both parties signed — subscription activates
APPROVED # Legacy / direct-approval shorthand (contract fully executed)
REJECTED
CANCELLED
}

enum ProposalStatus {
DRAFT
SENT
ACCEPTED # Triggers contract generation
DECLINED
EXPIRED
}

enum ContractStatus {
DRAFT # Generated but not yet sent
SENT # Sent to customer for signing
CUSTOMER_SIGNED # Customer signed, awaiting countersignature
FULLY_EXECUTED # Both parties signed
EXPIRED # Customer didn't sign within expiry window
VOIDED # Invalidated (e.g., terms changed, contract regenerated)
}

enum SignatureMethod {
TYPED # Name typed and rendered in signature font
DRAWN # Drawn on canvas
UPLOADED # Uploaded signature image
}

enum BillingCycle {
MONTHLY
QUARTERLY
ANNUALLY
}

enum PaymentMethodPreference {
INVOICE
CREDIT_CARD
DIRECT_DEBIT
}

enum RiskLevel {
LOW
MEDIUM
HIGH
}

type EnterpriseRequest {
id: ID!
userId: ID!
companyId: ID
subscriptionId: ID
status: EnterpriseRequestStatus!

# Organization
organizationLegalName: String!
organizationNumber: String!
country: String!
industry: String!
companySize: String!
website: String
billingEmail: String!
billingAddress: String!
vatNumber: String

# Feature requirements
requestedLimits: JSON!

# Billing prefs
billingCycle: BillingCycle!
paymentMethodPreference: PaymentMethodPreference!
estimatedBudget: String
purchaseOrderRequired: Boolean!
purchaseOrderNumber: String
additionalNotes: String

# Verification
orgVerified: Boolean!
emailVerified: Boolean!
riskLevel: RiskLevel

# Relations
user: User
company: Company
subscription: Subscription
proposals: [EnterpriseProposal!]
activeContract: EnterpriseContract # Current active/pending contract

# Admin
reviewedBy: User
reviewedAt: DateTime
rejectionReason: String
internalNotes: String

createdAt: DateTime!
updatedAt: DateTime!
}

type EnterpriseProposal {
id: ID!
enterpriseRequestId: ID!
basePrice: Int!
creditRate: Float
billingCycle: BillingCycle!
contractTermMonths: Int!
minimumSpend: Int
discountPercent: Float
setupFee: Int
currency: String!
approvedLimits: JSON!
proposalNotes: String
status: ProposalStatus!
sentAt: DateTime
expiresAt: DateTime
respondedAt: DateTime
contract: EnterpriseContract # Generated when proposal is accepted
createdAt: DateTime!
updatedAt: DateTime!
}

type EnterpriseContract {
id: ID!
enterpriseRequestId: ID!
proposalId: ID!
status: ContractStatus!
version: Int!

# Document
contractPdfUrl: String # URL to download/view the contract PDF
signedPdfUrl: String # URL to the fully executed contract PDF
terms: JSON! # Snapshot of contract terms

# Customer signature
customerSignedAt: DateTime
customerSignerName: String
customerSignerTitle: String
customerSignerEmail: String
customerSignatureMethod: SignatureMethod

# Admin countersignature
adminSignedAt: DateTime
adminSignerName: String
adminSignerTitle: String

# Lifecycle
sentAt: DateTime
expiresAt: DateTime
viewedByCustomerAt: DateTime

createdAt: DateTime!
updatedAt: DateTime!
}

4.2 New Mutations — User-Facing

# Replace existing REQUEST_ENTERPRISE_SUBSCRIPTION
mutation SubmitEnterpriseRequest($input: SubmitEnterpriseRequestInput!): EnterpriseRequest!

input SubmitEnterpriseRequestInput {
planId: ID!
companyId: ID

# Organization (Step 1)
organizationLegalName: String!
organizationNumber: String!
country: String!
industry: String!
companySize: String!
website: String
billingEmail: String!
billingAddress: String!
vatNumber: String

# Feature requirements (Step 2)
requestedLimits: JSON!

# Billing (Step 3)
billingCycle: BillingCycle!
paymentMethodPreference: PaymentMethodPreference!
estimatedBudget: String
purchaseOrderRequired: Boolean
purchaseOrderNumber: String
additionalNotes: String
}

# User views their enterprise request
query MyEnterpriseRequest: EnterpriseRequest

# User accepts a proposal — triggers contract generation, status → CONTRACT_PENDING
mutation AcceptEnterpriseProposal($proposalId: ID!): EnterpriseRequest!

# User declines/requests changes to proposal
mutation DeclineEnterpriseProposal($proposalId: ID!, $message: String): EnterpriseRequest!

# User cancels their pending request
mutation CancelEnterpriseRequest($requestId: ID!): EnterpriseRequest!

# User views the contract PDF (marks as viewed for audit trail)
query GetEnterpriseContract($contractId: ID!): EnterpriseContract!

# User signs the contract
mutation SignEnterpriseContract($input: SignEnterpriseContractInput!): EnterpriseContract!

input SignEnterpriseContractInput {
contractId: ID!
signerName: String! # Full legal name of the person signing
signerTitle: String! # Job title (e.g., "CEO", "Head of HR")
signerEmail: String! # Email of the signer
signatureData: String! # Base64 encoded signature (typed rendering, canvas drawing, or uploaded image)
signatureMethod: SignatureMethod! # TYPED, DRAWN, or UPLOADED
agreedToTerms: Boolean! # Must be true — confirms "I have read and agree"
authorizedToSign: Boolean! # Must be true — confirms "I am authorized to sign on behalf of [org]"
}

# Download fully executed contract PDF
query GetSignedContractPdf($contractId: ID!): String! # Returns signed S3 URL

4.3 New Mutations — Admin

# List all enterprise requests with filtering
query AdminEnterpriseRequests(
$status: EnterpriseRequestStatus
$page: Int
$limit: Int
): AdminEnterpriseRequestsResult!

type AdminEnterpriseRequestsResult {
requests: [EnterpriseRequest!]!
total: Int!
}

# Get single request with full details
query AdminEnterpriseRequest($id: ID!): EnterpriseRequest!

# Update request status (e.g., SUBMITTED → UNDER_REVIEW)
mutation AdminUpdateEnterpriseRequestStatus(
$requestId: ID!
$status: EnterpriseRequestStatus!
$internalNotes: String
): EnterpriseRequest!

# Verify organization
mutation AdminVerifyOrganization(
$requestId: ID!
$verified: Boolean!
$notes: String
): EnterpriseRequest!

# Create and send a pricing proposal
mutation AdminCreateEnterpriseProposal(
$input: AdminCreateEnterpriseProposalInput!
): EnterpriseProposal!

input AdminCreateEnterpriseProposalInput {
requestId: ID!
basePrice: Int!
creditRate: Float
billingCycle: BillingCycle!
contractTermMonths: Int!
minimumSpend: Int
discountPercent: Float
setupFee: Int
currency: String
approvedLimits: JSON!
proposalNotes: String
internalNotes: String
expiresInDays: Int # default 30
sendImmediately: Boolean # default true
}

# Approve directly (skip proposal flow, for trusted orgs)
# Still generates a contract — admin pre-signs, customer only needs to sign to activate
mutation AdminApproveEnterpriseDirectly(
$input: AdminApproveEnterpriseDirectlyInput!
): EnterpriseRequest!

input AdminApproveEnterpriseDirectlyInput {
requestId: ID!
basePrice: Int!
creditRate: Float
billingCycle: BillingCycle!
contractTermMonths: Int
approvedLimits: JSON!
billingOwnerId: ID!
preSignContract: Boolean # default true — admin signs the contract upfront
}

# Admin countersigns a customer-signed contract → activates subscription
mutation AdminCountersignContract($contractId: ID!): EnterpriseContract!

# Admin pre-signs a contract (for direct approval path — customer signs second)
mutation AdminPreSignContract($contractId: ID!): EnterpriseContract!

# Regenerate contract (e.g., terms changed before signing)
# Voids the previous contract and creates a new version
mutation AdminRegenerateContract($contractId: ID!, $reason: String): EnterpriseContract!

# Void a contract (e.g., deal fell through)
mutation AdminVoidContract($contractId: ID!, $reason: String!): EnterpriseContract!

# Reject request
mutation AdminRejectEnterpriseRequest(
$requestId: ID!
$reason: String!
): EnterpriseRequest!

# Request more information from customer
mutation AdminRequestEnterpriseInfo(
$requestId: ID!
$message: String!
): EnterpriseRequest!

# Generate detailed enterprise invoice with line items
mutation AdminGenerateDetailedInvoice(
$input: AdminGenerateDetailedInvoiceInput!
): Invoice!

input AdminGenerateDetailedInvoiceInput {
companyId: ID!
subscriptionId: ID!
billingPeriodStart: DateTime!
billingPeriodEnd: DateTime!
lineItems: [InvoiceLineItemInput!]
notes: String
dueInDays: Int
purchaseOrderNumber: String
sendToEmail: String # override billing email
}

input InvoiceLineItemInput {
description: String!
quantity: Int!
unitPrice: Int! # cents
}

# Enterprise dashboard stats
query AdminEnterpriseDashboard: AdminEnterpriseDashboardStats!

type AdminEnterpriseDashboardStats {
pendingRequests: Int!
activeEnterpriseAccounts: Int!
enterpriseMRR: Int! # cents
avgEnterpriseValue: Int! # cents
outstandingInvoiceAmount: Int! # cents
overdueInvoiceCount: Int!
}

4.4 Email Notifications (Backend Must Implement)

TriggerRecipientEmail Content
Request submittedAdmin (super admins)New enterprise request from [Company], org# [X], [size] employees
Request submittedCustomerConfirmation: "We received your enterprise request. We'll review within 2 business days."
Status → UNDER_REVIEWCustomer"Your enterprise request is now being reviewed by our team."
Proposal sentCustomerProposal details: pricing, limits, contract terms, CTA to accept/decline in-app
Proposal acceptedAdmin"[Company] accepted the enterprise proposal. Contract generated — awaiting signatures."
Proposal declinedAdmin"[Company] declined the proposal. Message: [their message]"
Contract readyCustomer"Your enterprise contract is ready for signing. Please review and sign within [X] days." + PDF attachment
Contract signed by customerAdmin"[Company] has signed the enterprise contract. Please countersign to activate."
Contract countersignedCustomer"Your enterprise contract has been fully executed. Your subscription is now active." + fully signed PDF
Contract pre-signed (direct)Customer"Your pre-approved enterprise contract is ready. Sign to activate your plan immediately." + PDF
Contract expiring soonCustomer"Your enterprise contract expires in [X] days. Please sign to avoid delays." (7 days + 3 days before expiry)
Contract voidedCustomer"Your enterprise contract has been voided. Reason: [X]. A new contract will be generated if applicable."
Contract renewal reminderCustomer + Admin"Enterprise contract for [Company] expires on [date]. [X] days notice period."
Request rejectedCustomer"Your enterprise request was not approved. Reason: [X]. Contact support for questions."
More info requestedCustomer"We need additional information for your enterprise request: [admin message]"
Invoice generatedCustomer (billing email)PDF invoice attached, payment details, due date
Invoice overdueCustomer + AdminReminder: Invoice #X is overdue by [N] days
Payment receivedCustomer"Payment received for invoice #X. Thank you."

4.5 Automated Backend Jobs

JobScheduleDescription
Enterprise Invoice Generation1st of each monthFor MONTHLY billing cycle enterprise accounts: calculate usage from previous month, generate invoice
Quarterly Invoice Generation1st of Jan/Apr/Jul/OctSame for QUARTERLY accounts
Annual Invoice GenerationAnniversary dateSame for ANNUALLY accounts
Invoice Overdue CheckDailyMark invoices as OVERDUE if past due date, send reminder email
Proposal Expiry CheckDailyExpire proposals past expiresAt, notify customer
Overdue Access ReviewWeeklyFlag enterprise accounts with invoices overdue > 30 days for admin review
Risk AssessmentOn submissionAuto-calculate risk: check org number format, email domain match, company existence
Contract Expiry CheckDailyExpire unsigned contracts past expiresAt, notify customer 7 days + 3 days before
Contract Renewal CheckDailySend renewal reminders when contract end date is within renewalNoticeDays

4.6 Automated Invoice Calculation Logic

When generating an enterprise invoice, the backend should:

  1. Base fee: The agreed basePrice for the billing period
  2. Credit usage: Count credits consumed in the period × creditRate
  3. Minimum spend: If total < minimumSpend, charge minimumSpend
  4. Discount: Apply discountPercent to the total
  5. Setup fee: Include in the first invoice only if setupFee > 0
Line items:
- Enterprise Plan Base Fee (Monthly/Quarterly/Annual): $X
- AI Credits Used: N credits × $X.XX = $Y
- CV Parsing: N parses (included / $Z overage)
- [Other metered features if applicable]
─────────────────────────────────
Subtotal: $A
Volume Discount (X%): -$B
─────────────────────────────────
Total Due: $C

Payment Terms: Net 30
Bank Details: [AiQlick bank info]
PO Number: [if provided]

5. Frontend Implementation Plan

5.1 New Components to Create

components/
reusable/
payments/
EnterpriseRequestModal.tsx # Multi-step modal (Steps 1-4)
EnterpriseRequestModal/
OrganizationStep.tsx # Step 1: Org details form
FeatureRequirementsStep.tsx # Step 2: Feature limit questionnaire
BillingPreferencesStep.tsx # Step 3: Billing prefs
ReviewStep.tsx # Step 4: Review & submit
EnterpriseRequestStatus.tsx # Status tracker component (with contract step)
EnterpriseProposalCard.tsx # Proposal display + accept/decline
EnterpriseContractView.tsx # Contract PDF viewer + signing UI
EnterpriseContractView/
ContractPdfViewer.tsx # Scrollable PDF viewer
SignatureCapture.tsx # Type / draw / upload signature
ContractSigningModal.tsx # Full signing flow modal
ContractStatusBadge.tsx # Contract status chip

admin/
payments/
EnterpriseRequestDetail.tsx # Full request review modal (admin)
EnterpriseRequestDetail/
OrgVerificationTab.tsx # Organization verification tab
FeatureReviewTab.tsx # Feature requirements review
PricingProposalTab.tsx # Create/send pricing proposal
ContractManagementTab.tsx # Contract view, countersign, regenerate
BillingManagementTab.tsx # Invoice management
EnterpriseDashboardWidgets.tsx # Dashboard stats cards

5.2 New GraphQL Operations to Add

graphql/operations/
enterprise/
queries.ts # MyEnterpriseRequest, admin queries
mutations.ts # Submit, accept/decline proposal, admin mutations
fragments.ts # ENTERPRISE_REQUEST_FIELDS, PROPOSAL_FIELDS

5.3 New Types

lib/types/
enterprise.ts # EnterpriseRequest, Proposal, form types

5.4 Modified Existing Components

FileChange
PlansTab.tsx"Request Access" opens EnterpriseRequestModal instead of direct mutation call
PlansTab.tsxShow EnterpriseRequestStatus component when user has pending/active request
EnterpriseTab.tsx (admin)Complete rewrite to use new request queue + detail modal
payment/page.tsxAdd enterprise request status query to billing page
creditsPage.tsxShow contract details for enterprise customers

5.5 Config Updates

Add to planFeatures.ts:

export const ENTERPRISE_INDUSTRIES = [
"Technology", "Healthcare", "Finance", "Education",
"Manufacturing", "Retail", "Consulting", "Legal",
"Real Estate", "Government", "Non-profit", "Other"
] as const

export const COMPANY_SIZE_OPTIONS = [
{ value: "1-10", label: "1-10 employees" },
{ value: "11-50", label: "11-50 employees" },
{ value: "51-200", label: "51-200 employees" },
{ value: "201-500", label: "201-500 employees" },
{ value: "500+", label: "500+ employees" },
] as const

export const BILLING_CYCLE_OPTIONS = [
{ value: "MONTHLY", label: "Monthly" },
{ value: "QUARTERLY", label: "Quarterly" },
{ value: "ANNUALLY", label: "Annually" },
] as const

export const PAYMENT_METHOD_OPTIONS = [
{ value: "INVOICE", label: "Invoice (Bank Transfer)" },
{ value: "CREDIT_CARD", label: "Credit Card" },
{ value: "DIRECT_DEBIT", label: "Direct Debit" },
] as const

6. Security Considerations

ConcernMitigation
Org number validationBackend validates format per country before accepting
Rate limitingMax 1 pending enterprise request per user/company
Data accessUsers can only see their own requests; admin queries require SuperAdmin role
Proposal tamperingProposal acceptance verifies proposalId belongs to the user's request
Invoice PDFGenerated server-side, signed, served via authenticated endpoint
PII in billingBilling address, VAT number treated as sensitive data — encrypted at rest
Org verificationAdmin must manually verify before approving; automated risk scoring aids but doesn't replace
Contract integrityContract PDFs are generated server-side; terms JSON is immutable once contract is created
Signature authenticitySignature includes timestamp + IP address; stored alongside contract for audit
Contract tamperingSigned PDFs include a hash/checksum; any modification invalidates the contract
Signature authorizationUser must confirm authorization checkbox before signing; signer email is verified
Contract access controlOnly the request owner and SuperAdmin can view/download contract PDFs
Contract PDF URLsPre-signed S3 URLs with short expiry (15 min) — not permanent public links

7. Migration Strategy

Phase 1: Core Flow (MVP)

  1. Backend: Create EnterpriseRequest and EnterpriseProposal tables
  2. Backend: Implement submit, admin review, and approve mutations
  3. Backend: Email notifications for submit + approve/reject
  4. Frontend: Enterprise request modal (4 steps)
  5. Frontend: Admin request queue with basic review
  6. Keep existing REQUEST_ENTERPRISE_SUBSCRIPTION as fallback during migration

Phase 2: Proposal Flow

  1. Backend: Proposal creation, sending, acceptance mutations
  2. Backend: Proposal expiry cron job
  3. Frontend: Proposal card in user billing page
  4. Frontend: Admin pricing proposal tab
  5. Frontend: Accept/decline flow

Phase 3: Contract Signing

  1. Backend: Create EnterpriseContract table
  2. Backend: Contract PDF generation (using template engine — e.g., Puppeteer HTML→PDF or a PDF library)
  3. Backend: signEnterpriseContract mutation with signature capture + IP logging
  4. Backend: adminCountersignContract mutation → subscription activation
  5. Backend: Contract expiry cron job
  6. Backend: Email notifications for contract lifecycle (ready, signed, executed, expiring)
  7. Frontend: Contract PDF viewer component
  8. Frontend: Signature capture component (type/draw/upload)
  9. Frontend: Contract signing modal with terms review
  10. Frontend: Admin contract management tab (view, countersign, regenerate, void)

Phase 4: Invoicing

  1. Backend: Enhanced invoice model with line items
  2. Backend: Automated invoice generation cron jobs
  3. Backend: Invoice PDF generation with company branding
  4. Frontend: Admin billing management tab
  5. Frontend: Enterprise customer invoice view

Phase 5: Polish

  1. Risk assessment automation
  2. Enterprise dashboard widgets
  3. Overdue handling and access blocking
  4. Contract renewal reminders + auto-renewal flow
  5. Enterprise customer self-service portal (usage, invoices, limits, contract)

8. Backend Checklist (What Backend Needs to Build)

Database

  • EnterpriseRequest table with all fields from Section 3.1
  • EnterpriseProposal table with all fields from Section 3.2
  • EnterpriseContract table with all fields from Section 3.3
  • Extend Subscription table with enterprise fields from Section 3.4 (including contractId)
  • Extend Invoice table with enterprise fields from Section 3.5
  • Migrations for all schema changes

GraphQL Schema

  • EnterpriseRequest type (with activeContract relation)
  • EnterpriseProposal type (with contract relation)
  • EnterpriseContract type
  • All enums: EnterpriseRequestStatus, ProposalStatus, ContractStatus, SignatureMethod, BillingCycle, PaymentMethodPreference, RiskLevel
  • All input types from Section 4.2 and 4.3 (including SignEnterpriseContractInput)

Mutations & Queries (User-Facing)

  • submitEnterpriseRequest — create request with full questionnaire data, validate org number format, set status=SUBMITTED
  • myEnterpriseRequest — return current user's active enterprise request (most recent non-cancelled), include activeContract
  • acceptEnterpriseProposal — validate ownership, update proposal status to ACCEPTED, generate contract PDF, set request status to CONTRACT_PENDING
  • declineEnterpriseProposal — update proposal status, send message to admin
  • cancelEnterpriseRequest — only if status is SUBMITTED or UNDER_REVIEW
  • getEnterpriseContract — return contract with PDF URL (pre-signed S3), mark viewedByCustomerAt on first view
  • signEnterpriseContract — validate input (agreedToTerms + authorizedToSign must be true), store signature data + IP + timestamp, embed signature into PDF, set contract status to CUSTOMER_SIGNED, set request status to CUSTOMER_SIGNED, notify admin
  • getSignedContractPdf — return pre-signed S3 URL for the fully executed contract (only after FULLY_EXECUTED status)

Mutations & Queries (Admin)

  • adminEnterpriseRequests — paginated list with status filtering
  • adminEnterpriseRequest — single request with all details + user/company relations
  • adminUpdateEnterpriseRequestStatus — status transitions with validation
  • adminVerifyOrganization — set orgVerified flag
  • adminCreateEnterpriseProposal — create proposal, optionally send immediately
  • adminApproveEnterpriseDirectly — skip proposal, create subscription directly
  • adminRejectEnterpriseRequest — reject with reason
  • adminRequestEnterpriseInfo — set status to UNDER_REVIEW, send message
  • adminGenerateDetailedInvoice — calculate usage, create invoice with line items
  • adminEnterpriseDashboard — aggregate stats query

Mutations & Queries (Admin — Contract)

  • adminCountersignContract — verify contract is CUSTOMER_SIGNED, embed admin signature, generate final signed PDF, set contract to FULLY_EXECUTED, activate subscription, set request to CONTRACT_SIGNED/APPROVED
  • adminPreSignContract — for direct approval: admin signs first, send pre-signed contract to customer
  • adminRegenerateContract — void existing contract, create new version with updated terms, notify customer
  • adminVoidContract — set contract to VOIDED with reason, notify customer

Contract PDF Generation

  • HTML → PDF template engine (e.g., Puppeteer, PDFKit, or similar)
  • Contract template with dynamic fields: parties, terms, limits, pricing, dates
  • Signature embedding: overlay signature image/text onto the PDF at designated signature fields
  • Hash/checksum generation for integrity verification
  • S3 storage for contract PDFs (separate bucket or prefix from general uploads)
  • Pre-signed URL generation for secure, time-limited access

Subscription Activation (on contract fully executed)

  • Triggered when contract reaches FULLY_EXECUTED status (both signatures present)
  • Create Subscription with billingMode: POSTPAID, status ACTIVE
  • Set all approved feature limits from proposal onto the subscription's plan (or create a custom plan)
  • Link enterpriseRequestId and contractId to subscription
  • Copy billing details (email, address, PO, VAT) to subscription
  • Grant initial credits if applicable
  • Set contract dates based on contractTermMonths

Email Notifications

  • All email triggers from Section 4.4 (20 triggers including contract lifecycle)
  • Invoice PDF generation and attachment
  • Contract PDF attachment for contract-ready and fully-executed emails
  • Email templates for each trigger

Cron Jobs / Scheduled Tasks

  • Monthly/quarterly/annual invoice auto-generation
  • Invoice overdue detection (daily)
  • Proposal expiry check (daily)
  • Contract expiry check (daily) — expire unsigned contracts, send reminders at 7d and 3d before
  • Contract renewal check (daily) — send renewal reminders when within renewalNoticeDays of end
  • Overdue access review (weekly)
  • Risk assessment on submission

Validation Rules

  • Max 1 pending request per user/company
  • Org number format validation per country (basic regex)
  • Status transition validation (e.g., can't go from REJECTED to APPROVED)
  • Proposal can only be accepted within expiry window
  • Only SuperAdmin can access admin enterprise mutations
  • Rate limiting on submission endpoint

Invoice Calculation

  • Base fee calculation per billing cycle
  • Credit usage metering and pricing
  • Minimum spend enforcement
  • Discount application
  • Setup fee (first invoice only)
  • Line item breakdown generation
  • PDF generation with company branding, payment details, PO number