toga-ai 1.0.68 → 1.0.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/knowledge/1.0/apps/togadesk/INDEX.md +1 -0
- package/knowledge/1.0/apps/togadesk/architecture.md +87 -0
- package/knowledge/1.0/apps/togaview/INDEX.md +1 -0
- package/knowledge/1.0/apps/togaview/architecture.md +67 -0
- package/knowledge/2.0/apps/worker2/INDEX.md +1 -0
- package/knowledge/2.0/apps/worker2/features/teams-transcript-export.md +120 -0
- package/knowledge/INDEX.md +3 -3
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
|
+
| [TogaDesk Architecture](architecture.md) | TogaDesk is the staff-facing support desk (analysts work at `/desk/`). | desk/includes/classes/class.ticket.php, desk/includes/controllers/actions.php, desk/api/resources/tickets.php, crons/tickets.php |
|
|
5
6
|
| [SMB Contract Editing & the clientMspId Corruption Trap](features/smb-contract-editing.md) | The SMB contracts page (`/desk/?route=toga/smbcontracts&togaClientId=<id>`) edits `TOGA_*.SMBContracts` rows via a modal. | desk/template/modals/toga/smbcontracts/smbContract.php, desk/includes/controllers/modals/toga/smbcontracts/smbContract.php, desk/includes/controllers/actions/toga/smbcontracts/smbContract.php, desk/includes/controllers/actions/toga/smbcontracts/edit.php |
|
|
6
7
|
| [Ticket Lifecycle (class.ticket.php)](features/ticket-lifecycle.md) | All TogaDesk ticket creation and reply handling funnels through `Ticket` in `desk/includes/classes/class.ticket.php`. | desk/includes/classes/class.ticket.php, desk/includes/controllers/actions.php, desk/api/resources/tickets.php, crons/tickets.php, desk/includes/controllers/actions/tickets/merge.php |
|
|
7
8
|
| [Standalone PHP Test Script Bootstrap (TogaDesk)](workflows/standalone-test-scripts.md) | How to write a standalone CLI PHP script that bootstraps the TogaDesk framework for read-only testing of desk classes (e.g. | |
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TogaDesk Architecture
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: togadesk
|
|
5
|
+
project: TogaDesk
|
|
6
|
+
client: shared
|
|
7
|
+
type: architecture
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-12
|
|
10
|
+
owners: ["mhammontree"]
|
|
11
|
+
files:
|
|
12
|
+
- desk/includes/classes/class.ticket.php
|
|
13
|
+
- desk/includes/controllers/actions.php
|
|
14
|
+
- desk/api/resources/tickets.php
|
|
15
|
+
- crons/tickets.php
|
|
16
|
+
related:
|
|
17
|
+
- 1.0/apps/togaview/architecture.md
|
|
18
|
+
- 1.0/apps/togadesk/features/ticket-lifecycle.md
|
|
19
|
+
- 1.0/apps/togadesk/features/smb-contract-editing.md
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
TogaDesk is the staff-facing support desk (analysts work at `/desk/`). It is a framework 1.0
|
|
24
|
+
(`App_`) app bootstrapped from the `library` core (`_.php`). The on-disk repo root contains
|
|
25
|
+
legacy top-level code; **the live application root is `desk/`** — e.g. the live
|
|
26
|
+
`class.ticket.php` is `desk/includes/classes/class.ticket.php`, while the root
|
|
27
|
+
`includes/classes/class.ticket.php` is an ancient variant that must never be extended.
|
|
28
|
+
|
|
29
|
+
## System topology
|
|
30
|
+
| System | Serves | DB connections |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| TogaDesk (`desk/`) | Staff/analysts | `db_togadesk` (TOGaDeskSupport), `db_toga` (TOGA), `db_client_aig`, per-client by name |
|
|
33
|
+
| TogaView (sibling repo) | Clients at `<client>.togaview.com` | same cluster, same link names |
|
|
34
|
+
|
|
35
|
+
- **TogaDesk and TogaView share the `TOGaDeskSupport` database** — tickets, clients,
|
|
36
|
+
contacts, departments, ClientMsp all live there. A change to ticket data semantics affects
|
|
37
|
+
both apps.
|
|
38
|
+
- All legacy databases (TOGaDeskSupport, TOGA, TOGA_*, RetailServices) are on the same MySQL
|
|
39
|
+
cluster, so cross-schema joins (e.g. `TOGaDeskSupport.ClientMsp` from a `db_toga`
|
|
40
|
+
connection) work and are used everywhere.
|
|
41
|
+
- `db_X` link names resolve generically to `[database_X]` sections in the per-environment
|
|
42
|
+
`config.<env>.ini`. Environment comes from the `ENVIRONMENT` env var — it defaults to
|
|
43
|
+
`worker` if unset, so a CLI script without it fails looking for `config.worker.ini`.
|
|
44
|
+
|
|
45
|
+
## The MSP data model (the core of everything)
|
|
46
|
+
```
|
|
47
|
+
TOGaDeskSupport.clients (togadesk client)
|
|
48
|
+
▲ clientId
|
|
49
|
+
TOGaDeskSupport.ClientMsp (id, clientId, type ENUM 'msp'|'reseller',
|
|
50
|
+
▲ ticketDepartmentId, companyName)
|
|
51
|
+
│ clientMspId
|
|
52
|
+
TOGaDeskSupport.ClientMspContacts(togadeskContactId → TOGaDeskSupport.contacts.id)
|
|
53
|
+
= the people who get MSP logins in togaview
|
|
54
|
+
|
|
55
|
+
TOGA.Clients (toga client registry; togadeskClientId, databaseName)
|
|
56
|
+
TOGA_<databaseName>.SMBContracts (clientMspId → ClientMsp.id, mainContactId,
|
|
57
|
+
serviceSeats, dateContractEnd)
|
|
58
|
+
TOGA_*.SMBContractItems (seats; serviceRequestId NULL = open seat)
|
|
59
|
+
TOGA_*.ServiceRequests (contactId → Contacts.id)
|
|
60
|
+
TOGA_*.Contacts (customerId → Customers.id)
|
|
61
|
+
TOGA_*.Customers (the managed business)
|
|
62
|
+
```
|
|
63
|
+
Invariants:
|
|
64
|
+
- An MSP's "customers" are **TOGA-side `Customers` rows**, NOT togadesk clients. All of an
|
|
65
|
+
MSP's tickets carry the MSP's own `tickets.clientid`.
|
|
66
|
+
- A togadesk client can own **multiple ClientMsp rows** (clients 18 and 26 do). Never assume
|
|
67
|
+
exactly one.
|
|
68
|
+
- **Multiple TOGA clients can share one TOGA_* database** (e.g. TOGA clients 9 and 20 both
|
|
69
|
+
use `TOGA_True`). Any page listing `SMBContracts` for a `togaClientId` lists every tenant's
|
|
70
|
+
contracts in that database — the root of the clientMspId corruption bug.
|
|
71
|
+
- `tickets_departments.clientId` maps support departments to a togadesk client; a client can
|
|
72
|
+
have several, but `ClientMsp.ticketDepartmentId` holds only ONE — never build
|
|
73
|
+
department-scoping logic on it.
|
|
74
|
+
|
|
75
|
+
## Key flows
|
|
76
|
+
- All ticket creation/replies funnel through `Ticket` (`desk/includes/classes/`):
|
|
77
|
+
staff UI (`actions.php`), API (`desk/api/resources/tickets.php`), email intake
|
|
78
|
+
(`crons/tickets.php` IMAP poll → `emailToTicket()`), merge. See ticket-lifecycle feature doc.
|
|
79
|
+
- SMB contract administration edits TOGA_* `SMBContracts` from `/desk/?route=toga/smbcontracts`.
|
|
80
|
+
See smb-contract-editing feature doc.
|
|
81
|
+
|
|
82
|
+
## Key decisions
|
|
83
|
+
- `Ticket::deriveCustomerId()` (June 2026) resolves `tickets.customerid` at creation so
|
|
84
|
+
staff/API/email tickets are visible in the TogaView MSP portal; it returns null rather than
|
|
85
|
+
guess when ambiguous, and swallows (logs) exceptions so email intake is never blocked.
|
|
86
|
+
- DB access for tooling: legacy cluster via the TOGa Database Integration MCP, environment
|
|
87
|
+
`legacy`; schemas `TOGaDeskSupport`, `TOGA`, `TOGA_True`, etc.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
|
+
| [TogaView Architecture](architecture.md) | TogaView is the client-facing support portal, served per client at `<client>.togaview.com`. | index.php, _/app/framework.php, mvc/login/post.php |
|
|
5
6
|
| [TogaView Login Flows & Session Variables](features/login-flows.md) | `mvc/login/post.php` tries login flows in order; the first match wins. | mvc/login/post.php, _/app/framework.php |
|
|
6
7
|
| [MSP Dashboard & Ticket Visibility Rules](features/msp-dashboard.md) | Why tickets "disappear" in the TogaView client portal: different pages scope tickets **differently**, and the MSP pages depend on `tickets.customerid` and `SMBC | common/togaview/msp_dashboard.php, mvc/msp_client_dashboard, mvc/enterprise_dashboard, mvc/support/support.php |
|
|
7
8
|
| [Ticket Detail Page Security (common/togaview/ticket.php)](features/ticket-detail-page.md) | `common/togaview/ticket.php` is the ticket detail page for nearly ALL hosts — only towfoundation/newcenturyholdingsllc have their own variants; every other clie | common/togaview/ticket.php |
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TogaView Architecture
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: togaview
|
|
5
|
+
project: TogaView
|
|
6
|
+
client: shared
|
|
7
|
+
type: architecture
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-12
|
|
10
|
+
owners: ["mhammontree"]
|
|
11
|
+
files:
|
|
12
|
+
- index.php
|
|
13
|
+
- _/app/framework.php
|
|
14
|
+
- mvc/login/post.php
|
|
15
|
+
related:
|
|
16
|
+
- 1.0/apps/togadesk/architecture.md
|
|
17
|
+
- 1.0/apps/togaview/features/login-flows.md
|
|
18
|
+
- 1.0/apps/togaview/features/msp-dashboard.md
|
|
19
|
+
- 1.0/apps/togaview/features/ticket-detail-page.md
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
TogaView is the client-facing support portal, served per client at `<client>.togaview.com`.
|
|
24
|
+
Framework 1.0 (`App_`) app bootstrapped from the `library` core (`_.php`). It shares the
|
|
25
|
+
`TOGaDeskSupport` database with TogaDesk (tickets, clients, contacts, departments, ClientMsp)
|
|
26
|
+
— see the TogaDesk architecture doc for the cluster topology and the full MSP data model;
|
|
27
|
+
those invariants apply here unchanged.
|
|
28
|
+
|
|
29
|
+
## Page routing (stylePath model)
|
|
30
|
+
`index.php → App_Framework_TogaView::renderIndex()` (in `_/app/framework.php`):
|
|
31
|
+
|
|
32
|
+
1. A giant `switch ($_SERVER['HTTP_HOST'])` sets `$_SESSION['stylePath']` (and sometimes
|
|
33
|
+
`$_SESSION['host']`). Client subdomains are **hardcoded** — a new client subdomain must be
|
|
34
|
+
added to this switch (e.g. `craftex.togaview.com` → stylePath `togatechnology`, no `host`).
|
|
35
|
+
2. Page files: `mvc/<page>/get.php` typically resolves the template as:
|
|
36
|
+
- host in `HOSTS_USING_TOGA_TECH_STYLE` (= `['towfoundation','newcenturyholdingsllc']`)
|
|
37
|
+
→ `common/<host>/<page>.php`;
|
|
38
|
+
- else `common/<stylePath>/<page>.php` if it exists;
|
|
39
|
+
- else **fallback `common/togaview/<page>.php`** — the generic implementation.
|
|
40
|
+
3. `common/togatechnology/` has only header/footer/sidebar — so most clients run the
|
|
41
|
+
**generic** `common/togaview/*.php` pages. Only towfoundation, newcenturyholdingsllc (and
|
|
42
|
+
partially rumcsi via inline branches) have real page variants.
|
|
43
|
+
|
|
44
|
+
**Implication:** a change to `common/togaview/<page>.php` affects nearly every client at
|
|
45
|
+
once; a per-client behavior change belongs in a host/stylePath variant or an inline branch.
|
|
46
|
+
|
|
47
|
+
## Session / identity model
|
|
48
|
+
Login (`mvc/login/post.php`) tries flows in order — Retail, MSP contact, SMB admin, end user,
|
|
49
|
+
plus inline client branches (staplesprotection) and SAML clients handled in `framework.php`
|
|
50
|
+
(rumcsi, newcenturyholdingsllc). **Each flow sets a different session shape**; notably
|
|
51
|
+
staplesprotection sets `$_SESSION['email']` (not `emailAddress`) and no `togadeskClientId`.
|
|
52
|
+
Full matrix: login-flows feature doc. Any page reading session identity must tolerate the
|
|
53
|
+
divergent shapes (read `emailAddress` with `email` fallback).
|
|
54
|
+
|
|
55
|
+
## Ticket visibility
|
|
56
|
+
Each page scopes tickets differently (msp_dashboard, msp_client_dashboard,
|
|
57
|
+
enterprise_dashboard, support.php) — see the msp-dashboard feature doc. The MSP portal
|
|
58
|
+
depends on `tickets.customerid` being populated (TOGA `Customers.id`), which TogaDesk's
|
|
59
|
+
`Ticket::deriveCustomerId()` now sets at creation.
|
|
60
|
+
|
|
61
|
+
## Key decisions
|
|
62
|
+
- The ticket detail page `common/togaview/ticket.php` enforces an ownership check (clientid
|
|
63
|
+
match OR requester-email match) on both ticket view and attachment download; the email arm
|
|
64
|
+
is intentionally NOT restricted to unassigned tickets (staplesprotection and support.php
|
|
65
|
+
semantics require it). See ticket-detail-page feature doc.
|
|
66
|
+
- New client onboarding touches at minimum: the HTTP_HOST switch in `framework.php`, a login
|
|
67
|
+
flow (or SAML branch), and possibly the `smbContractSkus` whitelist in `login/post.php`.
|
|
@@ -7,3 +7,4 @@
|
|
|
7
7
|
| [Creating Worker Actions](features/creating-worker-actions.md) | How to add a new callable Worker action — a PHP class whose `public static` methods are invoked as background jobs (via webhook, cron, or `_Worker::runTask()`). | worker2/Worker/, worker2/Controller/Index.php, _underscore/Worker.php |
|
|
8
8
|
| [Elite Freshservice Sync (worker2)](features/elite-freshservice-sync.md) | `_Worker_Elite` processes Freshservice webhook events and syncs them into TOGA 2. | worker2/Worker/Elite.php, worker2/Config/dev-kmaramreddy-laptop.ini |
|
|
9
9
|
| [Monitoring Framework (Orchestrator + Child Monitors)](features/monitoring-framework.md) | A unified, DB-driven monitoring framework for business-critical data flows (Compass POs, Prudential asset imports, AIG closed claims, …). | worker2/Worker/Monitor.php, worker2/Worker/Monitors/, worker2/Worker/Notification/Email.php, dbchanges2/Core/2026-05-21 - Monitors.sql |
|
|
10
|
+
| [Teams Meeting Transcript Export](features/teams-transcript-export.md) | `_Worker_Team_Transcripts` (action `Team/Transcripts/Export`) polls Microsoft Graph for Teams meeting transcripts produced by a set of organizers, classifies ea | worker2/Worker/Team/Transcripts.php, worker2/Config/production.ini |
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Teams Meeting Transcript Export
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: worker2
|
|
5
|
+
project: Worker
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-12
|
|
10
|
+
owners: ["ajean"]
|
|
11
|
+
files:
|
|
12
|
+
- worker2/Worker/Team/Transcripts.php
|
|
13
|
+
- worker2/Config/production.ini
|
|
14
|
+
related:
|
|
15
|
+
- ../architecture.md
|
|
16
|
+
- ./creating-worker-actions.md
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Summary
|
|
20
|
+
|
|
21
|
+
`_Worker_Team_Transcripts` (action `Team/Transcripts/Export`) polls Microsoft Graph for
|
|
22
|
+
Teams meeting transcripts produced by a set of organizers, classifies each meeting by
|
|
23
|
+
client (from the meeting title), and archives the raw WebVTT to S3. Scheduled via three
|
|
24
|
+
`Core.CronJobs` rows (weekdays 10:00 / 13:00 / 17:30 Central).
|
|
25
|
+
|
|
26
|
+
## Key files / entry points
|
|
27
|
+
|
|
28
|
+
- `Worker/Team/Transcripts.php` — the whole feature (abstract class, static methods).
|
|
29
|
+
- `Config/production.ini` `[teams]` section — Entra app creds, organizer source, S3 target.
|
|
30
|
+
- `[teamsClientAliases]` config section — alias → canonical client name for classification.
|
|
31
|
+
- Ledger table `Team.TranscriptExports` (DB alias `_underscore::DB_TEAM`, core cluster).
|
|
32
|
+
|
|
33
|
+
## How it works
|
|
34
|
+
|
|
35
|
+
Per run, after acquiring a Graph client-credentials token:
|
|
36
|
+
|
|
37
|
+
1. **Resolve organizers** via `resolveConfiguredOrganizers()`:
|
|
38
|
+
- **Preferred:** the Entra security group in `[teams] organizer_group_id`. `getGroupMemberIds()`
|
|
39
|
+
calls `GET /groups/{id}/members/microsoft.graph.user?$select=id`, which returns member
|
|
40
|
+
**object-ids (GUIDs)** directly — exactly what `getAllTranscripts` requires. Uses the
|
|
41
|
+
`GroupMember.Read.All` app permission. Admins add/remove organizers in Entra with **no redeploy**.
|
|
42
|
+
- **Fallback:** the comma-separated `[teams] organizer_user_ids` list (used only when no group
|
|
43
|
+
is configured or the group resolves no members; group-lookup failures are caught so they
|
|
44
|
+
can't abort the run).
|
|
45
|
+
2. Per organizer: `getAllTranscripts(meetingOrganizerUserId='{guid}', startDateTime, endDateTime)`
|
|
46
|
+
over an incremental window (`MAX(dtCreated)` watermark from the ledger, else `now − lookbackDays`),
|
|
47
|
+
following `@odata.nextLink`.
|
|
48
|
+
3. Per new transcript (dedup by `transcriptIdentifier`): fetch meeting `subject`+`startDateTime`
|
|
49
|
+
(cached per meeting), classify, download VTT (`?$format=text/vtt`), `putObject` to S3, insert
|
|
50
|
+
ledger row.
|
|
51
|
+
|
|
52
|
+
**Classification:** case-insensitive substring match of the meeting title against active
|
|
53
|
+
`Core.Clients` names + `[teamsClientAliases]`, longest needle wins, min length 3. No match → `general`.
|
|
54
|
+
|
|
55
|
+
**S3 layout:** `s3://{[teams] s3_bucket}/{s3_prefix}{client-or-general}/{YYYY-MM-DD}/{HHMM}_{title-slug}_{shortId}.vtt`
|
|
56
|
+
(date/time in Central). Currently `toga-private/transcripts/…`.
|
|
57
|
+
|
|
58
|
+
## Data model
|
|
59
|
+
|
|
60
|
+
`Team.TranscriptExports` — unique `transcriptIdentifier` (idempotency + per-organizer watermark
|
|
61
|
+
via `MAX(dtCreated)`). Columns: `uuid, dtExported, dtCreated, dtMeeting, meetingSubject,
|
|
62
|
+
sizeBytes, classification, transcriptIdentifier, meetingIdentifier, organizerUserIdentifier, s3Key`.
|
|
63
|
+
|
|
64
|
+
## Entra app permissions (app-only / client credentials)
|
|
65
|
+
|
|
66
|
+
The dedicated Entra app **Teams-Worker2-TranscriptExport** needs, admin-consented:
|
|
67
|
+
|
|
68
|
+
- `OnlineMeetingTranscript.Read.All` — read transcript content.
|
|
69
|
+
- `OnlineMeetings.Read.All` — read meeting metadata.
|
|
70
|
+
- `GroupMember.Read.All` — read the organizer group's members (the object-ids).
|
|
71
|
+
|
|
72
|
+
`User.Read.All` is **deliberately not used** — the group-members call already returns object-ids,
|
|
73
|
+
so the old per-UPN `/users/{upn}?$select=id` lookup is unnecessary.
|
|
74
|
+
|
|
75
|
+
No Teams **Application Access Policy** is required for this tenant — verified the app can read
|
|
76
|
+
the organizers' transcripts directly once given a valid object-id.
|
|
77
|
+
|
|
78
|
+
## Client variations
|
|
79
|
+
|
|
80
|
+
None — uniform. Output is partitioned per client by meeting-title classification, but the
|
|
81
|
+
process is identical for all.
|
|
82
|
+
|
|
83
|
+
## Gotchas / known issues
|
|
84
|
+
|
|
85
|
+
- **`getAllTranscripts` requires an AAD object-id (GUID), NOT a UPN.** Passing a UPN
|
|
86
|
+
(e.g. `ajean@togatech.com`) returns the opaque `HTTP 400 BadRequest / "UnknownError"`.
|
|
87
|
+
This is the single most likely cause of an export failure.
|
|
88
|
+
- **The earlier UPN→GUID fix (PR #77) silently failed.** It resolved each UPN via
|
|
89
|
+
`GET /users/{upn}?$select=id`, but the app lacks `User.Read.All`, so that call returns
|
|
90
|
+
`403 Authorization_RequestDenied`, which `resolveUserId()` swallows and falls back to the UPN —
|
|
91
|
+
producing the same 400. Lesson: a "fix" that depends on an ungranted permission and silently
|
|
92
|
+
falls back will look correct in code review but never work in prod. The group-members approach
|
|
93
|
+
avoids the `/users` endpoint entirely.
|
|
94
|
+
- `resolveUserId()` still exists for the `organizer_user_ids` fallback path and returns a GUID
|
|
95
|
+
unchanged (regex match); it is bypassed entirely when the group is configured.
|
|
96
|
+
- Graph meeting/transcript ids are base64 and contain `+ / =` — they must be `rawurlencode()`'d
|
|
97
|
+
at every Graph call site (`getMeeting`, `downloadTranscriptVtt` fallback URL).
|
|
98
|
+
- `resolveWatermark()` guards against an unparseable stored `dtCreated`: without the guard,
|
|
99
|
+
`strtotime(...) === false` minus 60 yields a 1969 date and a decades-wide Graph query window.
|
|
100
|
+
- Plaintext `client_secret` lives in `Config/production.ini` `[teams]` — should be rotated /
|
|
101
|
+
moved to a secret store (out of scope as of this writing).
|
|
102
|
+
|
|
103
|
+
## Diagnosing a 400
|
|
104
|
+
|
|
105
|
+
A standalone bash diagnostic (`worker2/diagnose-transcripts.sh`) reproduces the Graph call
|
|
106
|
+
chain step-by-step (token → group members → `getAllTranscripts`) and prints the **full** Graph
|
|
107
|
+
error body that the worker discards (it keeps only `error.message`). It reads creds from the ini
|
|
108
|
+
at runtime and prints none. Useful first stop for any future Graph failure here.
|
|
109
|
+
|
|
110
|
+
## Change history
|
|
111
|
+
|
|
112
|
+
- 2026-06-12 — Resolve organizers from the `organizer_group_id` Entra group (object-ids via
|
|
113
|
+
GroupMember.Read.All) instead of per-UPN lookup; fixes the recurring HTTP 400 that PR #77's
|
|
114
|
+
`/users` approach couldn't (no User.Read.All). Hardened watermark parsing, URL-encoding, and
|
|
115
|
+
silent catches. Verified live: 6/6 organizers, 32 transcripts. (ajean)
|
|
116
|
+
|
|
117
|
+
## Related docs
|
|
118
|
+
|
|
119
|
+
- [Worker (worker2) Architecture](../architecture.md)
|
|
120
|
+
- [Creating Worker Actions](./creating-worker-actions.md)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -6,13 +6,13 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
6
6
|
|
|
7
7
|
- **library** (Library) _(framework core)_ — 4 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
8
|
- **worker** (Worker) — 4 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
|
-
- **togadesk** (TogaDesk) —
|
|
10
|
-
- **togaview** (TogaView) —
|
|
9
|
+
- **togadesk** (TogaDesk) — 4 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
10
|
+
- **togaview** (TogaView) — 4 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
|
|
11
11
|
|
|
12
12
|
## 2.0 framework
|
|
13
13
|
|
|
14
14
|
- **_underscore** (_Underscore) _(framework core)_ — 5 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
15
|
-
- **worker2** (Worker) —
|
|
15
|
+
- **worker2** (Worker) — 6 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
16
16
|
- **api2** (API) — 1 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
17
17
|
- **dbchanges2** (Database Changes) _(framework core)_ — 1 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
18
18
|
- **toga2-supply** (TOGa Supply) — 2 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
package/package.json
CHANGED