SessionEvent

SessionEvent is an append-only time-series log of Firebase auth token issuances, recording one row per distinct (membership, token_issued_at) tuple. It is written exclusively by the Firebase authentication strategy at request time and is the canonical source for WAU/MAU, retention, stickiness, and engagement-bucketing analytics. Each row is tied to a Membership (which in turn scopes a user to a workspace); there is no workspace FK on the row itself. The table was renamed from login_events in migration 20260511113135 and carries no soft-delete column โ€” it is explicitly append-only.

NamingValue
ObjectSessionEvent
Resource type (JSON:API type)session_event
Collection / records rootโ€” (not a records root)
REST base/v1/session-events
Entity classSessionEvent

Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.

API operations

OperationMethod & pathStatus
ListGET /v1/session-events๐ŸŸก Planned
RetrieveGET /v1/session-events/{id}๐ŸŸก Planned
CreatePOST /v1/session-events๐ŸŸก Planned
UpdatePATCH /v1/session-events/{id}๐ŸŸก Planned
DeleteDELETE /v1/session-events/{id}๐ŸŸก Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
session_event_iduuid (๐Ÿ”’ system)โœ… Yesunique; default gen_random_uuid()โ€”Public stable identifier for this session event. Generated server-side via gen_random_uuid(); never supplied by the caller.
token_issued_attimestamptz (๐Ÿ”’ system)โœ… YesNOT NULL; composite UNIQUE with membership_pk (session_events_membership_pk_token_issued_at_unique); indexed DESC (session_events_membership_pk_token_issued_at_desc_idx, session_events_token_issued_at_desc_idx)โ€”The decoded.iat of the Firebase ID token, expressed as a timestamp. Identical for every API request served by the same 1-hour token, making this the structural dedup key. Concurrent inserts for the same (membership, token_issued_at) silently collapse to one row.
event_typetext (๐Ÿ”’ system)โœ… YesNOT NULL; DEFAULT 'login'; CHECK event_type IN ('login','refresh') โ€” constraint name session_events_event_type_checklogin | refreshDiscriminates fresh sign-ins from silent token refreshes. 'login' when decoded.auth_time equals decoded.iat (within clock skew โ€” user just authenticated); 'refresh' when decoded.iat > decoded.auth_time (Firebase SDK silently refreshed the token). Both are derived from the same decoded token at write time.
created_attimestamptz (๐Ÿ”’ system)โœ… YesNOT NULL; set on insert via onCreate hookโ€”Wall-clock timestamp of when the row was inserted. Distinct from token_issued_at (which is the token's iat). Legacy rows backfilled token_issued_at from this column during the rename migration.

Relationships

NameTypeRequiredDescription
membershipto-one (ManyToOne)โœ… YesThe Membership row that authenticated. Identifies both the user (Person) and the workspace scope. The FK column membership_pk carries the composite unique constraint with token_issued_at.

System-computed

  • session_event_id โ€” generated via gen_random_uuid() DB default; also initialised in-process via randomUUID() as the ORM default value
  • created_at โ€” set by MikroORM onCreate hook to new Date() at insert time; never updated
  • token_issued_at โ€” sourced from decoded Firebase ID token iat field by firebase.strategy.ts; NOT user-supplied
  • event_type โ€” derived from decoded.auth_time vs decoded.iat comparison in firebase.strategy.ts; default 'login'
  • Dedup on (membership_pk, token_issued_at) โ€” enforced at the DB layer by the unique index; SessionEventRepository.recordIfNew catches SQLSTATE 23505 with constraint name session_events_membership_pk_token_issued_at_unique for silent dedup without swallowing unrelated unique violations
  • No deleted_at โ€” the table is append-only by design; soft-delete does not apply to this entity

Example

{
  "data": {
    "type": "session_event",
    "id": "a3c7f2e1-84bb-4d2a-b910-1e5c2f3d4a5b",
    "attributes": {
      "session_event_id": "a3c7f2e1-84bb-4d2a-b910-1e5c2f3d4a5b",
      "token_issued_at": "2026-06-02T09:14:00.000Z",
      "event_type": "login",
      "created_at": "2026-06-02T09:14:01.123Z"
    },
    "relationships": {
      "membership": {
        "data": { "type": "membership", "id": "d1e2f3a4-5b6c-7d8e-9f0a-b1c2d3e4f5a6" }
      }
    }
  }
}
Source: apps/api/src/database/entities/SessionEvent.ts ยท domain: platform ยท tier: Activity