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.mdfor 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
| Field | Type | Required | Notes |
|---|---|---|---|
| Organization Legal Name | text | Yes | Must match official registration |
| Organization Number | text | Yes | Business registration / VAT / EIN number |
| Country | select | Yes | Dropdown with country list |
| Industry | select | Yes | Pre-defined industry list |
| Company Size | select | Yes | 1-10, 11-50, 51-200, 201-500, 500+ |
| Website | url | No | Company website for verification |
| Billing Email | Yes | Where invoices will be sent (pre-filled from user email) | |
| Billing Address | textarea | Yes | Full billing address for invoices |
| VAT Number | text | No | For 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
| Feature | Default (Pro baseline) | Custom Input | Unlimited |
|---|---|---|---|
| Companies | 1 | number | checkbox |
| Team Members | 10 | number | checkbox |
| Collaboration Invites | — | number | checkbox |
| Connections / mo | — | number | checkbox |
| Jobs | — | number | checkbox |
| Pipelines | — | number | checkbox |
| Interviews / mo | — | number | checkbox |
| Meetings / mo | — | number | checkbox |
| Talent Pools | — | number | checkbox |
| Contacts | — | number | checkbox |
| Contact Notes | — | number | checkbox |
| CV Collections | — | number | checkbox |
| Shared Lists | — | number | checkbox |
| CV Parses / mo | — | number | checkbox |
| AI Messages / mo | — | number | checkbox |
| Text Rewrites / mo | — | number | checkbox |
| News Posts / mo | — | number | checkbox |
| Monthly Credits | — | number | checkbox |
Step 3: Billing Preferences
| Field | Type | Required | Notes |
|---|---|---|---|
| Billing Cycle | select | Yes | Monthly / Quarterly / Annually |
| Payment Method Preference | select | Yes | Invoice (bank transfer) / Credit Card / Direct Debit |
| Estimated Monthly Budget | select | No | < $500 / $500-2000 / $2000-5000 / $5000+ / Prefer not to say |
| Purchase Order Required | toggle | No | Whether they need PO numbers on invoices |
| PO Number | text | If PO required | Their purchase order number |
| Additional Notes | textarea | No | Free-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:
SUBMITTED→UNDER_REVIEW→PROPOSAL_SENT→CONTRACT_PENDING→CONTRACT_SIGNED→ACTIVE/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:
- User receives email notification with proposal summary
- In-app: the status tracker updates to "Proposal Sent"
- Shows the proposed pricing, custom limits, and contract terms
- User can Accept Proposal or Request Changes (sends message back to admin)
- 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:
- Status changes to
CONTRACT_PENDING - Customer receives email: "Your enterprise contract is ready for signing"
- In-app: status tracker shows "Contract" step as active
- Customer clicks [View Contract] to preview the full PDF
- 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
- On signing: signature + timestamp + IP address are embedded into the contract PDF
- Status changes to
CUSTOMER_SIGNED(waiting for AiQlick countersignature)
Step 2 — Admin Countersigns:
- Admin receives notification: "[Company] has signed the enterprise contract"
- 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)
- Admin countersigns (using their admin credentials as the AiQlick representative)
- Final signed contract PDF is generated with both signatures
- Status changes to
CONTRACT_SIGNED→ subscription activates → status becomesACTIVE
Step 3 — Post-Signing:
- Both parties receive the fully executed contract PDF via email
- Contract PDF is stored and accessible from:
- Customer: billing page → "View Contract" link
- Admin: enterprise request detail → Contract tab
- 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:
- Contract is still generated with the approved terms
- Admin can pre-sign (countersign first)
- Customer receives a pre-signed contract that only needs their signature
- 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:
| Column | Content |
|---|---|
| Company | Organization name + logo |
| Requester | User name + email |
| Org Number | Business registration number |
| Status | Chip: SUBMITTED / UNDER_REVIEW / PROPOSAL_SENT / APPROVED / REJECTED |
| Submitted | Date |
| Estimated Value | Budget range from questionnaire |
| Actions | Review / 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
| Section | Content | Admin Action |
|---|---|---|
| Company Details | Legal name, org number, country, industry, size, website | |
| Verification Status | Pending / Verified / Failed | Mark as Verified / Flag Issue |
| Org Number Check | Display org number with "Verify" button | Opens external registry lookup (link to country-specific business registry) |
| Email Verification | Billing email, domain match check | Send verification email |
| Website Check | Company website screenshot/status | Link to open website |
| Existing Account | Show if company already exists in system, their current plan, usage history | |
| Risk Assessment | Auto-calculated: new company, email domain match, org number format validation | Low / Medium / High risk badge |
Tab 2: Requested Features
Display the questionnaire responses in a table:
| Feature | Requested | Pro Limit | Recommendation | Override |
|---|---|---|---|---|
| Companies | Unlimited | 1 | 10 | [input] |
| Team Members | 50 | 10 | 50 | [input] |
| Jobs | Unlimited | — | -1 | [input] |
| ... | ... | ... | ... | ... |
Admin can override each limit before sending the proposal.
Tab 3: Pricing & Proposal
| Field | Description |
|---|---|
| Base Price | Monthly base price in cents (auto-suggested based on feature selections) |
| Credit Rate | Price per credit (default from billing config, can override) |
| Billing Cycle | Monthly / Quarterly / Annually (from customer preference) |
| Contract Term | Month-to-month / 6 months / 12 months / 24 months |
| Minimum Spend | Optional monthly minimum |
| Discount % | Volume discount percentage |
| Setup Fee | One-time setup fee (optional) |
| Custom Notes | Free-form notes visible to customer in the proposal |
| Internal Notes | Admin-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
| Section | Content | Admin Action |
|---|---|---|
| Contract Status | Current state: Draft / Pending Customer Signature / Customer Signed / Fully Executed | Status chip |
| Contract PDF | Preview of the generated/signed contract | [View PDF] [Download] |
| Signatory Info | Customer signer: name, title, email, signed at, IP address | Read-only |
| AiQlick Signer | Admin who will countersign | Auto-filled from logged-in admin |
| Countersign | Available when customer has signed | [Countersign & Activate] button |
| Pre-sign | For direct approval path — admin signs first | [Pre-sign Contract] button |
| Contract History | Audit log: generated, sent, viewed, signed dates | Timeline view |
| Regenerate | If terms change before signing | [Regenerate Contract] (invalidates previous) |
| Contract Template | Select template variant (standard / custom) | Dropdown |
Tab 5: Billing & Invoicing
| Section | Content |
|---|---|
| Payment Method | Invoice / Card / Direct Debit — set by admin |
| Billing Contact | Email, name, address (from questionnaire) |
| Invoice History | List of all invoices for this enterprise account |
| Generate Invoice | Date range picker → calculate usage → generate |
| Bank Details | AiQlick's bank details to include on invoices |
| Outstanding Balance | Total unpaid amount |
2.1.3 Enterprise Dashboard Widgets (Revenue Stats Tab)
Add to existing Revenue Statistics:
| Widget | Content |
|---|---|
| Pending Requests | Count of SUBMITTED + UNDER_REVIEW requests |
| Active Enterprise | Count of active enterprise subscriptions |
| Enterprise MRR | Monthly recurring revenue from enterprise accounts |
| Avg Enterprise Value | Average monthly spend per enterprise customer |
| Outstanding Invoices | Total unpaid enterprise invoice amount |
| Overdue Invoices | Count + 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)
| Trigger | Recipient | Email Content |
|---|---|---|
| Request submitted | Admin (super admins) | New enterprise request from [Company], org# [X], [size] employees |
| Request submitted | Customer | Confirmation: "We received your enterprise request. We'll review within 2 business days." |
| Status → UNDER_REVIEW | Customer | "Your enterprise request is now being reviewed by our team." |
| Proposal sent | Customer | Proposal details: pricing, limits, contract terms, CTA to accept/decline in-app |
| Proposal accepted | Admin | "[Company] accepted the enterprise proposal. Contract generated — awaiting signatures." |
| Proposal declined | Admin | "[Company] declined the proposal. Message: [their message]" |
| Contract ready | Customer | "Your enterprise contract is ready for signing. Please review and sign within [X] days." + PDF attachment |
| Contract signed by customer | Admin | "[Company] has signed the enterprise contract. Please countersign to activate." |
| Contract countersigned | Customer | "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 soon | Customer | "Your enterprise contract expires in [X] days. Please sign to avoid delays." (7 days + 3 days before expiry) |
| Contract voided | Customer | "Your enterprise contract has been voided. Reason: [X]. A new contract will be generated if applicable." |
| Contract renewal reminder | Customer + Admin | "Enterprise contract for [Company] expires on [date]. [X] days notice period." |
| Request rejected | Customer | "Your enterprise request was not approved. Reason: [X]. Contact support for questions." |
| More info requested | Customer | "We need additional information for your enterprise request: [admin message]" |
| Invoice generated | Customer (billing email) | PDF invoice attached, payment details, due date |
| Invoice overdue | Customer + Admin | Reminder: Invoice #X is overdue by [N] days |
| Payment received | Customer | "Payment received for invoice #X. Thank you." |
4.5 Automated Backend Jobs
| Job | Schedule | Description |
|---|---|---|
| Enterprise Invoice Generation | 1st of each month | For MONTHLY billing cycle enterprise accounts: calculate usage from previous month, generate invoice |
| Quarterly Invoice Generation | 1st of Jan/Apr/Jul/Oct | Same for QUARTERLY accounts |
| Annual Invoice Generation | Anniversary date | Same for ANNUALLY accounts |
| Invoice Overdue Check | Daily | Mark invoices as OVERDUE if past due date, send reminder email |
| Proposal Expiry Check | Daily | Expire proposals past expiresAt, notify customer |
| Overdue Access Review | Weekly | Flag enterprise accounts with invoices overdue > 30 days for admin review |
| Risk Assessment | On submission | Auto-calculate risk: check org number format, email domain match, company existence |
| Contract Expiry Check | Daily | Expire unsigned contracts past expiresAt, notify customer 7 days + 3 days before |
| Contract Renewal Check | Daily | Send renewal reminders when contract end date is within renewalNoticeDays |
4.6 Automated Invoice Calculation Logic
When generating an enterprise invoice, the backend should:
- Base fee: The agreed
basePricefor the billing period - Credit usage: Count credits consumed in the period ×
creditRate - Minimum spend: If total <
minimumSpend, chargeminimumSpend - Discount: Apply
discountPercentto the total - 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
| File | Change |
|---|---|
PlansTab.tsx | "Request Access" opens EnterpriseRequestModal instead of direct mutation call |
PlansTab.tsx | Show EnterpriseRequestStatus component when user has pending/active request |
EnterpriseTab.tsx (admin) | Complete rewrite to use new request queue + detail modal |
payment/page.tsx | Add enterprise request status query to billing page |
creditsPage.tsx | Show 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
| Concern | Mitigation |
|---|---|
| Org number validation | Backend validates format per country before accepting |
| Rate limiting | Max 1 pending enterprise request per user/company |
| Data access | Users can only see their own requests; admin queries require SuperAdmin role |
| Proposal tampering | Proposal acceptance verifies proposalId belongs to the user's request |
| Invoice PDF | Generated server-side, signed, served via authenticated endpoint |
| PII in billing | Billing address, VAT number treated as sensitive data — encrypted at rest |
| Org verification | Admin must manually verify before approving; automated risk scoring aids but doesn't replace |
| Contract integrity | Contract PDFs are generated server-side; terms JSON is immutable once contract is created |
| Signature authenticity | Signature includes timestamp + IP address; stored alongside contract for audit |
| Contract tampering | Signed PDFs include a hash/checksum; any modification invalidates the contract |
| Signature authorization | User must confirm authorization checkbox before signing; signer email is verified |
| Contract access control | Only the request owner and SuperAdmin can view/download contract PDFs |
| Contract PDF URLs | Pre-signed S3 URLs with short expiry (15 min) — not permanent public links |
7. Migration Strategy
Phase 1: Core Flow (MVP)
- Backend: Create
EnterpriseRequestandEnterpriseProposaltables - Backend: Implement submit, admin review, and approve mutations
- Backend: Email notifications for submit + approve/reject
- Frontend: Enterprise request modal (4 steps)
- Frontend: Admin request queue with basic review
- Keep existing
REQUEST_ENTERPRISE_SUBSCRIPTIONas fallback during migration
Phase 2: Proposal Flow
- Backend: Proposal creation, sending, acceptance mutations
- Backend: Proposal expiry cron job
- Frontend: Proposal card in user billing page
- Frontend: Admin pricing proposal tab
- Frontend: Accept/decline flow
Phase 3: Contract Signing
- Backend: Create
EnterpriseContracttable - Backend: Contract PDF generation (using template engine — e.g., Puppeteer HTML→PDF or a PDF library)
- Backend:
signEnterpriseContractmutation with signature capture + IP logging - Backend:
adminCountersignContractmutation → subscription activation - Backend: Contract expiry cron job
- Backend: Email notifications for contract lifecycle (ready, signed, executed, expiring)
- Frontend: Contract PDF viewer component
- Frontend: Signature capture component (type/draw/upload)
- Frontend: Contract signing modal with terms review
- Frontend: Admin contract management tab (view, countersign, regenerate, void)
Phase 4: Invoicing
- Backend: Enhanced invoice model with line items
- Backend: Automated invoice generation cron jobs
- Backend: Invoice PDF generation with company branding
- Frontend: Admin billing management tab
- Frontend: Enterprise customer invoice view
Phase 5: Polish
- Risk assessment automation
- Enterprise dashboard widgets
- Overdue handling and access blocking
- Contract renewal reminders + auto-renewal flow
- Enterprise customer self-service portal (usage, invoices, limits, contract)
8. Backend Checklist (What Backend Needs to Build)
Database
-
EnterpriseRequesttable with all fields from Section 3.1 -
EnterpriseProposaltable with all fields from Section 3.2 -
EnterpriseContracttable with all fields from Section 3.3 - Extend
Subscriptiontable with enterprise fields from Section 3.4 (includingcontractId) - Extend
Invoicetable with enterprise fields from Section 3.5 - Migrations for all schema changes
GraphQL Schema
-
EnterpriseRequesttype (withactiveContractrelation) -
EnterpriseProposaltype (withcontractrelation) -
EnterpriseContracttype - 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), markviewedByCustomerAton 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, statusACTIVE - Set all approved feature limits from proposal onto the subscription's plan (or create a custom plan)
- Link
enterpriseRequestIdandcontractIdto 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
renewalNoticeDaysof 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