# UCM recording architecture

MarvelPBX 12.5.4 contains its complete recording integration under `modules/MarvelPBX`. It has no runtime dependency on the DEV integration repository, AMI, `/recapi`, HTTP Digest, browser GUI endpoints, directory scraping, or guessed recording paths.

## Request flow

1. An authenticated VTiger user opens `index.php?module=MarvelPBX&action=RecordingProxy&record=<PBXManager-ID>`.
2. The action accepts only the positive numeric record ID. It verifies MarvelPBX permission and PBXManager record permission.
3. The service loads `sourceuuid`, `recordingurl`, `callstatus`, and `starttime` server-side and rejects deleted or non-PBXManager records.
4. The package client uses JSON `POST <base_url>/api`: challenge, login with MD5(challenge + password), and cookie-authenticated actions.
5. `cdrapi` is queried only for the call date with bounded pagination. Every `main_cdr` and dynamic `sub_cdr_N` node is inspected. Correlation is exact string equality between PBXManager `sourceuuid` and node `uniqueid`; ambiguity fails closed.
6. `getRecordInfosByCall` confirms the recording metadata using the `AcctId` from the exact recording-bearing node.
7. The confirmed metadata recordfile is strictly parsed into its exact safe relative directory and WAV basename. Authenticated `action=recapi` without `filedir` or `filename` provides the bounded server-authoritative root CSV; the metadata directory must occur exactly once. That exact directory is then listed and the metadata basename must occur exactly once.
8. The same authenticated action streams only that exact directory-plus-basename into a bounded non-public PHP temporary stream. MIME, maximum size, and RIFF/WAVE signature are validated before browser headers are emitted.

Browser Range is not forwarded or advertised. If supplied, the first implementation returns the complete validated WAV with HTTP 200. No audio is persisted in the web root and no `recordingurl` field is written.

## Trust boundaries

The browser controls only the PBXManager record ID. It cannot supply a UUID, filename, path, URL, host, UCM action, cookie, or credentials. List rendering only creates an optimistic same-origin proxy URL and performs no UCM request. The proxy is the sole recording-resolution boundary.

Successful responses use `audio/x-wav`, a server-derived filename, `nosniff`, and private no-store caching. Permission failures are sanitized 403 responses; missing recordings are sanitized 404 responses; disabled settings or transport failures are sanitized 503 responses. UCM bodies and stack traces are never returned.

The settings row bounds connection time, total request time, CDR pages/records, root/directory CSV size, and audio bytes. The client retries an expired documented cookie at most once and clears its in-memory cookie after streaming or failure.

## Legacy recordingurl policy

Templates never echo `recordingurl`. The compatibility parser rejects schemes, external hosts, embedded credentials, CR/LF, fragments, and traversal. It recognizes the exact same-origin MarvelPBX RecordingProxy route for the same numeric record as syntactically safe, but never treats that recursive route as an underlying media source. A record with sourceuuid still resolves through UCM even when an old proxy URL is stored. No historical filesystem or external-host allowlist is enabled because none has been proven by offline fixtures.

## Rollback

Before upgrading, snapshot the module runtime, module metadata, owned settings table, reporting view, and relevant permissions. Rollback restores the prior package/runtime and database snapshot as one operation. It must not delete or rewrite PBXManager, crmentity, MarvelPBX base/CF data, or recordings.
