Skip to main content

SPEC 003 — Cap Table

FieldValue
StatusDRAFT
PriorityP0 — Launch-Critical
Backendequa-server/modules/captable/
APIequa-server/modules/api/src/endpoints/captable-endpoints.ts
Frontendequa-web/src/modules/captable/
Confluence sources incorporated: “Allocation Graphs,” “Capitalization V1” — see sections 6a and 6b below

1. Feature Purpose

The cap table is the core product of Equa. It tracks who owns what in an organization — shareholdings, security types, pricing, funding rounds, valuations, and ownership transfers. Every share issuance produces a signed certificate with legends. The cap table powers the fully-diluted ownership view, capital change history, and investor reporting.

2. Current State (Verified)

2.1 Backend

ComponentPath
Module rootequa-server/modules/captable/
API endpointsequa-server/modules/api/src/endpoints/captable-endpoints.ts

2.2 Frontend

ComponentPath
Cap table moduleequa-web/src/modules/captable/
Service layerequa-web/src/service/services/captable
Redux statecapTableReducer in root-reducer.ts

3. Data Model

Shareholdings

ColumnTypeConstraints
memberuuidFK → Members
organizationuuidFK → Organizations
sharesnumericPrecision-safe share count
securityTypehashFK → SecurityTypes (content-addressed)
issueDatedate
serialNumberintCertificate serial within org
shareholderNamevarcharName as printed on certificate
legendhashFK → Legends (content-addressed)
exercisedbooleanWhether options/warrants have been exercised
legacyShareholdingbooleanMigrated from legacy system

SecurityTypes

ColumnTypeConstraints
organizationuuidFK → Organizations
shareClassvarchare.g. “Common”, “Series A Preferred”
shareTypesmallintEnum (common, preferred, options, warrants, etc.)
certifiedSharesbooleanWhether share certificates are issued
votingSharesbooleanCarries voting rights
pricenumericDefault price per share
namevarcharDisplay name
sharePricinghashFK → SharePricingTable (content-addressed)
fractionalSharesbooleanAllows fractional ownership

SecurityDetails

Related metadata for security types (structure follows SecurityTypes context).

SecurityTypeSeniorityTable

Tracks liquidation preference ordering among security types within an organization.

SecurityTypeSharesTable

Aggregated share counts per security type (authorized, outstanding, reserved).

SharePricingTable

ColumnTypeConstraints
pricePerSharenumeric
parValuenumeric
originalIssuePricenumeric
conversionPricenumericFor convertible securities
conversionRatenumericConversion ratio

Holdings

ColumnTypeConstraints
entityuuidOrganization or fund entity
owneruuidMember or entity that owns the holding
valuenumericShare count or unit value
holdingTypevarcharType classification
namevarcharDisplay name
classvarcharShare class label
issueDatedate
pricePerUnitnumeric
outstandingnumericCurrently outstanding
authorizednumericTotal authorized
fullyDilutednumericFully-diluted count

CapitalChanges

ColumnTypeConstraints
modnumericChange amount (positive or negative)
timestamptimestampWhen the change occurred
typeuuidFK → SecurityTypes or change-type reference
organizationuuidFK → Organizations

FundingRounds

ColumnTypeConstraints
iduuidPK
organizationuuidFK → Organizations
numberintRound sequence number
endDatedate
totalCommonnumericCommon shares in round
totalPreferrednumericPreferred shares in round
namevarchare.g. “Seed”, “Series A”

Valuations

ColumnTypeConstraints
entityuuidFK → Organizations
issueDatedateValuation date
valuenumericValuation amount
unitsvarcharCurrency or unit label

Transfers

ColumnTypeConstraints
inputshashContent-addressed reference to source holdings
outputshashContent-addressed reference to TransferOutputs

TransferOutputs

ColumnTypeConstraints
holdinghashContent-addressed holding reference
owneruuidFK → new owner (Member or entity)
valuenumericTransferred amount

Legends

ColumnTypeConstraints
contenttextFull legend text (content-addressed by hash)

LegendMetas

ColumnTypeConstraints
legendhashFK → Legends
organizationuuidFK → Organizations
namevarcharLegend display name
authoruuidFK → Users who created the legend

Signatures

ColumnTypeConstraints
iduuidPK
shareholdinguuidFK → Shareholdings
signatoryuuidFK → Members
namevarcharSignatory name as displayed
titlevarcharSignatory title

4. API Endpoints

MethodPathAuthDescription
GET/api/v1/organizations/:id/captableYesFull cap table for organization
GET/api/v1/organizations/:id/shareholdingsYesList all shareholdings
POST/api/v1/organizations/:id/shareholdingsYesIssue new shares
PUT/api/v1/organizations/:id/shareholdings/:shIdYesUpdate a shareholding
DELETE/api/v1/organizations/:id/shareholdings/:shIdYesCancel / void a shareholding
GET/api/v1/organizations/:id/security-typesYesList security types
POST/api/v1/organizations/:id/security-typesYesCreate a security type
PUT/api/v1/organizations/:id/security-types/:stIdYesUpdate a security type
GET/api/v1/organizations/:id/funding-roundsYesList funding rounds
POST/api/v1/organizations/:id/funding-roundsYesCreate a funding round
GET/api/v1/organizations/:id/valuationsYesList valuations
POST/api/v1/organizations/:id/valuationsYesRecord a valuation
POST/api/v1/organizations/:id/transfersYesExecute a share transfer
GET/api/v1/organizations/:id/capital-changesYesCapital change history
GET/api/v1/organizations/:id/legendsYesList legends
POST/api/v1/organizations/:id/legendsYesCreate a legend
GET/api/v1/organizations/:id/signaturesYesList certificate signatures
POST/api/v1/organizations/:id/signaturesYesAdd a signature to a shareholding

5. Frontend Components

ComponentPathDescription
Cap table moduleequa-web/src/modules/captable/Cap table management, shareholding list, issuance forms
Shareholdings viewequa-web/src/modules/captable/Individual shareholding detail and certificate preview
Certificatesequa-web/src/modules/captable/Certificate generation with legends and signatures
Service layerequa-web/src/service/services/captableAPI client for cap table operations
Redux reducercapTableReducer in root-reducer.tsClient-side state for cap table data

6. Business Rules

  1. Numeric precision — Shares, prices, and valuations use numeric type (arbitrary precision) to avoid floating-point errors in financial calculations.
  2. Content-addressed immutability — SecurityTypes, Legends, SharePricing, and Transfers reference content by hash, ensuring historical records cannot be silently altered.
  3. Serial numbers — Each shareholding within an organization receives a sequential serialNumber for certificate identification.
  4. Fractional shares — Allowed only when SecurityTypes.fractionalShares = true for the relevant security type.
  5. Transfer integrity — Transfers use input/output hashes; the sum of output values must equal the input holding value (no shares created or destroyed).
  6. Exercised flag — Options and warrants track exercised = true once converted, preventing double exercise.
  7. Seniority orderingSecurityTypeSeniorityTable determines liquidation preference order among security types.
  8. Fully-diluted calculation — Holdings track outstanding, authorized, and fullyDiluted separately to support both basic and diluted ownership views.
  9. Legends on certificates — Every shareholding references a legend hash; legends are immutable once assigned to issued certificates.
  10. Signatures required — Certificates require at least one Signature record linking a signatory member with name and title.
  11. Legacy flaglegacyShareholding = true marks shareholdings imported from the previous system for migration tracking.

6a. Allocation Graph Model (from Confluence KnowledgeBase)

Source: Confluence KnowledgeBase — Allocation Graphs (by Christopher Johnson)
An entity can be divided into units, which are grouped into pools. Pools can be subdivided into child pools, forming a hierarchy called an allocation graph. An allocation graph is itself an entity. Node properties:
  • value — the amount of units allocated to the node
  • children — zero or more child nodes (sum of children’s values must not exceed parent’s value)
  • parent — every node except the root must have exactly one parent
Partition types — the units of a pool divide into:
  • Outstanding — issued and held by shareholders
  • External Reserved — allocated for external parties (investors, advisors)
  • Treasury (Internal Reserved) — held internally by the organization

6b. Capitalization V1 User Stories (from Confluence KnowledgeBase)

Source: Confluence KnowledgeBase — Capitalization V1 (by Christopher Johnson)
User stories (outstanding holdings only):
  • Transfer shares without affecting capital contributions of the source holding
  • Edit capital contributions of an active holding
  • Cancel a holding and preserve its capital contributions
  • Cancel a holding and its capital contributions
  • Edit capital contributions of a cancelled holding
  • Edit capital contribution of a holding that was transferred (effectively cancelled)
Key requirements:
  • When a holding is cancelled or transferred, capital contributions remain active by default
  • To cancel both a holding and its contributions: set contributions to zero, then cancel the holding
  • Users with cap table edit permission can edit cancelled holdings (known UI bug: “Resource Not Found” error)
  • Capital contribution fields in the Transfer form are deprecated and should not be used

7. Acceptance Criteria

  • Organization owner can create security types with class, pricing, voting, and fractional share settings
  • Shares can be issued to members with correct serial number auto-increment
  • Share pricing (price per share, par value, original issue price, conversion terms) is stored accurately
  • Shareholdings display on the cap table with correct ownership percentages
  • Fully-diluted view includes outstanding, authorized, and fully-diluted counts
  • Share transfers move ownership atomically (inputs → outputs) with value conservation
  • Options/warrants can be marked as exercised; double exercise is prevented
  • Funding rounds track common and preferred totals with round name and end date
  • Valuations are recorded per entity with date, value, and unit
  • Capital changes history logs every issuance, transfer, and cancellation
  • Legends are immutable and content-addressed
  • Certificates include legend text and at least one signature
  • Security type seniority ordering is configurable
  • Fractional shares are rejected when fractionalShares = false
  • Redux state stays in sync with server after cap table mutations

8. Risks

RiskImpactMitigation
Numeric precision loss in frontend JavaScriptIncorrect ownership percentagesUse string-based numeric transport; parse with decimal library on client
Transfer value mismatch (inputs ≠ outputs)Phantom shares created or destroyedServer-side validation: sum(outputs.value) must equal input holding value
Concurrent issuance creates duplicate serial numbersCertificate numbering conflictUse database sequence or serialized transaction for serial assignment
Content-addressed hash collisionWrong legend or pricing servedSHA-256 makes collision negligible; add unique constraint on hash
Legacy shareholding flag not consistently checkedIncorrect display for migrated dataCentralize legacy handling in service layer
Large cap tables degrade query performanceSlow page loadsPaginate shareholdings; index on (organization, securityType)
Missing signature on issued certificateLegally incomplete documentEnforce minimum one signature at issuance time via validation