> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SessionEvent

> SessionEvent is an append-only time-series log of Firebase auth token issuances, recording one row per distinct (membership, token_issued_at) tuple

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.

| Naming                          | Value                             |
| ------------------------------- | --------------------------------- |
| Object                          | SessionEvent                      |
| Resource type (JSON:API `type`) | `session_event`                   |
| Collection / records root       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/session-events`              |
| Entity class                    | `SessionEvent`                    |

<Note>
  **Internal object.** Not currently exposed on the public REST API. The operations below describe the intended contract.
</Note>

## API operations

| Operation | Method & path                    | Status     |
| --------- | -------------------------------- | ---------- |
| List      | `GET /v1/session-events`         | 🟡 Planned |
| Retrieve  | `GET /v1/session-events/{id}`    | 🟡 Planned |
| Create    | `POST /v1/session-events`        | 🟡 Planned |
| Update    | `PATCH /v1/session-events/{id}`  | 🟡 Planned |
| Delete    | `DELETE /v1/session-events/{id}` | 🟡 Planned |

## Data model

### Attributes

| Field              | Type                    | Required | Constraints                                                                                                                                                                                                                              | Allowed values   | Description                                                                                                                                                                                                                                                                                                          |
| ------------------ | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| session\_event\_id | uuid (🔒 system)        | ✅ Yes    | unique; 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\_at  | timestamptz (🔒 system) | ✅ Yes    | NOT 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\_type        | text (🔒 system)        | ✅ Yes    | NOT NULL; DEFAULT 'login'; CHECK event\_type IN ('login','refresh') — constraint name session\_events\_event\_type\_check                                                                                                                | login \| refresh | Discriminates 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\_at        | timestamptz (🔒 system) | ✅ Yes    | NOT 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

| Name       | Type               | Required | Description                                                                                                                                                                                    |
| ---------- | ------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| membership | to-one (ManyToOne) | ✅ Yes    | The 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

```json theme={null}
{
  "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" }
      }
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/SessionEvent.ts` · domain: platform · tier: Activity</sub>
