ESOP Policies and Behavioral Notes
- Pool Reservation & Recycling: The ESOP pool calculation reserves capacity for all non-terminal grants, including
PENDING_BOARD_APPROVAL,AWAITING_ACCEPTANCE_SIGNATURE,OFFERED,ACTIVE, andFULLY_EXERCISED. Exercised options remain reserved by default so the pool never "refills" without shareholder approval, and fully exercised grants stay blocked from the pool unless recycling is enabled. Schemes that explicitly recycle exercised shares can opt into the legacy behaviour by toggling therecycleExercisedSharesflag; when enabled, dashboards and fully diluted share counts track the outstanding (recycled) option balance rather than the configured pool size. Terminated grants that have passed their legalexpiryDatecontribute only their exercised portion to the pool (outstanding balances drop to zero) unless recycling is explicitly enabled.BAD_LEAVERgrants keep their vested balances reserved while their statutory/post-termination window remains open; onlyFOR_CAUSEterminations are stripped out immediately (seepolicy:termination-for-causefor forfeiture rules). When exit-only schemes keep the window closed, the pool continues to reserve the vested-but-locked portion (numberOfOptions − exercised − forfeited − lapsed) plus any shares already exercised so previously lapsed balances are not re-reserved but the exercised slice remains accounted for.
-
For-Cause Terminations: All unexercised options are forfeited immediately upon for-cause termination; any shares already exercised stay issued, but no further exercise is allowed. For-cause grants are excluded from terminated exercisable totals when calculating pool usage (see
policy:vesting-pool-reservation), ensuring the pool never reserves capacity for options that are permanently forfeited under disciplinary exits. Exit acceleration never restores lapses or forfeits onFOR_CAUSEgrants. -
Exit Acceleration Policy: When
accelerateOnExitis enabled the scheme fully vests active holders andGOOD_LEAVERterminations once the exit date arrives;BAD_LEAVERandFOR_CAUSEgrants remain forfeited even during exit acceleration. The optional flagaccelerateTerminatedGoodLeaversextends that behaviour to schemes that do not run full acceleration (e.g., exit-only unlocks without full acceleration) so terminated good leavers still accelerate, but it only clears recorded lapses/forfeits whenrestoreLapsedOptionsOnExitis enabled (and, for exit-only plans, whenreopenExerciseWindowOnExitalso stays on). Acceleration checks are evaluated deterministically at the same reference date used for vesting (termination date for terminated grants) so exports stay aligned. If the company postpones an exit, previously accelerated vesting events are unprocessed until the new date. Terminations processed after an exit – or grants markedBAD_LEAVER/FOR_CAUSE– retain their recorded lapses even if the scheme accelerated on exit.
- Acceleration keeps the window open through the exit-day local end-of-day only; after that deadline, any remaining reinstated balance lapses and pool usage retains only the already exercised portion.
- Termination flows compare the termination timestamp to the exit-day EOD deadline. If the termination timestamp is after the exit-day end-of-day (23:59:59.999 in company timezone), recorded lapses and forfeits remain in place even when
restoreLapsedOptionsOnExitand window reopen toggles are enabled. This allows terminations on exit day (before EOD) to be eligible for reinstatement while the exit window is open.- Manual termination routes (single grant, bulk, and member deactivation) honour the legal termination timestamp while evaluating exit reinstatement against the current processing time. Reinstatement only applies while that processing clock remains before the company-local exit-day end-of-day; once the deadline passes, historical terminations retain their recorded lapses even if policy toggles are enabled.
- Exercise APIs evaluate exit-day and legal-expiry deadlines against the submission timestamp. Backdated
exerciseDatevalues are only accepted while the submission occurs before the relevant deadline; once the window closes, the request is rejected even if the payload supplies an earlier timestamp. - Grants marked
EXPIREDsolely because the legal instrument lapsed (no termination timestamp) are treated as active participants for exit acceleration and overrides, so their exercisable balance reopens during the exit window while the exits-only lock rules continue to apply to actual terminations. - When the exit-day override fires for these expiry-only grants, any lapses recorded by expiry jobs are reinstated automatically even if "Restore lapsed options on exit" remains disabled (reflected as
effectiveLapsedOptions = 0ingetExerciseDataresponses), ensuring members recover the outstanding balance that policy guarantees during the exit window.
- Exit-Only Exercise Schemes: When a scheme is configured as exit-only, exercisable and net outstanding amounts are clamped to zero until an exit event is recorded. Once an exit is logged, previously lapsed post-termination windows only reopen and reinstate balances when both “Restore lapsed options on exit” and “Reopen post-termination window on exit” are enabled. Keeping either toggle off preserves recorded lapses/forfeits so the pool and reporting remain conservative. Non exit-only plans still rely solely on the
restoreLapsedOptionsOnExitflag; acceleration is not required to reinstate previously lapsed balances.- When administrators keep the toggle disabled, terminated holders remain locked even after the exit is recorded. This applies even if no post-termination lapse window was configured; the grant stays
EXPIRED/TERMINATEDwith zero exercisable balance so the pool cannot be reused prematurely. - Derived exercise helpers keep
windowExpired = truefor these terminated grants until both toggles are enabled, preventing dashboards and exports from surfacing a reopened window that policy forbids. - Locked exit-only grants retain their original vested totals in reporting (
netCumulativeVestedstays at the pre-gating value) whilenetOutstandingis suppressed to 0. The nightly post-termination processor simply flips their stored status toEXPIREDonce the exit-day deadline has passed and leaves recorded lapses/forfeits unchanged, ensuring pool reservations continue to carry the blocked balance. - Terminations captured during an exit-only reopening inherit the restored balance only when both toggles are enabled. Otherwise, the reinstatement stash retains the historical lapses/forfeits and the grant stays blocked.
- Clearing or postponing an exit after such terminations no longer replays the old lapses because the reinstatement stash is dropped once the termination is persisted.
- When administrators keep the toggle disabled, terminated holders remain locked even after the exit is recorded. This applies even if no post-termination lapse window was configured; the grant stays
- Exit-Day Deadline: When exit unlocks exercise (either via acceleration or exit-only rules), the effective exercise deadline is the end of the exit day in the resolved company timezone (falling back to the platform timezone, then UTC). The UI labels this as an “Exit event (end of day)” deadline so members see the exact local cut-off.
- Platform APIs (
getExerciseContext, notifications) always surface this exit-day deadline asdeadlineType = EXIT_EVENT_EODso downstream processes and alerts stay aligned. - Strict Expiry Option: Active grants always inherit the exit-day override so they can exercise even when their legal expiry has passed. The scheme toggle “Exit overrides grant expiry (exit day)” specifically controls whether eligible terminated holders (when restore-and, for exit-only plans, reopen policies allow them) receive the same override. Default is On; disable it only if your rules keep terminated holders locked after expiry even during an exit.
- Pool reservation: Capacity calculations reserve terminated exit‑only grants before an exit. Exercised portions are always reserved; in aggregate fallbacks the system conservatively reserves vested‑but‑locked balances as well to avoid over‑allocation. Detailed per‑grant views will still show 0 exercisable prior to exit. When the reopen toggle is disabled the pool continues to reserve the terminated balance even after the exit is recorded so administrators cannot recycle the pool prematurely.
- Reporting note: When an exit reopens an expired post‑termination window,
statusEffectivereflects the holder’s actual state: expiry-only grants (no termination timestamp) surfaceACTIVEfor the duration of the reopen, while terminated holders continue to surfaceTERMINATED. Once the exit-day deadline passes, both scenarios revert toEXPIRED. The original termination timestamp remains unchanged.
- Platform APIs (
- Post exit-day lapse: Once the exit-day local deadline has passed, any remaining vested-but-unexercised balance on exit-only terminated grants is moved to
lapsedOptionsautomatically, marking the grant as EXPIRED. API endpoints also surface anstatusEffectiveofEXPIREDimmediately after the deadline so member dashboards and exports reflect the closed window even before the nightly lapse job persists the lifecycle change. - Revived expiries: Exit-only schemes revive expired grants for terminated holders only when both the restore and reopen toggles are on. Active participants always receive the exit-day override regardless of the toggles, so they can exercise even if the instrument expiry has passed. For non exit-only plans, enabling “Restore lapsed options on exit” temporarily treats previously EXPIRED grants as TERMINATED during the reopening so that post-termination notifications and lapse jobs continue to run. After the exit-day deadline the remaining balance lapses and the grant returns to EXPIRED.
- Exit reinstatements store the original lapsed/forfeited balances while the exit is active, along with the exercised and outstanding baselines, ensuring that clearing or postponing the exit automatically restores the remaining totals after subtracting any options exercised during the reopening, without manual reconciliation. This applies to accelerated exits and to exit-only reopenings when the window is configured to reopen.
- The single-grant termination API mirrors the bulk-terminate and member deactivation flows by persisting the exit reinstatement stash (
exitRestored*fields) whenever restoration applies, so clearing or postponing an exit restores the exact pre-exit balances regardless of which termination surface was used.
- The single-grant termination API mirrors the bulk-terminate and member deactivation flows by persisting the exit reinstatement stash (
- Post-Termination Windows: After the post-termination exercise window lapses with no exit relief, exercisable and net-vested balances drop to zero to match statutory forfeiture. Any later acceleration or exit-only unlock recalculates from the shared vesting service so downstream consumers see the reopened totals immediately.
- Auto-Exercise for UNRESTRICTED Schemes: When a scheme is configured as UNRESTRICTED (anytime exercise,
exerciseOnExitOnly: false) and auto-exercise is enabled (autoExerciseEnabled: true), the platform automatically exercises vested options at each vesting event to trigger Section 8C tax obligations immediately. This solves the "paper gain" problem where employees owe PAYE on options they haven't exercised yet — under Section 8C, tax vesting occurs when UNRESTRICTED options become exercisable (at internal vesting), not when the employee chooses to exercise them. The settlement method follows the scheme configuration (autoExerciseSettlementMethod, defaultSHARE_WITHHOLDINGbutCASHis supported). When share withholding is selected the system withholds shares equal to the PAYE amount and issues the net balance; when cash settlement is selected the full option block is issued and the recorded PAYE amount is handed off to payroll for cash remittance. Auto-exercise processing includes 3 retry attempts with exponential backoff (1s, 2s, 4s delays) to handle transient failures. The feature is blocked during exit events (requires manual processing), requires a current valuation (max staleness: 183 days sourced fromCompanyConfig.maxValuationStaleness, defaulting to 183 when unset), and only processes grants inACTIVEstatus. Each auto-exercise is recorded with audit actions (AUTO_EXERCISE_COMPLETED,AUTO_EXERCISE_FAILED) and links to the originatingvestingEventIdfor traceability. Idempotency checks prevent duplicate exercises for the same vesting event. This feature is gated byNEXT_PUBLIC_ENABLE_UNRESTRICTED_SCHEMESenvironment variable (default:false) — when disabled, only RESTRICTED (exit-only) schemes are available. Seedocs/reference/ESOP_SECTION_8C.mdfor tax implications and complete implementation details. Implementation:lib/services/exercise.service.ts(canAutoExercise(),autoExerciseAtVesting()), triggered by daily vesting cron job inlib/email-notifications.ts(processRegularVestingEvents()).
-
Invitation vs Option Expiry: Grant invitation validity is tracked via
offerExpiresAtand is distinct from the instrument's optionexpiryDate(7–10 years or company policy). Accepting an offer is blocked only whenofferExpiresAt(computed from the invitation issue timestamp) has passed. Both offer expiry and option expiry are evaluated at end‑of‑day (23:59:59.999) in the resolved company timezone (falling back to the platform timezone, then UTC viaresolveTimezone).- End-of-Day Grace Period: Offer expiry uses the same end-of-day calculation as exercise windows for consistency. When an offer is set to expire on January 30, members can accept until 23:59:59.999 on January 30 in the company's local timezone. This ensures predictable behavior and aligns with the platform's general deadline pattern. Once that moment passes, the offer must be reissued or extended before acceptance can proceed.
- Default Window: New offers default to 30 days from invitation issuance. This can be customized at three levels (in order of precedence): company-level configuration via Dashboard → Company → Configuration, the
INVITE_DEFAULT_DAYSenvironment variable, or the hardcoded default of 30 days. Admins can still accept grants on behalf of users after the invite expires by reissuing or extending the offer.
-
Leaver Policies:
- Good Leaver: preserves vested options as at termination date; unvested options forfeit. Post-termination exercise window may apply.
- Bad Leaver: unvested options are forfeited immediately; vested options remain but may be repurchased at nominal value. The platform keeps their dashboards/access active until the legal exercise window lapses so they can action remaining rights.
- For Cause: See
policy:termination-for-causeabove for complete forfeiture and pool treatment rules.
- Termination eligibility check: Termination flows reject termination dates that fall before a grant's legal start date (grant date or vesting start). This keeps statutory vesting intact and ensures exit acceleration math evaluates from the correct employment reference. Attempts to terminate earlier than the grant start raise an error until the grant metadata is corrected.
- Post-expiry guardrail: Termination submissions captured after the grant’s legal expiry end-of-day (23:59:59.999 in the resolved company timezone) are rejected across single-grant, bulk, and member deactivation flows. Submissions timestamped on the expiry date itself remain valid through that local deadline. Extend the option expiry (or capture the termination earlier) so the statutory post-termination window remains enforceable before filing the termination.
- Last exercise ordering: Terminations must also fall on or after the holder's most recent exercise timestamp. Same-day submissions are only accepted when the termination time is equal to or later than the exercise. The shared termination validator enforces this ordering so the statutory window stays intact and regulators receive a chronological audit trail.
- Termination audit log: Every admin surface requires both a precise termination timestamp (ISO 8601 datetime) and a descriptive termination reason (minimum 10 characters) so audit exports, emails, and downstream compliance reviews capture when and why the employee departed. Attempts without a sufficient reason or missing the timestamp are rejected. For additional details on timestamp normalization and timezone handling, see
TIMEZONE_RULES.md.
- Post-Termination Exercise Window Counting: The post-termination exercise window (lapse days) defines how many calendar days remain exercisable after termination. The termination date itself is the first exercisable day (day 1 of the window). A 30-day window means 30 full calendar days are exercisable starting from the termination date. The final exercisable day is calculated as
termination date + (lapseDays - 1)calendar days at end-of-day in the company-local timezone. Why subtract 1? Because the termination date itself counts as day 1, we only need to add (lapseDays - 1) additional days to reach the final day. Example: A 30-day window from January 1 means: Day 1 = Jan 1, Day 30 = Jan 30. Calculation: Jan 1 + (30 - 1) days = Jan 1 + 29 days = Jan 30. The deadline is 23:59:59.999 on January 30 in the resolved company timezone, giving exactly 30 full calendar days (Jan 1 through Jan 30 inclusive). Window overrides must remain between 0 and 365 days. Seelib/exercise-window.tsfor implementation details anddocs/guides/platform-user-guide.mdfor configuration guidance.
-
Exercise Window Timezone: Post‑termination exercise windows use the company-local timezone for deadline calculations. Callers must resolve the timezone via
resolveTimezone({ companyId })and pass it to exercise window functions likecalculateExerciseWindowDeadline(). The resolution chain falls back from company timezone → platform timezone → UTC. If no timezone is passed to the calculation functions, they default to UTC. Deadlines honour DST changes so lapses end at the local 23:59:59. Configure your company timezone in settings so deadlines, alerts, and expiry processing align with local regulations. -
Snapshot semantics (forfeits and lapses): Unless otherwise stated, reporting snapshots use policy‑effective values. In particular,
forfeitedOptionsreflects recorded forfeits plus any policy‑effective lapses at the snapshot time. When “Restore lapsed options on exit” is enabled and exit acceleration or an exit‑only unlock applies, effective lapses are reinstated (0) and the snapshot’sforfeitedOptionsexcludes those reinstated lapses.
- Grant expiry alignment: Option
expiryDatemust be on or after the grant's start date (same-day expiry is permitted). Invite creation and grant edits enforce this guardrail so instruments never expire before they legally exist. If administrators try to capture an expiry that predates the grant, the platform blocks the submission and surfaces a clear error instructing them to choose a later (or equal) expiry date.
- SARS Valuation Freshness: Exercises and discounted grants rely on the latest valuation on file. If the valuation is older than 183 days, both discounted grants and exercises are blocked unless an administrator records an explicit override. Important: Valuation staleness is measured from the current processing time (when the exercise or grant is being processed), not from historical event dates like vesting dates. This ensures fresh valuations are used even when processing delayed vesting events or backdated grants, preventing stale valuations from being applied to current transactions.
- Override procedure:
- Obtain a board resolution approving reliance on the stale valuation. The resolution must be approved by the directors and minuted by the company secretary (or the designated compliance officer where no secretary is recorded).
- Record the approval by generating or uploading the signed resolution via Dashboard → Documents → Compliance → Board Resolution so the override is stored alongside the valuation and audit history.
- When editing a grant or processing an exercise against a stale valuation, tick the SARS valuation override confirmation so the acknowledgement (
confirmStaleValuation: true) is recorded in the audit trail and confirmation email. When no valuation exists, capture the board approval metadata without the stale confirmation flag—the override proceeds once the supporting details are supplied. - Attach the signed board minute or resolution to the override submission. Capsense blocks the exercise until a document URL is provided so SARS reviewers can trace the acknowledgement back to the supporting evidence.
- When no valuation exists (for example, immediately after incorporation) or a stale valuation is reused to discount an exercise price, the grant edit workflow enforces entry of the board meeting date, approval reference, and fair value per share. Submissions without those details are rejected, and the stored grant now records the override metadata so SARS audits can be satisfied later.
- Override procedure:
- Future-dated valuations: If the latest valuation date falls after the grant or exercise effective date, Capsense treats the quote as unavailable and requires an admin override. When you proceed with that override, the exercise dialog blocks submission until an administrator acknowledges the “valuation date occurs after this transaction” warning so the audit trail captures that you knowingly relied on board-approved pricing instead of the future-dated valuation.
- Late board minutes: When the override’s board approval date is recorded after the grant or exercise effective date, Capsense surfaces a compliance warning and blocks submission until an administrator acknowledges that the board minute post-dates the transaction. This acknowledgement proves that management accepted the timing risk while still attaching the signed minute to the override.
- Price variance acknowledgement: If the override market price differs from the board-approved fair value per share, administrators must acknowledge the variance before the exercise can proceed. The acknowledgement captures that the board-approved FMV was intentionally adjusted and keeps the override trail auditable for SARS.
- Guardrails: Capsense refuses valuations dated after the grant or exercise effective date. Future-dated quotes are treated as unavailable, forcing administrators to either capture a compliant valuation (dated on or before the transaction) or record a manual override with the correct board-approved price. When board approval minutes are captured after the effective date, the override raises a compliance warning—administrators must either correct the meeting date or explicitly acknowledge the risk before the exercise can proceed.
- Fair Market Value Capture: When no SARS valuation exists the member onboarding UI now flags the missing FMV, requires administrators to enter the board-approved exercise price manually, and reminds them to retain the supporting board resolution instead of deriving a nominal value from share capital.
- Market Price on Exercise: The platform calculates the market price from the latest valuation by default. When administrators invoke the manual override, they must supply the board-approved fair market value and justification; members cannot self-submit exercises.
- Exercise Share Class Configuration: Exercises require the scheme's
exerciseShareClassIdto be configured during ESOP setup. If not configured, exercise requests will be rejected with an error prompting the administrator to configure the share class via ESOP Setup or Company Configuration. There is no automatic fallback to a default share class—the configuration must be explicit to ensure proper tracking of which share class receives exercised shares. This ensures administrators make deliberate decisions about share class structure and prevents exercises from being issued to an unintended share class. Configure via Dashboard → ESOP Setup → Exercise Share Class or/api/schemes/[schemeId]/exercise-share-class.
-
Share Authorization Hierarchy: The platform enforces a hierarchical authorized share structure where company-wide authorized shares (set in Company Configuration) serves as the ceiling, and individual share class authorizations (set in Cap Table → Share Classes) represent allocations of that ceiling. The sum of all
ShareClass.authorizedSharesmust not exceedCompany.totalShares(MOI limit). This validation is enforced at both the API level (/api/company/share-classesPOST and PUT endpoints) and surfaced as a real-time warning in the cap table UI when the sum exceeds the company total. The configuration page shows allocation status (e.g., "800,000 of 1,000,000 allocated (80%)") to help administrators track how the MOI ceiling is distributed across share classes. When creating or updating a share class would cause the total to exceed the company-wide limit, the API returns a detailed error message showing current allocation, the new class amount, and the excess, directing administrators to increase the company-wide authorized shares first. This prevents invalid configurations that would violate MOI limits and ensures cap table calculations remain accurate for dilution analysis and compliance reporting. -
Backdated Vesting Policy: The API allows
vestingStartDateto be earlier than thegrantDateto align vesting with an employment start date or probation end. This can cause immediate vesting upon acceptance (e.g., a 12‑month cliff may elapse instantly if the backdate crosses the cliff). Admin screens show the calculated vesting outcome before saving. If you prefer to prohibit or warn on aggressive backdating, set internal policy and review the previewed vested amounts prior to submission. Future guardrails may include optional warnings when backdating exceeds a configurable threshold.
- AI Document Templates: All AI-generated documents start from professionally-structured baseline templates (TypeScript-based) that include South African legal compliance requirements (Companies Act Section 97, Income Tax Act Section 8C, CIPC forms). AI agents refine templates with actual company data rather than generating from scratch, ensuring consistency and compliance. Templates include 50+ placeholders that are automatically filled from the company's configuration, scheme settings, grant details, and board information. The template registry (
lib/document-templates/index.ts) provides access to all 6 document types: Scheme Rules, Offer Letter, Acceptance Form, Board Resolution, Compliance Certificate (CoR46.2), and Annual Report. Each template maintains a structured section hierarchy with required and optional sections, validated through unit tests to ensure completeness and legal accuracy.
- Document AI Validation: AI-generated documents pass through 5-stage validation: (1) Drafting - loads baseline template and fills placeholders with company data from database queries, (2) Personalization - adds company-specific context and adjusts language for readability, (3) Validation - checks structural completeness and data consistency, (4) Compliance - verifies South African legal requirements including proper references to Companies Act Section 97, Income Tax Act Section 8C, and CIPC filing forms, (5) QA - performs final quality checks including grammar, formatting, and professional presentation. All documents require legal counsel review before use - AI generation creates drafts, not final legal instruments. Feature requires Enterprise plan (feature gate:
ai_docs). The system supports OpenAI (gpt-5-2025-08-07) as primary provider with automatic fallback to Anthropic Claude (claude-sonnet-4-20250514) when OpenAI is unavailable. Documents are generated in dual formats (PDF for final distribution, DOCX for legal review) and stored in S3 with audit trail logging.
- Document Legal Compliance: All AI-generated documents reference applicable South African legislation and regulatory requirements. Scheme Rules include Companies Act 2008 Section 97 (employee share scheme approval requirements), board and shareholder approval thresholds, and implementation procedures. Tax-related documents (Scheme Rules, Offer Letters, Annual Reports) include Income Tax Act Section 8C references explaining ESOP tax treatment, with explicit disclosures about tax vesting timing based on RESTRICTED (exit-only exercise - tax deferred until restrictions lift) vs UNRESTRICTED (anytime exercise - tax due at internal vesting) scheme classification. The Compliance Certificate template follows CIPC Form CoR46.2 structure for annual share scheme filings, including company registration details, scheme authorization information, annual activity metrics, and compliance officer attestation. Board Resolution templates include proper legal authority references, recitals explaining context, numbered resolutions, and director signature sections. All templates maintain professional legal tone and include disclaimers requiring qualified legal counsel review before final use.
- Company Secretary Designation: At least one board member must be designated as Company Secretary for proper corporate governance and compliance. This requirement ensures that board resolutions, ESOP documentation, and CIPC filings have proper authority and legal validity under the South African Companies Act Section 97. The setup wizard enforces this validation before scheme activation (
lib/validations.ts), blocking setup submissions until a secretary is designated. The secretary role is tracked via theisSecretaryboolean field on theBoardMembermodel. When generating board resolutions and compliance documents, the system identifies the secretary for proper attestation and signature authority. If no secretary is explicitly designated, document generation and certain governance workflows may be blocked or require manual override.
- Document Soft Delete (Archive): Documents use soft delete (archival) instead of permanent deletion to preserve compliance audit trails and enable recovery. When an admin archives a document, the system sets
Document.deletedAtto the current timestamp and records aDOCUMENT_DELETEDaudit action with operation'archived'. Archived documents are excluded from default queries (deletedAt: null) but can be viewed by toggling the "Show Archived" filter in Document Management. Restoring an archived document clears thedeletedAttimestamp (sets tonull) and logs aDOCUMENT_GENERATEDaudit action with operation'restored'. ThedeletedAtfield is indexed for efficient filtering. Soft delete is preferred for compliance (legal/regulatory requirements to retain document history), audit trail completeness, recovery from accidental deletion, document lifecycle analytics, and preventing permanent data loss. API endpoints enforce that documents cannot be archived twice (deletedAtalready set) and cannot be restored if not archived (deletedAtis null). All archive/restore operations are COMPANY_ADMIN or SUPERADMIN only. Implementation:DELETE /api/documents/[documentId](archive),PATCH /api/documents/[documentId](restore).
- Document Signature Reminders: Admins can send reminder emails to signers with pending signature requests via the Document Management interface. The reminder system (
POST /api/documents/[documentId]/send-reminder) queries allPENDINGsignature requests for the document and sends individualized reminder emails to each pending signer. Each email includes the document name, company name, magic link to the signature page (/sign/{token}), expiry date warning, and contact information. After sending, the system updatesDocumentSignatureRequest.lastReminderSentAtto the current timestamp to track reminder frequency. The audit trail logs aDOCUMENT_GENERATEDaction with operation'signature_reminder_sent', recipient count, and recipient details (name/email). Best practices: Wait 2-3 days between reminders to avoid spam, send first reminder when 50% of validity period has elapsed, send final reminder 1-2 days before expiry. Reminders are only sent to pending signers (not already signed), and the system returns an error if no pending requests exist. Implementation:/app/api/documents/[documentId]/send-reminder/route.ts.
- Document Signature Cancellation: Admins can cancel all pending signature requests for a document when content needs revision, employee leaves before signing, board resolution is superseded, or workflow is no longer needed. The cancellation endpoint (
POST /api/documents/[documentId]/cancel-signature) updates allPENDINGsignature requests toREJECTEDstatus and updates the parent document'ssignatureStatustoREJECTED. This action is irreversible—signers cannot complete signatures after cancellation and their magic links become invalid. The audit trail logs aDOCUMENT_DELETEDaction with operation'signature_requests_cancelled', cancelled count, and recipient details. The system returns an error if no pending requests exist to cancel. Note: The API currently cancels all pending requests for a document; per-signer cancellation is not supported. Use cases include document regeneration (content errors found), terminated employees (offer no longer valid), superseded resolutions (new version generated), or abandoned workflows. COMPANY_ADMIN or SUPERADMIN authorization required. Implementation:/app/api/documents/[documentId]/cancel-signature/route.ts.
- Document Management Filtering: The Document Management UI (
/dashboard/documents/management) provides comprehensive filtering to help admins track documents, monitor signature workflows, and manage lifecycles. Filters include: (1) Document Type - filter by SCHEME_RULES, OFFER_LETTER, ACCEPTANCE_FORM, BOARD_RESOLUTION, COMPLIANCE_CERTIFICATE, or ANNUAL_REPORT, (2) Signature Status - filter by NO_SIGNATURE (no workflow), PENDING (awaiting signatures), SIGNED (completed), EXPIRED (links expired), or REJECTED (cancelled/declined), (3) Search - case-insensitive name search with partial matching, (4) Show Archived - toggle to view archived documents (exclusive with active view). Filters combine with AND logic (e.g., "Offer Letters" + "Pending Signature" shows only pending offer letters). The signature status filter uses multi-signer awareness—documents with multiple signers show overall status based on priority: all SIGNED → SIGNED status, any EXPIRED → EXPIRED status, any REJECTED → REJECTED status, any PENDING → PENDING status. Pagination supports 50 documents per page with Previous/Next navigation. All queries are company-scoped to prevent cross-company access. Implementation:GET /api/documents/managementwith query parameterstype,signatureStatus,search,showArchived,page,limit.
- Board Approval Workflow: All new grants require board approval via electronic signatures before members receive offer letters. When a grant is created, it enters
PENDING_BOARD_APPROVALstatus and the system auto-generates a board resolution document. All active board members receive signature requests via magic links. Once all required signatures are collected, the grant transitions toAWAITING_ACCEPTANCE_SIGNATUREstatus and the system generates the member offer letter. The offer letter is then sent to the member, transitioning the grant toOFFEREDstatus. When the member signs the offer letter, the grant becomesACTIVE. This workflow ensures proper governance approvals are collected and documented before equity commitments are made to employees. The board resolution template includes grant details, vesting terms, and legal authorization references. Electronic signatures use SHA-256 document hashing for integrity verification and token-based magic links for secure access. All signatures are timestamped and stored in the audit trail for compliance purposes.