# Member usage analytics

## What is measured

Authenticated Nuxt usage is grouped into OAuth login sessions. The frontend sends a heartbeat every 30 seconds while the site is visible, focused, and the user has interacted within the last five minutes.

The report contains:

- user and member company;
- last login in each month;
- number of logins in each month;
- average active session duration, formatted as minutes:seconds.

OAuth token refreshes, page reloads, and opening another browser tab do not create another login record. A new record is created after the user logs out and authenticates again. IP addresses, user agents, visited paths, query strings, and page content are not stored.

## Deploy

Run the database migration in the Laravel application:

```bash
php artisan migrate
```

Deploy both applications so the Laravel API and the Nuxt plugin become active at the same time. Existing historical activity cannot be reconstructed; collection begins after deployment.

## Export

In the Laravel backoffice, open **Users**. Choose the start and end month next to the statistics icon, then click the icon to download the XLSX report. Both months are inclusive full calendar months, e.g. selecting July to September always covers 01 July 00:00 through 30 September 23:59.

The endpoint can also be opened directly by an administrator with `users.view` permission:

```text
/admin/member-usage/export?from=2026-08&to=2026-08
```

Months use the Laravel application timezone (`Y-m` format). If omitted, the report covers the current month. The report contains one row per user per calendar month in the selected range, ordered by month and login count, and can be sorted or filtered further in Excel.

- **Last login in month**: the most recent login timestamp within that calendar month. It never reflects logins outside the selected months.
- **Logins in month**: the number of logins that occurred within that calendar month, counting only logins inside the selected range. Because whole months are always used, a month is never partially counted.
- **Average session duration**: the average across sessions started in that calendar month only.

## Accuracy and privacy

- Time from hidden, unfocused, or idle tabs is excluded.
- A failed heartbeat can make active time lower than the real value; it is never extrapolated from OAuth token lifetime.
- Each heartbeat is capped at 60 seconds server-side.
- The export is restricted to authenticated backoffice users with `users.view` permission because it contains personal usage data.
- Define a retention period appropriate to the organization's privacy policy. For example, sessions older than 12 or 24 months can be deleted with a scheduled Laravel command.
