Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions docs/prd/FLEET_01_Camera_Identity_Organization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# PRD — Camera Identity & Organization

**Status**: Draft
**Created**: 2026-08-22
**Owner**: TBD
**Priority**: 1 — foundation
**Scope**: Stable camera identity, physical location hierarchy, normalized tags,
saved smart collections, and the selector language consumed by later fleet PRDs.

---

## 1. Problem

lightNVR can name and tag streams, which works well for small installations. At
hundreds of cameras, names and IP addresses are mutable, tags become inconsistent,
and flat lists cannot answer ordinary operational questions such as “show every
offline exterior camera in Building C.”

Authorization, storage, event routing, bulk configuration, and health monitoring
all need to select the same sets of cameras. Implementing a different grouping
model for each feature would create incompatible policy systems.

## 2. Goals

- Give every camera an immutable UUID independent of name, address, and hardware
replacement.
- Represent one primary physical location path per camera.
- Preserve many-to-many tags as flexible facets rather than replacing them with
flat groups.
- Add saved static and dynamic collections for reusable fleet queries.
- Define one versioned selector format shared by authorization, event routes,
storage policies, fleet jobs, and operator views.
- Migrate existing installations without changing recording or playback behavior.

## 3. Non-goals

- Maps, floor plans, and GIS presentation; covered by UXD 04.
- Bulk editing or configuration templates; covered by Fleet 04.
- Permission enforcement; covered by Fleet 02.
- Multi-NVR federation or multi-tenant cloud management.
- Replacing the existing substream and detection-stream fields with separate
camera entities in v1.

## 4. Product model

| Concept | Cardinality | Purpose | Example |
| --- | --- | --- | --- |
| Camera UUID | One per configured camera | Durable identity | `0192...` |
| Display name | One mutable value | Human recognition | `North Lobby` |
| Location | One leaf; inherits ancestors | Physical organization | Campus / Bldg A / Floor 2 |
| Tag | Many per camera | Cross-cutting facets | `outdoor`, `ptz`, `critical` |
| Static collection | Explicit camera membership | Curated group | `Guard Tour A` |
| Smart collection | Saved selector | Dynamic group | `offline AND tag:entrance` |

The configured stream remains the camera record in v1. Its main, sub, and
detection URLs are profiles of the same logical camera.

## 5. Requirements

### 5.1 Stable identity

- Add a non-null UUID to every camera/stream record.
- Generate UUIDs for existing rows during migration and never derive them from
display name, URL, or IP address.
- Use UUIDs in new APIs, event subjects, policy bindings, and audit records.
- Retain name-based API compatibility during a documented transition period.
- A camera replacement workflow may change serial, MAC, URL, and credentials
while preserving UUID, history, policy membership, and operator layouts.

### 5.2 Location hierarchy

- Store an adjacency-list hierarchy with stable node UUID, parent UUID, name,
type, sort order, and optional metadata.
- Suggested types are organization, site, building, floor, and area, but custom
labels are allowed.
- Prevent cycles and destructive deletion of nonempty nodes.
- Moving a subtree updates effective selectors without rewriting every camera.
- Existing cameras migrate under a root `Unassigned` node.

### 5.3 Normalized tags

- Normalize tag identity separately from its display label.
- Tags are case-insensitive for uniqueness and preserve display casing.
- Support optional color and description metadata.
- Rename and merge tags without editing each camera record individually.
- Existing tag strings migrate losslessly.

### 5.4 Collections and selectors

- Static collections store explicit camera UUID membership.
- Smart collections store a versioned selector AST, not raw SQL.
- v1 selector predicates: camera UUID, location subtree, tag any/all/none,
enabled state, recording mode, vendor/model, ONVIF capability, and health state.
- Boolean `AND`, `OR`, and `NOT` composition is supported with bounded nesting.
- Selector evaluation returns a total count plus a paginated camera result.
- A dry-run/preview endpoint explains why a camera matched.
- Saved collections can be private or shared; access enforcement lands in Fleet
02, while v1 defaults shared mutation to administrators.

### 5.5 APIs and migration

- CRUD APIs for locations, tags, and collections use camera UUIDs.
- Fleet query API supports server-side pagination, sorting, facets, and counts.
- Migration is idempotent and safe to resume after interruption.
- Backup/export formats include stable identities and organization metadata.
- Existing endpoints remain functional until their UUID replacements are adopted
by the web UI.

## 6. Phasing

| Phase | Scope |
| --- | --- |
| P0 | UUID schema, migration, UUID-capable camera APIs |
| P1 | Location hierarchy and tag normalization |
| P2 | Selector evaluator and fleet query API |
| P3 | Static/smart collections and organization management UI |

## 7. Acceptance criteria

- A migrated installation retains all streams, tags, recordings, and playback.
- Renaming or replacing a camera does not change its UUID or lose history.
- An operator can represent at least five hierarchy levels and move a complete
subtree without editing its cameras.
- A query such as `location:Building-C AND tag:outdoor AND health:offline`
returns correct results and facet counts from a 1,000-camera fixture.
- Authorization, event, storage, and bulk-operation code can consume the same
selector JSON without feature-specific translations.
- Malformed or excessively complex selectors are rejected with actionable errors.

## 8. Risks and mitigations

| Risk | Mitigation |
| --- | --- |
| UUID migration breaks name-based callers | Dual lookup during transition; log deprecated name use |
| Free-form tags remain inconsistent | Central tag dictionary with rename and merge |
| Selector language becomes an unsafe query engine | Typed AST, bounded depth, parameterized SQL only |
| “Camera” and “stream” terminology diverge | Preserve stream internals in v1; document the product-level camera abstraction |

## 9. Dependencies and successors

This PRD has no new-feature dependency. It is required by Fleet 02–04, Storage
01, both ONVIF PRDs, and the later operations PRDs.

## 10. Open questions

- Whether location node types should remain suggestions or be administrator-
defined vocabulary.
- Whether camera replacement needs history in v1 or only an audited overwrite.
- Whether private smart collections belong in the server database or user-local
preferences for the first implementation.
165 changes: 165 additions & 0 deletions docs/prd/FLEET_02_Scoped_Authorization_Audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# PRD — Scoped Authorization & Audit

**Status**: Draft
**Created**: 2026-08-22
**Owner**: TBD
**Priority**: 2 — access-control foundation
**Scope**: Action-level authorization, resource selectors, scoped API tokens,
consistent endpoint enforcement, and a durable audit trail. SSO is explicitly a
deferred, customer-triggered phase.

---

## 1. Problem

The current admin/user/viewer roles and allowed-tag filtering provide a useful
baseline, but institutional deployments need to distinguish viewing video from
listening, talking, exporting, operating PTZ, deleting evidence, or changing a
camera. A per-camera checkbox matrix would become unmanageable at hundreds of
cameras and would drift as cameras move or are added.

The same decision must be enforced consistently by every UI and API endpoint,
and sensitive actions need an auditable record.

## 2. Goals

- Authorize explicit actions over dynamic resource scopes.
- Reuse Fleet 01 selectors so permissions follow locations and tags.
- Keep roles understandable: roles bundle actions; grants bind a role to a scope.
- Apply the same authorization rules to sessions and API tokens.
- Default-deny newly introduced privileged actions while preserving sensible
behavior for existing users during migration.
- Audit access-sensitive and state-changing operations.
- Leave a clean integration seam for a future organizational identity provider.

## 3. Non-goals

- OIDC, SAML, LDAP, or automatic identity-provider discovery in the initial
implementation.
- Multi-tenant cloud identity federation.
- Per-frame watermarking or DRM.
- Building organization-specific compliance reports before a customer defines
the applicable policy.

## 4. Authorization model

`principal/group -> grant -> role(actions) + resource selector + optional schedule`

Initial actions:

- `live.view`, `audio.listen`, `audio.talk`
- `recordings.replay`, `recordings.export`, `snapshot.create`
- `ptz.control`
- `evidence.protect`, `recording.delete`
- `camera.configure`, `fleet.execute_job`
- `storage.configure`, `events.configure`
- `users.manage`, `system.admin`

Roles are named reusable action bundles. A grant binds a user or local group to
a role and a Fleet 01 selector. A schedule may limit a grant by local time and
day. Explicit deny rules are out of scope for v1; absence of an allow is deny.

## 5. Requirements

### 5.1 Policy storage and evaluation

- Persist roles, actions, local groups, grants, schedules, and policy version.
- Compile and cache selectors without caching past policy or camera changes.
- Expose a single server-side authorization function used by all handlers.
- Return `403` without revealing resource metadata when a principal lacks access.
- List endpoints filter unauthorized resources and compute totals after filtering.
- All new actions begin denied except for the built-in administrator role.
- Provide a policy simulation endpoint for administrators: principal + action +
resource returns allow/deny and the matching grant, without executing the action.

### 5.2 Migration and built-in roles

- Map existing admins to every action over all cameras.
- Map existing viewers to safe read-only actions within their `allowed_tags`.
- Map existing users to a documented compatibility role within their current
scope; call out any newly restricted destructive action during upgrade.
- Keep built-in roles immutable but cloneable.
- Migrate `allowed_tags` into selector-backed grants and deprecate it only after
all handlers use the new evaluator.

### 5.3 API tokens

- Tokens inherit or narrow the issuing principal's grants; they never widen them.
- Token creation requires an explicit expiry, description, and displayed-once
secret.
- Persist only a strong token hash and token identifier.
- Audit creation, use, revocation, expiry, and denied privileged calls.

### 5.4 Audit trail

- Record timestamp, request/correlation ID, principal, authentication method,
action, target UUID, outcome, remote address, and safe structured details.
- Required events include login outcomes, policy changes, camera configuration,
PTZ control, audio talk activation, export, protect/unprotect, deletion,
storage policy changes, event route changes, and backup restore.
- Never log passwords, tokens, camera credentials, or raw authorization headers.
- Provide filtered, paginated export with a configurable retention period.
- Audit records are append-only through supported APIs.

### 5.5 Administration UI

- Role editor presents action descriptions and warns on destructive bundles.
- Grant editor uses location, tag, collection, or explicit-camera selectors.
- Scope preview shows matched count and a sample before save.
- “Test access as user” uses the simulation endpoint and is itself audited.
- Every denied UI action remains hidden or disabled, but server enforcement is
always authoritative.

### 5.6 Deferred SSO phase

OIDC/SSO is **not part of the initial implementation**. It activates when a
committed organizational deployment—such as an SJC-scale customer—requires it
and supplies a real IdP configuration and administrative testing partner.

When triggered, the phase should add:

- Authorization Code flow with PKCE, issuer discovery, key rotation, logout, and
configurable local-admin break-glass access.
- IdP group/claim mapping to existing lightNVR roles and grants.
- Just-in-time user provisioning with safe default scope.
- Audit entries that preserve external subject and issuer.

The core authorization schema must not depend on OIDC, so delaying SSO does not
defer useful access-control work.

## 6. Phasing

| Phase | Scope | Trigger |
| --- | --- | --- |
| P0 | Action vocabulary, policy evaluator, endpoint inventory | Immediate |
| P1 | Selector grants, migration, scoped API tokens | After Fleet 01 selector API |
| P2 | Audit log and policy administration UI | After P0/P1 |
| P3 | OIDC/SSO and group mapping | Committed organizational customer only |

## 7. Acceptance criteria

- Endpoint tests prove every protected action denies an unauthorized user even
when the HTTP request bypasses the UI.
- A grant for `tag:parking` automatically includes a newly tagged camera and
excludes it when the tag is removed.
- A user may replay but not export recordings when those actions differ.
- A camera-scoped token cannot query or mutate cameras outside its grants.
- Every required sensitive operation produces a redacted audit record with a
correlation ID.
- Upgrading preserves administrator access and produces a migration report.
- No OIDC dependency is required to ship P0–P2.

## 8. Risks and mitigations

| Risk | Mitigation |
| --- | --- |
| Missed endpoint creates an authorization gap | Route inventory plus mandatory handler tests and centralized middleware/helper |
| Dynamic selectors create surprising access | Preview, simulation, audit, and visible matching-grant explanation |
| Existing users lose required access | Compatibility mapping and upgrade report |
| SSO work becomes speculative | Gate P3 on a committed customer and actual IdP |

## 9. Dependencies

- Fleet 01 for stable camera UUIDs and selectors.
- Fleet 03 should reuse audit correlation IDs and may publish security events, but
durable audit storage must not depend on MQTT delivery.
Loading
Loading