recordings: record calls, link them to history, Recordings page

sp-sub-record now also sets CDR(SP_REC); phone numbers can record every
call (record_inbound), with the notice from Settings → Recording played
first (SP_REC_ANNOUNCE). Aggregation links the MixMonitor file as a
recordings row (size, ffprobe length). /api/recordings lists, plays
(Range; admins and the people on the call) and deletes; recordings past
recordings.retentionDays are deleted daily.

Web: Recordings page (play, download, delete), a player in Call history
and My calls, a Recording settings tab with the consent notice (08 §5),
and "Record every call" on phone numbers.

e2e m7-t3: the notice plays before a recorded inbound call and the
recording plays from Call history (the M7 acceptance). The AMI
Originate helper moved to scripts/e2e/ami.mjs.

Task: M7-T3
This commit is contained in:
iamdoubz committed 2026-10-18 14:57:52 -05:00
1 parent 8abcea9533
commit 4b6b95090a
46 files changed
+810 -54

No files matched your search

+14
View File
@@ -64,3 +64,17 @@ export type MyCallDto = CallDto & {
/** Someone called me and nobody answered (a colleague answering in a group isn't missed). */
missedByMe: boolean;
};
export type RecordingDto = {
id: string;
startedAt: string;
durationMs: number | null;
sizeBytes: number | null;
call: {
id: string;
direction: CallDirection;
fromNumber: string | null;
fromName: string | null;
toNumber: string | null;
} | null;
};
+2
View File
@@ -31,6 +31,8 @@ const DidFields = z.object({
.regex(/^[A-Za-z0-9 :_.#-]*$/, 'Letters, digits, spaces and : _ . # - only')
.nullable(),
e911Address: z.string().trim().max(200).nullable(),
/** Record every call to this number (callers hear the recording notice first, if set). */
recordInbound: z.boolean(),
});
export const DidCreateSchema = DidFields.partial().required({