Add Jitsi reports to IDAA

This commit is contained in:
Scott Idem
2026-05-05 14:02:52 -04:00
parent 146682a30b
commit 0b04ce7c0c
3 changed files with 737 additions and 225 deletions

View File

@@ -85,8 +85,8 @@ src/routes/idaa/
│ │ └── [event_id]/
│ │ ├── +page.svelte # Meeting detail page — renders view OR edit based on session flag
│ │ └── +page.ts
── video_conferences/ # Jitsi video conference integration
└── jitsi_reports/ # External Jitsi reporting
── video_conferences/ # Jitsi video conference integration
└── jitsi_reports/ # Jitsi meeting activity log report (trusted_access only)
```
> **Note:** Recovery Meetings has **two UI entry points**:
@@ -183,6 +183,12 @@ fetch(`${api_root_url}/customers/${uuid}`, {
- **`novi_bb_base_url`**: (optional) Base URL used to build links for Bulletin Board notification emails.
- **`jitsi_exclude_names`**: (optional) Array of display name strings to exclude from Jitsi Reports.
Used to hide known staff and test accounts from the activity report so participant counts and lists
reflect real member activity only. Names are matched case-insensitively against `final_participants[].displayName`.
Example: `["Scott I.", "Michelle V.", "Brie K."]`. The filter is applied before the "Real meetings only"
threshold check — a session with only excluded participants is treated as having 0 real participants.
- **Email config values** (`noreply_email`, `noreply_name`, `admin_email`, `admin_name`): used by functions that send notification emails (BB posts, comments, recovery meetings).
### Stores / runtime fields set by verification
@@ -446,6 +452,94 @@ Moderation permissions are controlled by `novi_jitsi_mod_li` in the IDAA store.
---
## Module 5: Jitsi Reports
**Route:** `/idaa/jitsi_reports/`
**Access:** `trusted_access` or `novi_verified` — same gate as the rest of `(idaa)/`
**Data source:** `activity_log` table — `jitsi_meeting_event` and `jitsi_meeting_stats` log types
**Library function:** `qry__jitsi_report()` in `src/lib/ae_reports/reports_functions.ts`
An admin/staff reporting tool that aggregates raw Jitsi activity logs into human-readable meeting sessions. It is **not** a member-facing page — IDAA members do not see it.
### View Modes
Two display modes, toggled via a button in the page header:
| Mode | Description |
| --- | --- |
| **Grouped by Room** (default) | One collapsible section per `room_name`. Each section contains a compact table: Date / Time / Duration / Attendees / Participant List. Mirrors the output of the offline Python script (`create_jitsi_report.py`). |
| **Flat List** | Original card-per-session accordion layout. Better for drilling into event timelines and raw participant lists. |
Both modes use the same filtered data set — switching views does not reset filters.
### Filters
| Filter | Default | Logic |
| --- | --- | --- |
| **Real meetings only** | off | Show only sessions where `real_participant_count >= 2` OR `duration > 5 min`. Applied **after** staff exclusion (see below). |
| **Min. Participants** | 0 | Minimum `real_participant_count` to display a session. |
| **Room Name** | (empty) | Case-insensitive substring match against `room_name`. |
| **From / To** | (empty) | Date range applied to `start_time`. "To" date includes the full end of day. |
A "Reset Filters" button appears whenever any filter is non-default.
### Staff / Test Exclusion
**Problem:** Staff and test accounts (Scott, Michelle, Brie) join real member meetings for setup, testing, and tech support. Their presence inflates participant counts and pollutes the participant list.
**Solution:** A configurable exclusion list in `site_cfg_json`:
```json
{ "jitsi_exclude_names": ["Scott I.", "Michelle V.", "Brie K."] }
```
**How it works (client-side only, no backend change needed):**
1. On load, the page reads `$ae_loc.site_cfg_json?.jitsi_exclude_names` (string array, defaults to `[]`).
2. For every session, a `real_participants` derived list is computed by filtering `final_participants` against the exclusion list (case-insensitive display name match).
3. `real_participant_count = real_participants.length` — this count drives all filters, stats, and the participant list column in grouped view.
4. The raw `final_participant_count` from the API is never shown to the user once an exclusion list is configured.
**Why display-name matching (not Novi UUID):** Jitsi participant data (`meta_json.participants`) only contains `displayName` and `role` — the Novi UUID is not passed through to the activity log. UUID-based exclusion would require a Jitsi config change plus a backend schema update and is deferred. Display names for OSIT staff are stable and controlled.
### Summary Stats
Shown above the meeting list when data is loaded. Stats reflect the **filtered + exclusion-applied** view:
- **Meetings Shown** — count of sessions passing all filters
- **Total Participants** — sum of `real_participant_count` across all shown sessions
- **Avg Duration** — mean session duration (HH:MM:SS)
- **Total Duration** — sum of all session durations (HH:MM:SS)
In grouped view, each room header also shows its own subtotals (meeting count, unique participants).
### Jitsi URL Builder
Collapsible panel, visible to `trusted_access` users only. Generates properly-formatted Jitsi meeting URLs for IDAA rooms. Component: `ae_idaa_comp__jitsi_url_builder.svelte`.
### Export
CSV and JSON export buttons in the page header export the **currently filtered + exclusion-applied** data set.
### Room Name Fragmentation
The same logical meeting can appear as multiple rooms (e.g. `IDAA-BIPOC-Meeting`, `IDAA-BIPOC-Meeting-2026`, `IDAA-BIPOC-Meeting-March-31`) because the Jitsi URL builder appends a date suffix to generate unique per-session room names. In grouped view, these appear as separate groups. A future normalization pass (strip trailing date suffixes) could optionally merge them — not implemented yet.
### Data Flow
```text
activity_log table
└── qry__jitsi_report() # reports_functions.ts — fetches + aggregates by meeting_id
└── MeetingReport[] # { meeting_id, room_name, start_time, final_duration,
# final_participants, final_participant_count, events }
└── jitsi_reports/+page.svelte
├── apply exclusion list → real_participants / real_participant_count
├── apply filters → meetings_filtered
├── derive grouped view → Map<room_name, MeetingReport[]>
└── render flat or grouped
```
---
## State Management (`ae_idaa_stores.ts`)
Four stores manage all IDAA state:
@@ -582,6 +676,7 @@ ae_loc.idaa_loc = { novi_uuid: 'test-uuid-value', ... };
| Bulletin Board | ❌ None | Priority — most sensitive module |
| Recovery Meetings | ✅ Substantial | `tests/idaa_recovery_meeting_edit.test.ts` — form render, field interactions, PATCH payload verification (all sections), real backend save, creation linkage (Novi UUID in POST body) |
| Video Conferences | ❌ None | Jitsi complexity, lower priority |
| Jitsi Reports | ❌ None | Admin-only tool; lower privacy risk than member modules |
**Pending:** BB Post and Post Comment creation linkage tests (pattern established in Recovery Meetings test).
@@ -634,4 +729,4 @@ ae_loc.idaa_loc = { novi_uuid: 'test-uuid-value', ... };
---
**Document Status:** ✅ Current
**Last Verified:** 2026-04-07updated for Novi UUID triple-linkage enforcement, staff editing rules, Contact 1 convention, test coverage
**Last Verified:** 2026-05-05added Module 5: Jitsi Reports (grouped view, real-meetings filter, staff exclusion via `jitsi_exclude_names`); fixed route tree (`jitsi_reports/` is inside `(idaa)/`)