conferences: rooms with PIN and admin PIN, per-room limits, recording
ci / images (push) Canceled after 0s
ci / check (push) Canceled after 3s

/api/conferences CRUD: PINs stored encrypted, shown to admins (they hand
them out), never in the audit log; an admin PIN needs a different room
PIN (checked against the stored values on PATCH). The generator renders
sp-conf-{id} per 03 §6.11 (PIN prompt, 3 tries, admin PIN joins with
sp_admin_user), the number in sp-local-numbers and destApp conference.

Two changes from the spec's snippet, both found with real calls and
written back into 03:
- Set(CONFBRIDGE(bridge,max_members)) is ignored once ConfBridge()
  names a bridge profile: a 4th caller got into a room of 3. Each room
  now has its own [sp_room_<n>](default_bridge) profile in
  confbridge_selfphoneng.conf.
- A recorded room runs sp-sub-record on each caller's leg (just before
  ConfBridge) instead of record_conference, so the files are ordinary
  call recordings: call history, Recordings page, retention.

Web: Conference rooms page (list, drawer form), "Conference room" in
the DestinationPicker. Golden case conferences. e2e m8-t3: room built
in the UI, wrong PIN refused and asked again, admin PIN joins with
flags AM, a 4th caller turned away, recordings listed, and a no-PIN
room with two desk phones.

Task: M8-T3
This commit is contained in:
iamdoubz committed 2026-10-19 04:56:41 -05:00
1 parent 964a3c0b25
commit a6c423de97
45 files changed
+1456 -14

No files matched your search

+11
View File
@@ -19,6 +19,7 @@ export function loadCase(name: string): Snapshot {
routes?: Partial<Snapshot['routes'][number]>[];
ringGroups?: Partial<Snapshot['ringGroups'][number]>[];
queues?: Partial<Snapshot['queues'][number]>[];
conferences?: Partial<Snapshot['conferences'][number]>[];
ivrs?: Partial<Snapshot['ivrs'][number]>[];
timeConditions?: Partial<Snapshot['timeConditions'][number]>[];
holidays?: Snapshot['holidays'];
@@ -104,6 +105,16 @@ export function loadCase(name: string): Snapshot {
id: q.id!,
number: q.number!,
})),
conferences: (raw.conferences ?? []).map((c, i) => ({
name: `Room ${i + 1}`,
pin: null,
adminPin: null,
maxMembers: 20,
record: false,
...c,
id: c.id!,
number: c.number!,
})),
routes: (raw.routes ?? []).map((r, i) => ({
name: `Route ${i + 1}`,
position: i,