Analytics Event Schema¶
Generated: 2025-11-22 Version: 1.0 Scope: Activation, HR profiles, Leave, Recruitment (MVP slice)
1. Taxonomy Overview¶
Event naming follows VerbNoun or NounStateChanged semantics.
All events MUST include eventVersion to allow additive evolution.
Categories: - activation. (signup, invite, activation) - user. (profile interactions) - leave. (type, accrual, request) - recruit. (job, applicant, feedback) - system.* (infrastructure, isolation tests)
2. Common Envelope¶
| Field | Type | Required | Description |
|---|---|---|---|
| eventName | string | Y | Canonical event identifier (e.g., activation.SignupStarted) |
| eventVersion | int | Y | Schema version for this event (start at 1) |
| occurredAt | ISO-8601 | Y | UTC timestamp |
| traceId | string | Y | Correlates multi-step flows |
| tenantId | string | Conditional | Present after tenant provisioning |
| userId | string | Conditional | Actor user if authenticated |
| actorRole | string | Conditional | Role context (owner, admin, employee, hiringManager) |
| source | string | Y | Origin (frontend, backend, job-accrual, batch) |
| requestId | string | Conditional | Attach for API-origin events |
| metadata | object | N | Arbitrary key-value (non-PII) |
| pii | object | N (Restricted) | Encrypted or hashed sensitive fragments (e.g., emailHash) |
PII handling: raw PII never emitted—only hashed values (SHA-256 + salt) or classification tags.
3. Event Definitions¶
3.1 Activation¶
activation.SignupStarted (v1)¶
| Field | Type | Notes |
|---|---|---|
| emailHash | string | Hashed user email |
| signupFlowVersion | string | A/B test variant |
activation.TenantProvisioned (v1)¶
| Field | Type | Notes |
|---|---|---|
| tenantId | string | Newly created tenant |
| ownerUserId | string | User who initiated provisioning |
| provisioningLatencyMs | int | Time from request to ready |
activation.InvitationCreated (v1)¶
| Field | Type | Notes | | invitationId | string | Internal ID | | invitedEmailHash | string | Hashed invitee email | | expiresAt | ISO-8601 | Expiration timestamp |
activation.InvitationAccepted (v1)¶
| Field | Type | Notes | | invitationId | string | Link back to created invite | | userId | string | New user id | | acceptanceLatencyMs | int | Time from creation to acceptance |
activation.ActivationCompleted (v1)¶
| Field | Type | Notes | | userId | string | Activated user | | profileFieldsCompletedPct | number | % required profile fields completed |
3.2 User Profile¶
user.ProfileViewed (v1)¶
| Field | Type | Notes | | profileUserId | string | Owner of profile viewed | | viewerUserId | string | Actor | | isSelf | boolean | Self vs other |
user.ProfileEdited (v1)¶
| Field | Type | Notes | | profileUserId | string | Edited profile | | editorUserId | string | Actor | | changedFields | string[] | List of field keys changed |
3.3 Custom Field¶
user.CustomFieldAdded (v1)¶
| Field | Type | Notes | | fieldId | string | New field identifier | | fieldType | string | text|number|date|dropdown | | required | boolean | Required flag |
3.4 Leave¶
leave.LeaveTypeCreated (v1)¶
| Field | Type | Notes | | leaveTypeId | string | Identifier | | accrualRateHoursPerMonth | number | Basic accrual |
leave.AccrualRun (v1)¶
| Field | Type | Notes | | jobId | string | Accrual job execution id | | employeesProcessed | int | Count | | durationMs | int | Total job duration | | success | boolean | Outcome |
leave.LeaveRequestCreated (v1)¶
| Field | Type | Notes | | leaveRequestId | string | Identifier | | employeeId | string | Requesting employee | | leaveTypeId | string | Type | | startDate | ISO-8601 | Start | | endDate | ISO-8601 | End | | hoursRequested | number | Requested hours |
leave.LeaveRequestStatusChanged (v1)¶
| Field | Type | Notes | | leaveRequestId | string | Identifier | | oldStatus | string | Previous | | newStatus | string | New | | changedByUserId | string | Actor |
3.5 Recruitment¶
recruit.JobPublished (v1)¶
| Field | Type | Notes | | jobId | string | Job opening | | isRemote | boolean | Remote flag | | location | string | Optional city/region |
recruit.ApplicantStageChanged (v1)¶
| Field | Type | Notes | | applicantId | string | Candidate | | jobId | string | Job reference | | oldStage | string | Previous stage | | newStage | string | New stage | | changedByUserId | string | Actor |
recruit.FeedbackAdded (v1)¶
| Field | Type | Notes | | applicantId | string | Candidate | | jobId | string | Job reference | | authorUserId | string | Feedback author | | feedbackLength | int | Character count (content stored elsewhere) |
3.6 System¶
system.IsolationTestExecuted (v1)¶
| Field | Type | Notes | | testId | string | Test reference | | passed | boolean | Outcome | | durationMs | int | Duration |
4. Versioning Strategy¶
- Minor additive fields bump
eventVersiononly if consumer parsing requires branching. - Removed/renamed fields require new eventName suffix (e.g., ActivationCompletedV2).
- Deprecation tracked in a CHANGELOG under
/docs/analytics/CHANGELOG.md(to be created when needed).
5. Privacy & Compliance¶
- Hash emails with salted SHA-256; salt rotated quarterly.
- Avoid sending full PII in events; for diagnostics use metadata with classification tags (e.g.,
"containsPII": false). - Retention: raw event store 180 days, aggregated metrics indefinite.
6. Quality Rules¶
- Event emission must not block request: fire-and-forget or async queue.
- If emission fails, record fallback log with same envelope minus fields.
- Validate event schema via JSON Schema in CI (future task).
7. Sample JSON (activation.InvitationCreated v1)¶
{
"eventName": "activation.InvitationCreated",
"eventVersion": 1,
"occurredAt": "2025-11-22T10:15:30Z",
"traceId": "trace-123",
"tenantId": "ten-456",
"userId": "usr-789",
"actorRole": "admin",
"source": "backend",
"invitationId": "inv-001",
"invitedEmailHash": "sha256:abcdef...",
"expiresAt": "2025-11-25T10:15:30Z",
"metadata": {"uiVersion": "1.0.3"}
}
8. Implementation Checklist¶
- JSON Schemas created per event.
- Emission library wrapper with envelope auto-population.
- Error handling & retry strategy defined.
- Dashboard queries validated (activation funnel, stage conversion).
- Data retention job scheduled.
9. Open Questions¶
- Need separate event for magic link validation pre-activation? (
activation.MagicLinkValidated) - Include environment (dev/stage/prod) explicitly or infer from infrastructure metadata?
- Standardize correlation across message broker vs HTTP (same traceId propagation)?
Document Version: 1.0