Skip to main content

SPEC 022 — Activity Tracking

FieldValue
StatusDRAFT
PriorityP1 — Core Product
Backendequa-server/modules/activity/
Frontendequa-web/src/modules/actions/

1. Feature Purpose

Activity Tracking provides a comprehensive audit trail and action management system for organizations on the Equa platform. It captures three categories of activity: discrete user actions (e.g. cap table edits, document uploads), structured event logs for analytics and compliance, and organizational tasks (e.g. stock option exercises, compliance to-dos). Together these give admins visibility into what happened, when, and by whom — and let stakeholders act on pending items.

2. Current State (Verified)

2.1 Actions

DetailValue
EntityActions — records discrete user actions within an organization
ScopeOrganization-level; each action is tied to a user and an action type
UsagePowers the organization activity feed and feature-request tracking

2.2 Event Logs

DetailValue
EntityEventLogs — generic event journal
Payloaddata JSON column holds arbitrary event-specific details
UsageAudit trail, analytics pipeline input, compliance reporting

2.3 Tasks

DetailValue
EntityTasks — tracks actionable items (e.g. option exercises, compliance steps)
Composite PK(entity, type, status) — one active task per entity-type combination
TypesTaskType enum (e.g. exercise option, sign agreement, file compliance)
StatusesTaskStatus enum (e.g. pending, in_progress, completed, cancelled)

2.4 Exercise Option Tracking

DetailValue
EntityTasksExerciseOption — captures exercise details for stock option tasks
RelationshipLinked to a Task row; stores the selected option hash and share count

2.5 Backend and Frontend

ComponentPath
Backend moduleequa-server/modules/activity/
Endpointsequa-server/modules/api/src/endpoints/activity-endpoints.ts
Frontend moduleequa-web/src/modules/actions/

3. Data Model

Actions

ColumnTypeConstraints
iduuidPK
organizationuuidFK → Organizations, NOT NULL
typeuuidFK → action type definition, NOT NULL
useruuidFK → Users, NOT NULL
createdAttimestampDEFAULT now()

EventLogs

ColumnTypeConstraints
iduuidPK
typevarcharNOT NULL — event type identifier (e.g. cap_table.updated, document.uploaded)
useruuidFK → Users, nullable (null for system-generated events)
organizationuuidFK → Organizations, NOT NULL
datajsonnullable — event-specific payload
createdAttimestampDEFAULT now()

Tasks

ColumnTypeConstraints
entityuuidComposite PK part — the target entity (e.g. grant ID, agreement ID)
typeTaskTypeComposite PK part — enum value identifying the task category
statusTaskStatusComposite PK part — enum value for current state
createdAttimestampDEFAULT now()
updatedAttimestampnullable

TasksExerciseOption

ColumnTypeConstraints
iduuidPK
optionHashNOT NULL — identifies the specific option grant
sharesnumericNOT NULL — number of shares being exercised

4. API Endpoints

MethodPathAuthDescription
GET/api/v1/organizations/:id/actionsYesList organization actions (paginated, filterable by type and user)
POST/api/v1/organizations/:id/actionsYesRecord a new action
GET/api/v1/organizations/:id/actions/:actionIdYesGet action details
GET/api/v1/organizations/:id/eventsYesList event log entries (paginated, filterable by type and date range)
GET/api/v1/organizations/:id/tasksYesList tasks (filterable by type and status)
POST/api/v1/organizations/:id/tasksYesCreate a new task
PUT/api/v1/organizations/:id/tasks/:entity/:typeYesUpdate task status
GET/api/v1/organizations/:id/tasks/exercisesYesList exercise option tasks with details
POST/api/v1/organizations/:id/tasks/exercisesYesCreate an exercise option task

5. Frontend Components

ComponentPathDescription
ActionsPageactions/ActionsPage.tsxOrganization activity feed with filters for action type and user
ActionItemactions/components/ActionItem.tsxSingle action row with timestamp, user avatar, and description
TaskListactions/components/TaskList.tsxPending tasks list with status badges and action buttons
ExerciseOptionFormactions/components/ExerciseOptionForm.tsxForm for submitting stock option exercise requests
FeatureRequestFormactions/components/FeatureRequestForm.tsxForm for submitting feature requests (tracked as actions)
ActivityTimelineactions/components/ActivityTimeline.tsxChronological timeline view of all organization activity

Frontend Behavior

  • Activity feed — Displays a reverse-chronological list of actions with infinite scroll pagination.
  • Filter bar — Users can filter by action type, user, and date range; filters update the URL query parameters.
  • Task status transitions — Status changes trigger optimistic UI updates with rollback on API failure.
  • Exercise option flow — The exercise form validates share counts against the grant’s vested/available balance before submission.
  • Real-time updates — Activity feed does not auto-refresh; users pull to refresh or navigate away and back.

6. Business Rules

  1. Immutable actions — Once recorded, actions cannot be edited or deleted; they serve as an audit trail.
  2. Immutable event logs — EventLog entries are append-only; no updates or deletes are permitted.
  3. Composite task uniqueness — The (entity, type, status) composite primary key ensures only one active task of a given type exists per entity. Status transitions create new rows rather than updating in place.
  4. Task status machine — Tasks follow a defined state machine: pending → in_progress → completed or pending → cancelled. Backward transitions are not allowed.
  5. Exercise validationTasksExerciseOption.shares must not exceed the vested and unexercised balance of the referenced option grant.
  6. Organization scoping — All activity queries are scoped to the requesting user’s organization; cross-org queries are not supported.
  7. System events — EventLogs with user = null represent system-generated events (e.g. scheduled jobs, automated processes).
  8. Event type conventions — Event types follow resource.action naming (e.g. cap_table.updated, document.uploaded, member.invited).
  9. Action type registry — Action types are defined by UUID references; new types must be registered before use.
  10. Feature requests — Feature request actions are a special action type that collects user feedback; they appear in the admin panel (SPEC 019) for review.

7. Acceptance Criteria

  • Organization activity feed displays actions in reverse chronological order
  • Actions can be filtered by type, user, and date range
  • New actions are recorded with correct user, organization, and type references
  • Actions are immutable — no edit or delete endpoints exist
  • Event logs capture structured event data with correct type and payload
  • Event logs are append-only with no update or delete capability
  • Tasks display with correct status badges (pending, in_progress, completed, cancelled)
  • Task status transitions follow the defined state machine
  • Backward status transitions are rejected by the API
  • Exercise option tasks validate share count against available vested balance
  • Exercise option form prevents submission when shares exceed available balance
  • Feature requests are recorded as actions and visible in admin panel
  • All activity queries are scoped to the requesting user’s organization
  • Pagination works correctly for large activity feeds (100+ items)

8. Risks

RiskImpactMitigation
High-volume event logging on active organizationsDatabase bloat, slow queriesAdd time-based partitioning on EventLogs; archive old entries to cold storage
Composite PK on Tasks prevents status historyCannot audit task state transitions over timeLog status changes to EventLogs before updating Tasks; consider adding a TaskHistory table
Exercise validation race conditionTwo concurrent exercises exceed available sharesUse database-level locking (SELECT FOR UPDATE) on the option grant during exercise creation
No real-time feed updatesUsers see stale activity dataDocument manual refresh requirement; consider WebSocket or polling in future iteration
Action type registry requires pre-registrationFriction when adding new action typesProvide a seed script; validate type UUIDs at startup
EventLogs.data is unstructured JSONInconsistent payloads, difficult queryingDefine JSON schemas per event type; validate payloads before insert
Cross-org data leak via malformed querySensitive activity visible to wrong organizationEnforce organization scoping in repository layer; add integration tests for isolation
Large exercise option numeric valuesPrecision loss on share countsUse numeric type (arbitrary precision); validate reasonable bounds on input