Legal intake and document automation

Briefly

Court-ready drafts in minutes

Briefly is legal intake and document automation for solo consumer‑law attorneys handling high‑volume matters. Mobile‑friendly, guided questionnaires validate facts once, then assemble a complete retainer and court‑ready first draft for instant e‑sign. Eliminate retyping and signature chase, cut intake‑to‑engagement under 30 minutes, reduce errors 60%, and reclaim six billable hours weekly.

Subscribe to get amazing product ideas like this one delivered daily to your inbox!

Briefly

Product Details

Explore this AI-generated product idea in detail. Each aspect has been thoughtfully created to inspire your next venture.

Vision & Mission

Vision
Make instant, error-free onboarding universal, empowering solo attorneys to serve more clients, reclaim time, and grow sustainably.
Long Term Goal
Within 4 years, power intake for 25,000 solo and small consumer-law firms, process 10 million matters annually, slash onboarding time to under 15 minutes and first-draft errors 60% globally.
Impact
For solo consumer-law attorneys, compresses intake-to-engagement from days to under 30 minutes, cuts data entry 80%, and reduces first-draft errors 60%. Clients complete on mobile 2.3x faster, lifting conversion 25% and freeing an average of 6 billable hours per week.

Problem & Solution

Problem Statement
Solo consumer-law attorneys handling high-volume matters waste hours chasing signatures and retyping client data from emails and PDFs into first drafts. Generic CRMs miss legal nuance and lack validation, causing errors, delays, lost revenue, and poor client experience.
Solution Overview
Briefly replaces email/PDF intake with mobile-friendly, guided questionnaires that validate legal facts and merge answers into court-ready first drafts. Matter Blueprint auto-assembles a complete retainer and draft packet and routes it for instant e‑sign, eliminating retyping and signature chase to reach engagement in under 30 minutes.

Details & Audience

Description
Briefly automates legal intake and turns client answers from mobile-friendly questionnaires into court-ready first drafts in minutes. Built for solo consumer-law attorneys handling high-volume matters. It eliminates back-and-forth emails and retyping, cutting intake-to-engagement to under 30 minutes and errors by 60%. The Matter Blueprint assembles a complete retainer and first-draft packet, ready for instant e-sign.
Target Audience
Tech-forward solo consumer-law attorneys (28-55) overwhelmed by high-volume intake, demanding speed and accuracy.
Inspiration
On a Saturday in my friend's one-room office, her coffee went cold while she chased missing signatures and squinted at blurry phone photos of IDs. The client had answered the same questions by email, PDF, and intake call, yet the retainer still went out wrong. The click: a single mobile, guided flow that validates facts once and auto-assembles a court-ready packet, ready for instant e-sign.

User Personas

Detailed profiles of the target users who would benefit most from this product.

M

Mobile Maverick Maya

- Age 34, solo consumer-law litigator in metro corridor. - Works from iPhone and ultrabook; shared coworking office. - Handles debt-defense, eviction, small-claims appeals; 25+ actives. - Annual revenue ~$250k; minimal admin staff.

Background

Cut teeth at legal aid juggling heavy dockets and walk-ins. Opened a solo practice and embraced cloud tools to stay productive between courthouses and client homes.

Needs & Pain Points

Needs

1. Instant mobile intake with photo capture. 2. One-tap retainer e-sign in person. 3. Auto-assembled drafts from validated answers.

Pain Points

1. Leads lost during courthouse downtime. 2. Retyping on tiny screens creates errors. 3. After-hours signature chase kills evenings.

Psychographics

- Craves momentum and visible progress daily. - Values autonomy and time-to-impact. - Trusts tools proven in real-world chaos. - Despises double entry and desk-bound workflows.

Channels

1. LinkedIn mobile feed 2. YouTube how-tos 3. Apple Podcasts law practice 4. Clio App Directory research 5. Reddit r/lawfirm peers

B

Bilingual Bridge Bella

- Age 36, English–Spanish bilingual solo in storefront office. - 70% walk-ins; consumer debt, auto fraud, landlord issues. - Serves families via evenings/weekends; heavy WhatsApp communication. - Revenue ~$180k; one part-time assistant.

Background

Grew up translating forms for relatives and saw errors snowball. After nonprofit stints, opened her practice to deliver accessible, culturally mindful services.

Needs & Pain Points

Needs

1. Accurate multilingual questionnaires and clauses. 2. Client-friendly explanations reducing fear. 3. Simple phone upload for documents.

Pain Points

1. Mistranslations create costly clause mistakes. 2. Intimidating language triggers form abandonment. 3. Clarification back-and-forth drains capacity.

Psychographics

- Champions accessibility and language justice. - Builds trust through radical transparency. - Prefers visuals over dense legal text. - Community reputation beats paid advertising.

Channels

1. Facebook Groups local 2. WhatsApp Business chats 3. Google Business Profile reviews 4. YouTube Spanish explainers 5. Avvo profile discovery

S

Security-Strict Sam

- Age 48, consumer credit/FCRA solo, suburban office. - Former IT minor; meticulous about security hygiene. - Handles 15–20 active matters; minimal staff. - Pays premium for compliant, documented vendors.

Background

A near-miss phishing incident early in practice made security personal. He rebuilt workflows to centralize data, eliminate email PII, and document every signature.

Needs & Pain Points

Needs

1. SOC 2, encryption, and data residency details. 2. Complete signature and edit audit trails. 3. Role-based access with granular permissions.

Pain Points

1. Vendor security claims without documentation. 2. PII scattered across inboxes and drives. 3. Unclear data ownership and retention terms.

Psychographics

- Skeptical until proof outweighs risk. - Requires auditable, defensible, fully documented processes. - Prefers standards over vendor promises. - Values control and least-privilege access.

Channels

1. ABA Law Practice Today newsletter 2. State bar listserv ethics 3. LinkedIn security threads 4. Capterra security filters 5. LawNext Podcast episodes

I

Integration-Obsessed Ivy

- Age 32, ops lead at 3-person consumer firm. - Background in SaaS support and paralegal work. - Owns tech stack budget and vendor relationships. - Remote-first; Eastern time, cloud everything.

Background

Automated intake at a prior firm with Zapier and Clio. Now measured on reducing manual touches and duplicate records across systems.

Needs & Pain Points

Needs

1. Native Clio, LawPay, and Google Drive sync. 2. Webhooks for intake and e-sign events. 3. Flexible field mapping and deduplication.

Pain Points

1. CSV exports breaking critical automations. 2. Duplicate contacts across disconnected tools. 3. No sandbox to test integrations safely.

Psychographics

- Treats workflows as puzzles to optimize. - Loves API docs, webhooks, and schemas. - Avoids lock-in; favors portable data. - Measures success in touches eliminated.

Channels

1. Zapier Community forum 2. Clio App Directory reviews 3. YouTube automation tutorials 4. LegalTechHub vendor pages 5. Reddit r/NoCode discussions

C

Conversion-Centric Carlos

- Age 38, PI-adjacent consumer practice; heavy PPC spend. - Urban office; dedicated call tracking and CRM. - 40+ leads weekly; limited staff bandwidth. - Comfortable with SMS-first communications.

Background

Came from a growth agency before law school. Built his practice on paid search and relentless funnel optimization.

Needs & Pain Points

Needs

1. Short adaptive intake minimizing drop-off. 2. Auto SMS nudges for incomplete forms. 3. UTM capture into CRM records.

Pain Points

1. Long forms bleed expensive leads. 2. Delayed e-sign cools buyer intent. 3. Lost attribution between ad and intake.

Psychographics

- Obsessed with measurable outcomes and ROI. - Iterates relentlessly; A/B tests everything. - Demands instant, mobile-friendly experiences. - Prefers automation over manual follow-ups.

Channels

1. Google Ads forum 2. Meta Ads Manager resources 3. YouTube analytics deep-dives 4. LinkedIn marketer circles 5. CallRail blog insights

C

Clinic-Driven Dana

- Age 41, solo; monthly clinics with volunteers. - Serves debt, eviction, wage garnishment communities. - Uses Chromebooks, hotspots; limited IT support. - Funding mix: fees, grants, donations.

Background

Built clinic playbooks after disaster-response volunteering. Partnerships with nonprofits drive surges requiring fast intake, triage, and batch paperwork.

Needs & Pain Points

Needs

1. QR-enabled kiosk intake for events. 2. Bulk reminders and status updates. 3. Batch document assembly by session.

Pain Points

1. Paper sign-up sheets go missing. 2. Inconsistent volunteer data entry. 3. Post-clinic follow-up falls through.

Psychographics

- Community impact over billable maximization. - Needs calm systems amid chaos. - Values repeatable, scalable, template-driven processes. - Embraces volunteers with simple workflows.

Channels

1. State bar pro bono portal 2. Eventbrite event management 3. Facebook Events promotion 4. Mailchimp newsletters 5. WhatsApp Groups volunteers

Product Features

Key capabilities that make this product valuable to its target users.

One-Tap Resume

Let clients re-enter intake with a single biometric prompt (Face ID/Touch ID) using passkeys. They land exactly on the last unanswered question with autosaved progress—no passwords, security questions, or re-verification steps—cutting lockouts, drop-off, and support calls while speeding intake-to-engagement.

Requirements

Passkey Biometric Sign-In
"As a client, I want to use Face ID or Touch ID to resume my intake so that I can continue without remembering a password or re-verifying my identity."
Description

Implement WebAuthn/FIDO2 passkey-based authentication that triggers native biometric prompts (Face ID/Touch ID/Windows Hello) to resume an existing intake without passwords, security questions, or redundant re-verification. Register discoverable passkeys tied to the client’s matter and relying party domain, support platform and synced passkeys (iCloud/Google Password Manager), and enforce strong attestation and anti-replay protections. Ensure cross-browser/mobile compatibility (Safari, Chrome, Edge) and accessibility fallbacks to device PIN within the passkey flow. On success, issue a short-lived session bound to the device and client, minimizing PII exposure and aligning with Briefly’s security posture.

Acceptance Criteria
Mobile One-Tap Resume via Biometric Passkey
Given a client has an active matter with autosaved progress and a registered discoverable passkey for Briefly’s RP ID And they open the intake link in Safari (iOS) or Chrome (Android) When they tap "Resume with Face ID/Touch ID" Then the native biometric prompt is invoked via WebAuthn with userVerification='required' And upon successful assertion verification, the app navigates directly to the last unanswered question for that matter And previously answered questions are restored and immutable where applicable And no password, security questions, or additional verification steps are requested And the time from biometric success to question view load is p95 ≤ 2.5 seconds And an audit event (clientId, matterId, authenticator type, non-PII device fingerprint, timestamp) is recorded
Passkey Registration with Discoverable Credential and Attestation
Given a client reaches the "Enable One‑Tap Resume" step during initial intake When they opt to create a passkey Then navigator.credentials.create is called with residentKey='required' (rk=true), userVerification='required', rpId set to Briefly’s relying party domain, and a cryptographically random ≥32‑byte challenge And the server verifies attestation (packed/apple/android-safetynet/tpm) and rejects registrations when strong attestation is expected but absent or invalid And origin and rpId validation must pass, otherwise registration is rejected And the credential is stored with user.id bound to clientId+matterId, AAGUID recorded, signCount initialized, and flagged as discoverable And UI confirms successful creation and offers a test sign‑in that completes without additional credentials
Cross-Browser and Cross-Platform Passkey Support
Given supported environments Safari (iOS/iPadOS/macOS), Chrome (Android/Windows/macOS), and Edge (Windows/macOS) When a registered client resumes using a platform or synced passkey (iCloud Keychain or Google Password Manager, including cross‑device handoff where supported) Then authentication completes successfully and lands on the last unanswered question across all listed environments And unsupported browsers or versions hide the "Resume with Face ID/Touch ID" option and display a neutral compatibility notice And browser/device matrix tests pass with ≥99% success rate across the matrix in CI
Accessible Fallback to Device PIN Within Passkey Flow
Given a client initiates passkey authentication When biometric verification is unavailable, fails, or the user selects "Use device passcode/PIN" Then the platform’s passcode/PIN prompt is presented within the WebAuthn flow and, upon success, authentication continues without any password or out‑of‑band re‑verification And the UI meets WCAG 2.2 AA (labels, focus order, contrast ≥4.5:1, keyboard operability, screen‑reader announcements) And authentication attempts are limited to 5 consecutive failures per challenge before requiring a new challenge
Short-Lived, Device-Bound Session Issuance
Given a valid WebAuthn assertion is verified server‑side When issuing a session Then set a new random HttpOnly, Secure, SameSite=Lax cookie with idle timeout ≤30 minutes and absolute timeout ≤2 hours And bind the session to device and client via stored credentialId and AAGUID; subsequent requests must present the same binding And block session reuse from other devices or browser profiles And exclude PII from the session payload (opaque IDs only); PII resides server‑side And rotate session ID on resume page load and on privilege elevation; invalidate on logout or matter completion
Anti-Replay, Origin, and RP ID Enforcement
Given the server creates an authentication challenge When an assertion is received Then verify: single‑use challenge within ≤60 seconds; rpIdHash matches Briefly’s RP ID; origin equals the HTTPS relying party origin; clientData.type is 'webauthn.get'; userVerification='required'; and signCount increases or is safely handled per zero‑counter authenticators And reject and audit any reused challenge, mismatched origin/RP ID, or stale/non‑advancing signCount; do not issue a session And apply rate limiting to failures (≤10 attempts per hour per IP and credentialId)
Progress Integrity and Matter Isolation on Resume
Given a client has multiple matters or prior intakes When they authenticate with a passkey mapped to a specific matter Then route only to that matter’s last unanswered question, with autosaved progress restored exactly as of the lastSavedAt timestamp And prevent access to data from other matters or clients; enforce credentialId → clientId+matterId binding server‑side And disallow skipping required validations or signatures during resume And log an audit trail entry of the mapping check and resume action
Resume-to-Last Unanswered Question Routing
"As a client, I want to land on the next unanswered question so that I can finish quickly without hunting for where I left off."
Description

Restore the client’s position to the exact next unanswered question upon successful biometric authentication. Persist a server-side cursor that respects dynamic branching logic, conditional reveals, and required validations in Briefly’s guided questionnaires. Handle schema versioning by mapping prior responses to updated question sets and re-evaluating the next required field. Provide idempotent navigation so repeated resumes always land at the correct step, and ensure seamless handoff to e-sign once all questions are complete.

Acceptance Criteria
Resume to Last Unanswered Question After Biometric Authentication
Given a client has an in‑progress intake with at least one unanswered required question When the client taps Resume and completes Face ID/Touch ID passkey authentication successfully Then the app navigates directly to the first unanswered required question in the current flow and shows no password or security‑question prompts And the progress indicator reflects the correct completion percentage based on server‑evaluated required fields And the resume navigation completes within 2 seconds at the 95th percentile from successful biometric auth to question render And previously answered questions remain persisted and are not re‑asked unless invalidated by branching changes
Server‑Side Cursor Honors Branching and Validations
Given the questionnaire contains dynamic branching, conditional reveals, and required validations When the client resumes the intake Then the server computes the next required field using current answers and dynamic logic, and routes the client to the first invalid or unanswered required field And if a prior answer change invalidates downstream answers, the cursor moves to the first affected field requiring re‑entry And the client cannot navigate past required unanswered/invalid fields; Next/Submit remains disabled until the field meets validation rules And server evaluation of the next required field completes within 200 ms p95
Schema Versioning and Response Mapping on Resume
Given the questionnaire schema has been upgraded from version X to version X+1 while a client has partial answers on X When the client resumes the intake Then prior responses are mapped to X+1 per migration rules; unmappable or changed‑semantics fields are flagged as needing input And deprecated questions do not block progress and are not displayed And the client is routed to the first required unmapped/unanswered field in X+1 And the mapping job completes within 500 ms p95 server time and writes an audit record with source version, target version, mapping outcomes, and target question id
Idempotent Navigation Across Repeated and Concurrent Resumes
Given a client triggers multiple resume attempts within 60 seconds, including from two different devices When biometric authentication succeeds on each attempt Then all attempts resolve to the same server‑computed target question id for the current answer state And duplicate resume requests are handled idempotently (by request id or nonce) so no duplicate sessions are created And no stale client cache can override the server cursor; each device renders the server‑provided target step until new answers are submitted And at most one active questionnaire session exists per intake; secondary sessions are revoked with a user‑visible notice
Completion Detection and Seamless Handoff to E‑Sign
Given all required questions are answered and validations pass When the client resumes the intake Then the client bypasses the questionnaire and lands directly on the e‑sign step with the assembled retainer/first‑draft linked to the current answer set And if e‑sign is partially completed, resume lands on the correct pending signature step; if fully executed, resume lands on engagement confirmation And the handoff to e‑sign completes within 2 seconds p95 and preserves the document version hash associated with the submitted answers And subsequent resumes after full execution never reopen the questionnaire unless an authorized staff member reopens the intake
Security and Privacy Guardrails on Resume
Given a resume deep link is opened When biometric authentication has not yet succeeded Then no PII, question text, or answer content is displayed; only the biometric prompt is shown And after three consecutive biometric failures or an invalid passkey assertion, the intake is locked for 5 minutes and a secure re‑attempt message is sent to the client And resume tokens are single‑use and expire after 15 minutes; reused or expired tokens return 401 and prompt a fresh passkey ceremony And all resume events are logged with timestamp, device, IP, and outcome without storing sensitive content
Per-Field Autosave with Offline Retry
"As a client on a spotty connection, I want my answers to autosave so that I never lose progress and can resume exactly where I left off."
Description

Autosave responses on every field blur/change and queue writes when offline, with exponential backoff and eventual consistency. Implement field-level versioning and last-write-wins with server timestamps to avoid data loss across devices. Display unobtrusive save status indicators and guard against partial submissions affecting validation. Ensure autosave events update the resume cursor and can be resumed via passkey from any device when connectivity is restored.

Acceptance Criteria
Autosave on Field Blur/Change with Status Indicator
Given an authenticated client is filling intake and has connectivity When the client blurs a field or changes its value Then the client app sends a per-field autosave request within 500 ms And a non-blocking "Saving…" indicator is shown adjacent to the field When the server acknowledges success Then the indicator changes to "Saved" within 100 ms and auto-fades within 2 seconds When the save fails with a retriable error or offline status Then the indicator changes to "Offline—will retry" without blocking input
Offline Queue with Exponential Backoff and Persistence
Given the device is offline or the save endpoint is unreachable When a field is blurred or changed Then the value is enqueued locally with field key, value, version, and timestamp And retries follow exponential backoff (1s, 2s, 4s, 8s...) capped at 60s until success And the queue order is preserved FIFO per field And the queue persists to storage and survives app relaunch When connectivity is restored Then all pending writes start flushing within 5 seconds subject to backoff
Field-Level Versioning and Last-Write-Wins Conflict Resolution
Given a field has version N on the server When Device A saves a new value and Device B saves a different value for the same field near-simultaneously Then the server applies authoritative server timestamps and stores the later server-received write as the winner (last-write-wins) And the server increments the field version and returns the authoritative value, server timestamp, and new version Then the client reconciles to the authoritative value within 500 ms And if the local value was overwritten, a non-blocking "Updated from another device" notice is shown
Resume Cursor Updates on Autosave
Given a client completes field F that unlocks the next question When the autosave for field F succeeds Then the server updates the resume cursor to the next unanswered question ID And the client updates its local resume cursor within 500 ms And subsequent navigation in-session uses the updated cursor
Passkey Resume Lands on Last Unanswered Question Across Devices
Given a client has a saved resume cursor on the server And the client signs in via passkey on a different device When the intake resumes Then the client is routed directly to the question matching the server-stored resume cursor And time from authentication to question display is under 2 seconds on a 4G connection And if offline changes existed on another device, routing uses the server cursor until those changes sync; future resumes use the updated cursor
Autosave Does Not Trigger Form-Level Validation or Partial Submission
Given required fields remain unanswered on the current step When autosave occurs for any field Then no form-level validation errors or submission side effects are triggered on the client or server And only field-level inline feedback may appear after first blur And the server accepts partial autosave payloads without rejecting due to missing required fields (2xx response) And full validation executes only on explicit submit
Eventual Consistency After Reconnect
Given a client made multiple offline edits across several fields creating a queued batch And another device edited one of those fields while the first device was offline When connectivity is restored on the first device Then queued writes are flushed and reconciled by last-write-wins within 10 seconds And within 10 seconds both devices display identical field values and the same resume cursor And no duplicate records or data loss are recorded in the server audit log
Secure Deep-Link Resume Tokens
"As a client, I want to resume securely from a link my attorney sends so that I can quickly continue on any device without dealing with passwords."
Description

Generate signed, time-limited deep links that route clients back to their intake, requiring a passkey assertion before restoring the session. Tokens are single-use, scope-limited to the matter, and revoked on completion or upon attorney action. Support universal links/app links for mobile and web routes that include the latest questionnaire context to precompute the resume cursor while preventing PII exposure in URLs.

Acceptance Criteria
Time-Limited, Signed Resume Link Creation
Given an existing intake matter with saved progress When a resume deep link is generated for the client Then the URL contains an opaque, cryptographically signed token verifiable server-side And the token includes an expiration equal to now plus the configured TTL And validation after expiration returns 401 with error_code "token_expired" And no session is restored when expired
Passkey Assertion Gate Before Session Restore
Given a valid, unexpired resume token is presented When the client activates the link Then the server issues a WebAuthn assertion challenge bound to the token and matter And upon successful passkey assertion the client session is restored and isAuthenticated=true And no password or security questions are displayed And failed or cancelled assertions do not consume the token and return 401 "webauthn_failed"
Single-Use Token Enforcement
Given a token that has successfully restored a session When the same link is used again Then validation returns 410 with error_code "token_consumed" And no session is restored And tokens are consumed only upon successful passkey assertion
Matter-Scoped Access and Resume Cursor Precomputation
Given a valid, unexpired token for matter M When it is presented Then access is limited to matter M and attempts to use the token to access any other matter return 403 "scope_mismatch" And the resume cursor is computed server-side from the latest saved questionnaire context at validation time And the client lands on the last unanswered question upon session restore And no questionnaire answers are passed in the URL
Automatic and Manual Token Revocation
Given a matter with one or more active resume tokens When the matter is marked Completed Then all associated tokens become invalid immediately and validation returns 403 "token_revoked" And when an attorney triggers "Revoke resume links" for the matter Then all associated tokens become invalid immediately and validation returns 403 "token_revoked" And an audit event is recorded for each revocation action with timestamp, actor, matter_id, token_id
Universal/App Link Routing and Fallback
Given a resume link is opened on iOS with the native app installed When the link is tapped in Mail, Messages, or a browser Then it opens the native app via Universal Links and proceeds to passkey assertion And if the app is not installed it opens the web route in the default browser And on Android the link opens the native app via App Links when installed, otherwise the web route And on desktop it opens the web route And in all cases the user lands on the last unanswered question after successful assertion without additional navigation steps
No PII Exposure in URLs or Referrers
Given any generated resume link Then the URL path and query parameters contain no PII (name, email, phone, address, SSN, matter details) And the token value is opaque or encrypted such that its contents cannot be decoded without server-held keys And no questionnaire context appears in the URL And requests from third-party pages do not include PII in the HTTP Referer header And automated static checks and runtime tests detect and fail any PII in URL generation
Compliance-Grade Audit Logging
"As a firm owner, I want an auditable trail of resume and authentication events so that we meet compliance obligations and can resolve client disputes."
Description

Record immutable audit events for passkey registration, biometric assertions, resume attempts, cursor jumps, autosave writes, and e-sign transitions. Include timestamps, device/browser metadata, IP, outcome, and reason codes without storing biometric data. Provide export and matter-level views to satisfy legal recordkeeping, incident response, and dispute resolution requirements while meeting privacy standards.

Acceptance Criteria
Append-Only, Tamper-Evident Audit Trail
Given the system is operating When any audit event of type {PASSKEY_REGISTER, BIOMETRIC_ASSERT, RESUME_ATTEMPT, CURSOR_JUMP, AUTOSAVE_WRITE, ESIGN_TRANSITION} occurs Then the event is appended as a new record and prior records cannot be modified or deleted by any API or UI operation And each record contains prev_hash and record_hash forming a SHA-256 hash chain over canonicalized record content And any attempt to alter or delete a record is rejected and logged as AUDIT_TAMPER_ATTEMPT with outcome=FAILURE and reason_code=UNAUTHORIZED_MUTATION And audit storage is WORM with retention default 7 years (configurable 1–10 years per organization) and supports per-matter legal hold And a daily integrity verification job validates the hash chain and raises a P1 alert within 5 minutes if any chain breakage is detected
Event Coverage and Schema Completeness
Given an event is generated When the event is persisted Then mandatory fields are present: event_id(UUIDv4), timestamp(ISO8601 UTC), event_type∈{PASSKEY_REGISTER, BIOMETRIC_ASSERT, RESUME_ATTEMPT, CURSOR_JUMP, AUTOSAVE_WRITE, ESIGN_TRANSITION}, outcome∈{SUCCESS, FAILURE}, reason_code∈{OK, USER_CANCELLED, TIMEOUT, NETWORK_ERROR, DEVICE_NOT_SUPPORTED, ASSERTION_REJECTED, VALIDATION_ERROR, PERMISSION_DENIED, RATE_LIMITED, UNKNOWN} (nullable only when outcome=SUCCESS), matter_id, client_ref, session_id, request_id, ip_address, user_agent, device_type, os_version, browser_name, browser_version And event-specific fields are captured: AUTOSAVE_WRITE{question_id, bytes_written}, CURSOR_JUMP{from_question_id, to_question_id}, ESIGN_TRANSITION{envelope_id, transition∈{ENVELOPE_CREATED, SENT, VIEWED, SIGNED, COMPLETED, DECLINED}}, PASSKEY_REGISTER{attested:boolean, aaguid(optional)}, BIOMETRIC_ASSERT{authenticator_type∈{PLATFORM, ROAMING}}, RESUME_ATTEMPT{resume_method=PASSKEY, last_question_id} And writes with any missing mandatory field are rejected (not persisted) and a VALIDATION_ERROR is returned And within a session, timestamps are monotonically non-decreasing; if client clock skew > 2s is detected, skew_flag=true and server time is used for timestamp
Biometric Privacy and Data Minimization
Given biometric factors are used to unlock passkeys When audit events are recorded Then no biometric images, templates, or measurements are collected, transmitted, or stored And only passkey assertion outcome, optional aaguid, and non-biometric device/browser/IP metadata are stored And IP addresses are stored in full for security and additionally hashed (SHA-256) for analytics; no geo-lookup results are stored in the audit log And retention is configurable per organization (1–10 years, default 7) with per-matter legal hold; upon expiry without legal hold, records are purged from primary and backup stores within 30 days And GDPR/CCPA requests can export all audit records for a given client_ref within 30 days and contain no biometric data
Matter-Level Timeline View
Given a user with Matter Audit Viewer permission opens a matter When the Audit timeline is requested Then events for that matter are displayed reverse-chronologically with pagination (page_size=100) And filters are available for event_type, outcome, date range, and reason_code; search supports envelope_id and question_id And first page loads in ≤2s for matters up to 10,000 events; subsequent pages load in ≤1s And CURSOR_JUMP entries deep-link to the referenced question; ESIGN_TRANSITION entries link to the envelope view And no biometric data is displayed; device/browser/IP metadata is visible; Export button is shown only to users with Export Audit permission
Export Capabilities and Redaction
Given a user with Export Audit permission selects a matter or date range When an export is requested Then the system generates CSV and JSONL files plus a manifest.json containing generated_at, requested_by, filters, record_count, and sha256 checksums And two modes are supported: Compliance (full metadata) and Privacy-Redacted (IP masked /24 for IPv4 and /48 for IPv6; user_agent truncated to product/version; aaguid omitted) And exported files are signed and delivered via a pre-signed URL expiring in 24 hours; all access to the URL is audited And exports complete p95 ≤60s for up to 100,000 records; larger jobs run asynchronously with completion notification And export failures emit AUDIT_EXPORT with outcome=FAILURE and an appropriate reason_code
Reliability, Ordering, and Performance
Given intermittent connectivity When audit events are generated offline Then events are queued locally with sequence_number and flushed within 5s of reconnect And the server de-duplicates via idempotency keys, achieving at-least-once delivery with ≤1 duplicate per 10,000 events And per-session ordering is preserved by sequence_number; global ordering uses (timestamp, event_id) And ingest latency p95 ≤75ms and p99 ≤150ms; failures do not block user actions and are retried with exponential backoff up to 3 minutes And health metrics (success rate, backlog size, latency percentiles) are exposed and alert if breaching thresholds for ≥5 minutes
Access Control and Encryption
Given the audit log contains sensitive data When data is stored and accessed Then all audit data is encrypted in transit (TLS 1.2+) and at rest (AES-256) with KMS-managed keys rotated annually And access is restricted to roles {Admin, Compliance_Officer, Incident_Responder} and scoped to authorized matters; least privilege by default And all read and export actions are themselves audited with actor_id, action, target, timestamp, outcome And API access requires org-scoped tokens, pagination, and rate limiting (≤100 requests/min per user); optional IP allowlisting is supported And failed access attempts return HTTP 403 and are logged with reason_code=PERMISSION_DENIED
One-Tap Resume Analytics & Conversion Insights
"As a product owner, I want visibility into biometric resume success and drop-off so that I can optimize conversion and reduce support."
Description

Instrument funnel analytics to track prompt impressions, passkey availability, biometric success rate, fallback usage, resume-to-completion time, and drop-off points. Segment by device, browser, matter type, and questionnaire version. Surface dashboards and alerts to identify friction (e.g., unsupported browsers) and quantify impact on intake-to-engagement time and support volume.

Acceptance Criteria
Passkey Prompt Impressions & Availability Detection
Given a client lands on an intake resume entry point, When the One-Tap Resume UI is rendered, Then an event 'passkey_prompt_impression' is logged once per session with properties: client_id, session_id, device_type, os, browser_name, browser_version, matter_type, questionnaire_version, timestamp. Given the client’s environment is evaluated for WebAuthn/passkey support, When support is unavailable or disabled, Then an event 'passkey_unavailable' is logged with reason code (unsupported_browser|os_version|blocked_iframe|user_disabled|unknown) within 200ms of evaluation. Given multiple renders occur in a single session, When the prompt is re-shown, Then no additional 'passkey_prompt_impression' is recorded until a new session_id is created. Given intermittent network conditions, When events are queued offline, Then 95%+ of events are delivered within 60 seconds of connectivity restoration. Given data protection requirements, When events are logged, Then no PII (e.g., full name, email, phone) is included in payload properties.
Biometric Outcomes & Fallback Usage Tracking
Given a passkey biometric challenge is initiated, When the user authenticates successfully, Then log 'biometric_success' with challenge_id, latency_ms, attempt_count, and associate it to the latest 'passkey_prompt_impression' via session_id. Given the user fails or cancels biometric authentication, When the challenge ends, Then log 'biometric_failure' with failure_reason (no_biometrics|user_cancel|timeout|no_credential|unknown) and attempt_count. Given a fallback path (magic link, OTP, or manual login) is presented after failure, When the user selects a fallback, Then log 'fallback_used' with fallback_type and path_latency_ms. Given multiple attempts within one session, When outcomes are logged, Then metrics calculate success_rate, failure_rate, and fallback_rate per device_type and browser_name for the selected time window with denominators defined as unique challenge_id counts. Given analytics processing completes, When the daily aggregation job runs, Then success_rate and fallback_rate are updated by 02:00 UTC and visible on dashboards.
Resume-to-Completion Time & Conversion Attribution
Given a user resumes intake from One-Tap, When they reach the last unanswered question, Then log 'resume_started' with question_id and timestamp. Given the same user submits the retainer/first-draft step, When submission succeeds, Then log 'intake_completed' with timestamp and link it to the prior 'resume_started' via session_id to compute resume_to_completion_time_sec. Given multiple resumptions occur, When computing conversion, Then consider only the most recent 'resume_started' preceding each 'intake_completed' within 24 hours. Given a reporting time range is selected, When metrics are displayed, Then show median, p75, and p95 resume_to_completion_time_sec and conversion_rate = intake_completed/resume_started, with counts >= 30 flagged as statistically sufficient. Given outlier sessions (>99th percentile), When aggregating, Then exclude them from percentile computations but display outlier counts separately.
Drop-Off Point Capture by Questionnaire Step
Given a user resumes the questionnaire, When they abandon the flow for >15 minutes of inactivity or close the session, Then log 'drop_off' with last_question_id, step_name, percent_complete, and inactivity_ms. Given the questionnaire changes version, When drop-offs are recorded, Then events include questionnaire_version to enable version-level comparison. Given dashboards compute funnels, When rendering the step chart, Then display top 5 drop-off steps by rate with absolute counts and rates segmented by device_type and browser_name. Given data backfill is required after a schema change, When reprocessing 30 days of events, Then drop-off rates match pre-change baselines within ±2% absolute for overlapping periods.
Segmentation by Device/Browser/Matter/Version
Given raw events include device and context properties, When the dashboard filter is applied for any combination of device_type, os, browser_name/version, matter_type, and questionnaire_version, Then all metrics (impressions, availability rate, biometric success rate, fallback rate, conversion, time statistics) recompute within 3 seconds for 95th percentile queries over the last 30 days. Given an unsupported browser is detected, When events are ingested, Then browser normalization maps user agents to a canonical browser_name/version with 99%+ accuracy verified against a labeled test set. Given a saved segment is created, When a user returns to the dashboard, Then the segment persists and applies identically to chart and table views with matching totals (variance ≤ 0.5%).
Friction Alerts for Unsupported Browsers and Conversion Dips
Given alerting thresholds are configured, When unsupported_browser_rate exceeds 10% over a 15-minute rolling window for any device_type, Then send an alert to configured channels within 2 minutes containing segment details and top user agent strings. Given baseline conversion is established for the past 14 days, When resume_to_completion_conversion drops by ≥5 percentage points for ≥30 minutes (p-value < 0.05 via two-proportion z-test), Then send an alert with affected segments and recent deployments listed. Given an alert fires, When conditions recover for one full window, Then automatically resolve the alert and record 'alert_resolved' with time_to_recover minutes. Given alert noise risk, When three alerts of the same type occur within one hour, Then group subsequent alerts into a single incident thread with deduplicated notifications.
Support Volume Correlation & Impact Quantification
Given support ticket counts are synced hourly from the helpdesk API, When dashboards load, Then display support_volume per hour and overlay with prompt_impressions and unsupported_browser_rate. Given a date range is selected, When computing impact, Then show Pearson correlation between hourly support_volume and unsupported_browser_rate and estimate attributable tickets using a linear model with confidence intervals. Given One-Tap Resume is enabled for a cohort, When comparing to the prior 30-day baseline, Then show delta in average intake_to_engagement_time and support_volume with percent change and 95% confidence intervals. Given data export is requested, When the user clicks Export for the current view, Then a CSV with all filtered metrics is generated within 60 seconds and matches on-screen totals (variance ≤ 0.5%).

Adaptive Magic-Link

If a device can’t use passkeys, the portal automatically offers a time-limited, device-bound magic link as a secure fallback. Firms can set policy (email-first, SMS optional, expiration, one-use) and the flow nudges clients to set up a passkey after sign-in to keep future logins passwordless.

Requirements

Automatic Passkey Capability Check & Fallback Switch
"As a client using an older phone or an in-app browser, I want the portal to automatically offer a secure magic-link when passkeys aren’t available so that I can still sign in quickly without creating a password."
Description

Detect passkey/WebAuthn support and user readiness on the client portal at session start. If unsupported, unavailable, or declined, automatically present the magic-link option without exposing a password flow. Preserve a seamless, mobile-first UX across iOS, Android, and desktop browsers, and remember per-device capability to minimize friction on subsequent visits. Integrate with Briefly’s intake portal session management and permissions so that authenticated sessions map to the correct matter and user profile. Ensure graceful degradation for in-app browsers and private modes, with clear, plain-language prompts suitable for consumer-law clients.

Acceptance Criteria
Detect Passkey Support and Auto-Fallback at Session Start
Given a user opens the client portal and a new session is created When authentication initializes Then if WebAuthn is available and the user has an enrolled passkey for this account, show the passkey prompt within 1 second and do not render any password UI And if WebAuthn is unavailable, blocked, or unsupported, show the magic-link option as the primary path within 1 second and do not render any password UI And if WebAuthn is available but the user explicitly declines the passkey prompt, immediately present the magic-link option and do not render any password UI And the detected capability and user choice are cached per device for 30 days and used to skip redundant checks on subsequent visits
Enforce Magic-Link Policy Configuration (Email/SMS, One-Use, Expiry)
Given firm policy is set to email-first, SMS optional, one-use links, and a 10-minute expiration When a user requests a fallback sign-in Then send a single-use magic link via email immediately and include no password And send an SMS link only if SMS is enabled and the user has a verified mobile number And an expired link (older than 10 minutes) is rejected with an expiration message and an option to request a new link And a link that was already used is rejected with an invalidation message and cannot authenticate again And no password-based sign-in UI is displayed anywhere in the flow
Device-Bound Magic Link and Correct Auth Mapping
Given a magic link is requested from device A for user U and matter M When the link is opened on device B Then authentication is denied with guidance to request a new link on device B And when the link is opened on device A within the valid window, the user is authenticated and the session maps to user U and matter M And the authenticated session inherits the configured intake portal permissions for user U And session timeout and lifetime follow the configured portal policy and are reflected in the session token/cookie
Post-Login Passkey Nudge and Preference Persistence
Given a user signs in via magic link on a device that supports platform passkeys When the dashboard loads Then display a plain-language prompt to set up a passkey with actions "Set up now" and "Not now" And if the user completes setup, subsequent visits on that device default to passkey sign-in without showing magic-link first And if the user selects "Not now", suppress the prompt on that device for at least 14 days while keeping magic-link available
Graceful Degradation in Private Mode and In-App Browsers
Given the portal is opened in a private/incognito session or an in-app browser where WebAuthn is restricted When authentication initializes Then present the magic-link option as the primary path with a short plain-language explanation And ensure the UI meets mobile ergonomics (tap targets 7 44x44 px, no horizontal scroll) and WCAG 2.1 AA contrast And avoid cross-window flows; links open and complete in the same tab on iOS Safari, Android Chrome, and common in-app browsers
Abuse Prevention and Privacy-Safe Messaging for Magic Links
Given multiple magic-link requests are made for the same user or from the same IP within a short period When thresholds are exceeded Then throttle to a maximum of 5 requests per 15 minutes per user/email and 20 per hour per IP with a friendly rate-limit message And each issued link is cryptographically random, auditable, and revokable, and does not disclose account existence in responses or emails And outbound messages include firm display name per configuration and no sensitive data beyond a secure sign-in call-to-action
Cross-Platform Compatibility and Performance
Given users access the portal from iOS Safari, Android Chrome, and desktop Chrome/Edge/Firefox When authentication initializes and completes via passkey or magic-link Then the flow completes without errors across these browsers, with initial render under 2 seconds on 4G and core interactions under 100 ms after first input And no unsupported-browser banner is shown for these versions; if an unsupported version is detected, provide a clear upgrade prompt and magic-link fallback And the same user journey is fully keyboard-accessible on desktop
Firm-Level Magic-Link Policy Configuration
"As a firm admin, I want to set how magic links are delivered and how long they last so that our authentication aligns with our security posture and client communication preferences."
Description

Provide a firm admin console to configure magic-link policies: email-first delivery (default), optional SMS delivery, one-use enforcement, expiration window (e.g., 5–60 minutes), max issuance attempts, and per-matter-type overrides. Validate inputs, surface effective policy in UI tooltips, and store policies per firm tenant. At runtime, enforce policies for issuance, delivery, and consumption, with safe defaults for firms that do not configure. Expose audit-friendly snapshots of policy in effect at the time of each authentication event for compliance and dispute resolution.

Acceptance Criteria
Admin configures firm-wide magic-link policy
Given I am a firm admin on tenant T When I open Settings > Authentication > Magic Link Policy Then email-first delivery is enabled by default And I can toggle optional SMS delivery And I can toggle one-use enforcement (default on) And I can set expiration between 5 and 60 minutes inclusive; out-of-range values are rejected with inline error messaging And I can set max issuance attempts between 1 and 10 inclusive; out-of-range values are rejected with inline error messaging And clicking Save persists changes and page reload shows saved values
Admin defines per-matter-type policy override
Given a firm default policy exists When I create an override for matter type M Then I can configure the same fields as the default with identical validation rules And the override can be enabled or disabled And for authentications linked to M, the override is the effective policy And for other matter types, the firm default remains the effective policy And deleting or disabling the override immediately reverts affected authentications to the firm default
Portal surfaces effective policy via tooltips
Given I am viewing the admin policy page or the client login screen When I hover or tap the policy info icon Then a tooltip displays the effective policy summary: delivery order, allowed channels, one-use setting, expiration (minutes), max issuance attempts, and policy source (Default or Override + matter type) with last modified by and timestamp And the tooltip is accessible via keyboard and screen readers
Runtime policy enforcement on magic-link issuance
Given a user requests a magic link for matter X When the effective policy allows email-first delivery Then the system sends the link to the verified email on file And if SMS delivery is enabled and the user selects SMS, the system sends to a verified E.164-formatted number And issuance attempts are counted per user+matter; exceeding the configured max blocks further issuance with a generic error message and creates an audit entry And each issuance event records a snapshot of the effective policy
Runtime policy enforcement on magic-link consumption
Given a magic link issued under policy P When the link is used within the configured expiration Then the first successful use authenticates the user and consumes the token And any subsequent attempt returns 410 Gone with a generic message and does not authenticate And if used after expiration, the response is 401 Expired and does not authenticate And each consumption event records a snapshot of the effective policy
Safe defaults apply when firm has no policy configured
Given a firm has no stored magic-link policy When a magic link is issued or consumed Then the platform applies defaults: email-first enabled, SMS disabled, one-use enabled, expiration 15 minutes, max attempts 3 And the admin UI shows 'Default' as the policy source with these values And saving without changes creates a firm policy equal to the defaults
Audit snapshot retrieval for compliance
Given authentication issuance and consumption events have occurred When an admin views Audit > Authentication or calls the audit API with an event ID Then they can retrieve an immutable snapshot including: effective policy values, policy source (Default/Override + matter type), policy version ID, actor identity, delivery channel, timestamps, and outcome And modifying policies later does not change historical snapshots And exporting the audit report includes these snapshot fields in a human-readable record
Device-Bound, One-Use, Time-Limited Link Issuance
"As a client, I want a magic link that works only on my device and only once so that my account stays secure even if someone forwards my email."
Description

Generate a cryptographically strong, single-use token that is bound to the requesting device context and expires per firm policy. Bind by issuing a device nonce stored in secure client storage and validated at consumption time, with fallbacks that do not rely solely on IP. On link click, verify token integrity, device binding, expiration, and one-use constraints; then atomically redeem and invalidate the token. Provide clear UX for expired/invalid links with safe retry paths. Store minimal device metadata for security checks while respecting privacy. Integrate with Briefly session creation and redirect the user to the correct matter dashboard post-authentication.

Acceptance Criteria
Token Issuance on Unsupported-Passkey Device
Given a firm has magic-link fallback enabled with an expiration policy of N minutes and one-use enforced When a client on a device that cannot use passkeys requests a login link via the allowed channel (email-first, SMS optional per policy) Then the system generates a token with at least 128 bits of entropy, binds it to a device nonce, signs it server-side, and stores a server record with TTL = N minutes and state = issued And the device nonce is created and persisted in secure, origin-scoped client storage for that device context And the issued link contains only the opaque token (no PII or device metadata in the URL) And issuance respects rate limits of at most M links per user identity per 15 minutes per device (configurable)
Device Binding Validation on Link Consumption
Given a valid issued token and a stored device nonce on the requesting device When the user opens the magic link Then the server verifies token integrity, expiration, and that the presented device nonce matches the nonce bound to the token And acceptance does not depend solely on IP address (token is rejected if only IP matches and the device nonce is missing/mismatched) And if the device nonce is missing or mismatched, the token is not redeemed and the user is offered a safe path to request a new link
Atomic Redemption and One-Use Enforcement
Given a valid token that has not expired When two or more redemption requests occur concurrently Then exactly one request succeeds, the token transitions atomically from issued to redeemed, and all others fail with already-used status And after a successful redemption, any subsequent attempt with the same token fails regardless of timing or device And if the current time is past the configured TTL at redemption attempt, the redemption fails with expired status
Expired/Invalid Link UX with Safe Retry
Given a user opens an expired or already-used/invalid magic link When the portal renders the page Then the UI clearly states the link is expired or invalid without disclosing whether the email/phone is registered And the UI offers actions to Send a new link (respecting rate limits and firm policy) and Use a passkey instead And on selecting Send a new link, a fresh token is issued and previous tokens are invalidated without changing the user’s communication preferences
Privacy-Minimal Device Metadata Storage
Given device metadata is recorded for security checks When storing metadata server-side Then only minimal fields are stored: device nonce reference, hashed user agent fingerprint (salted), OS family, browser family and major version, and coarse network info (e.g., ASN); no precise location or raw user agent string is retained And metadata is encrypted at rest and retained no longer than the firm or platform policy retention window And no metadata is embedded in the link URL or sent to third parties
Session Creation and Matter Dashboard Redirect
Given a token redemption succeeds When the server creates an authenticated session Then a Briefly session is established with secure, HttpOnly, SameSite cookies scoped to the firm tenant And the user is redirected to the correct matter dashboard associated with the login initiation context; if none is available, redirect to the default dashboard And after landing, the UI displays a non-blocking nudge to set up a passkey for future logins
Firm Policy Configuration and Enforcement
Given a firm configures magic-link settings (email-first, SMS optional/disabled, expiration minutes, one-use enforcement) When tokens are issued and redeemed Then issuance uses only the enabled channels, applies the configured expiration, and enforces one-use at redemption And changes to policy take effect for newly issued tokens and are recorded in the audit log with actor, timestamp, and diff And attempting to issue via a disabled channel fails with a clear error and guidance
Adaptive Delivery: Email-First with SMS Optional
"As a client, I want to receive my magic link over email or SMS according to my preferences and what my firm allows so that I can sign in using the channel I actually check."
Description

Implement delivery services that prioritize email and optionally send via SMS when allowed by firm policy and client consent. Support verified sender domains, DKIM/SPF alignment, and deliverability monitoring for email; use registered alphanumeric or short codes for SMS with regional compliance. Provide localized, brandable templates with link safety measures (no sensitive info, no preview leakage). Include deep-linking for iOS/Android and a fallback code entry path when link opening fails. Handle bounced/undeliverable messages and surface actionable errors to the user and firm.

Acceptance Criteria
Email-First Dispatch with Policy Enforcement
Given a client needs a magic-link sign-in and the firm policy is Email-First with SMS optional When the system generates and dispatches the magic link Then the email must be sent from a verified sender domain with aligned SPF and DKIM, and DMARC evaluation not failing And deliverability events (queued, sent, delivered, opened/clicked) are captured and visible in logs within 60 seconds And no SMS is sent unless firm policy enables SMS and the client’s explicit consent is recorded with timestamp and source And if policy requires, SMS is only attempted after an email hard bounce or after staff-triggered resend via SMS And all channel decisions (email, SMS, none) are recorded to the audit log with policy rationale
SMS Optional Delivery with Regional Compliance
Given firm policy enables SMS and the client has provided verifiable consent When sending the magic link by SMS Then the sender must be a registered alphanumeric ID or short code appropriate to the recipient’s region And required compliance text (e.g., STOP to opt out, HELP for help) is included where mandated and opt-outs are honored within 1 minute And the message contains no sensitive personal or case information and only an opaque HTTPS link token And carrier delivery status (queued, sent, delivered, failed) and error codes are stored, with hard failures preventing automatic retries And messages to restricted regions or unregistered sender routes are blocked and surfaced with a clear error to staff
Localized, Brandable Templates without Preview Leakage
Given a firm’s selected locale, brand assets, and template configuration When composing and sending the magic-link email and SMS Then the content is localized to the recipient’s locale and uses firm name/logo/colors per configuration And the subject and body contain no client PII, matter numbers, or sensitive details And links use a firm-branded HTTPS domain and contain only an opaque token (no identifiable query parameters) And the landing page for the link sets headers/meta to minimize preview leakage and does not display client-specific content until after verification And template rendering passes automated lint checks for prohibited tokens and fails the send if violations are detected
Deep Linking to iOS/Android with Fallback Code Entry
Given a recipient device supports iOS Universal Links or Android App Links and the Briefly app is installed When the recipient taps the magic link Then the native app opens directly and receives the token; otherwise the mobile web flow opens And deep-link success or fallback is recorded as a metric and in the audit log And if link opening fails or is blocked, a Try code instead option is shown within 2 seconds And the recipient can request and enter a short-lived verification code to complete sign-in without the link And the code path enforces the same expiration and one-use policies as the link
Bounce and Undeliverable Handling with Actionable Errors
Given an email hard bounce, soft bounce, or SMS delivery failure occurs When the provider returns a failure status or bounce event Then the client UI displays a clear message with retry or channel-switch options and no sensitive details And the firm dashboard shows the failure with provider code, human-readable reason, and recommended next actions (e.g., correct address, use SMS) And hard bounces and SMS opt-outs add the address/number to a suppression list and prevent further automated sends And staff can override only after updating contact info or recording new consent, with all actions audited And all retries respect cooldown rules and do not exceed policy-defined attempt limits
Expiration, One-Use, and Device Binding Enforcement
Given firm policy defines a magic-link expiration window (e.g., 15 minutes) and one-use behavior When a recipient attempts to use the link Then the link is valid only within the policy window and on the first successful use And subsequent uses or uses after expiration return specific error states and offer to resend a new link And the first successful use binds the token to the initiating device; attempts from a different device require re-verification or a new link And each outcome (success, expired, re-use, device-mismatch) is logged with timestamp, channel, and device metadata
Post-Sign-In Passkey Enrollment Nudge
"As a client who signed in with a magic link, I want a simple prompt to set up a passkey so that my future logins are instant and secure without needing links."
Description

After a successful magic-link sign-in, prompt eligible devices to enroll a passkey to keep future logins passwordless and faster. Detect platform availability, present clear value messaging tailored for non-technical users, and support defer/dismiss with respectful reminder cadence. Track enrollment conversion per device without degrading privacy. Integrate with existing account security settings so users can manage registered passkeys and see device names. Ensure accessibility, localization, and mobile-first layouts consistent with Briefly’s portal UI.

Acceptance Criteria
Nudge Display on Eligible Devices After Magic-Link Sign-In
Given the user completes sign-in via magic link on a device with platform authenticator support and no passkey registered for this account on that device When the post-auth landing page renders Then display a non-blocking passkey enrollment nudge within 800 ms And include a primary action labeled "Set up passkey" and a secondary action labeled "Not now" And present copy that avoids technical jargon and reads at grade 7 or below (Flesch-Kincaid) And do not render the nudge if the device already has a registered passkey for this account And record exactly one nudge impression event per session
Platform Capability Detection and Safe Fallback
Given the device or browser does not support user-verifying platform authenticators or WebAuthn creation When the user signs in via magic link Then do not display the passkey enrollment nudge And log a single "nudge_skipped_ineligible" event for the session And do not attempt to invoke WebAuthn APIs And surface a "Passkeys not available on this device" explainer link within Account Security > Passkeys
Defer and Dismiss with Respectful Reminder Cadence
Given the nudge is shown on an eligible device When the user selects "Not now" Then snooze the nudge for 14 days on that device and do not show it again during that period And do not show the nudge more than once per session or more than twice per week on that device When the user selects "Don’t ask again on this device" Then suppress the nudge permanently for that device until the user re-enables prompts from Account Security > Passkeys And store only device-local preferences (no server-side PII) for snooze/suppress state
Passkey Enrollment Flow Success and Error Handling
Given an eligible device and the user clicks "Set up passkey" When WebAuthn create() is initiated with rp.id matching the portal domain, attestation set to "none", residentKey set to "preferred" or "required", and userVerification set to "required" Then prompt the platform authenticator and complete registration successfully And display a success confirmation and close the nudge When the user cancels or the operation times out Then show an inline, human-readable error with retry option and no page reload When the browser returns NotSupportedError or SecurityError Then gracefully close the flow, record a failure event, and do not re-prompt in the same session
Account Security Integration and Device Management
Given the user completes passkey enrollment When the user opens Account Security > Passkeys Then show the newly registered passkey with a friendly device name (from platform where available, otherwise a generic OS-based label) And show metadata: added date/time and last used date/time And allow the user to rename the device label and remove the passkey When the user removes the passkey Then delete the credential server-side and stop offering it for authentication And re-enable the enrollment nudge on that device in subsequent sessions
Privacy-Preserving Enrollment Conversion Tracking
Given the nudge is displayed, clicked, or completed When telemetry is recorded Then only the following fields are sent: tenant identifier, locale, capability flags, nudge variant, event type, and a rotating, device-local pseudonymous ID scoped to this tenant And no full User-Agent string, IP address, screen dimensions, or hardware identifiers are stored or transmitted And no third-party analytics endpoints are used And data retention for nudge events does not exceed 30 days And a user privacy toggle disables all nudge telemetry immediately
Accessibility, Localization, and Mobile-First Compliance
Given the nudge is rendered on any supported device When navigated with keyboard only Then focus order is logical, focus is visible, and all actions are reachable without pointer input And screen readers announce the nudge via aria-live="polite" with meaningful labels on all controls And color contrast meets WCAG 2.2 AA (>= 4.5:1 for text, >= 3:1 for large text and UI components) And interactive targets are at least 44x44 px on touch devices When viewed on 320 px width at 400% zoom Then no horizontal scrolling is required and content remains readable and operable When locale is changed between en-US and es-US Then all nudge strings are fully localized and text expansion does not break layout And right-to-left languages render correctly with mirrored layout And the nudge loads without causing cumulative layout shift greater than 0.1
Abuse Prevention & Rate Limiting
"As a firm security lead, I want safeguards that prevent spam and brute-force attempts on magic links so that our clients can authenticate safely without service disruption."
Description

Protect the magic-link flow from abuse with layered defenses: per-identity, per-device, and per-IP issuance throttles; link-click rate limits; enumeration-resistant error messages; optional human verification after thresholds; and anomaly detection for unusual request patterns. Block disposable/known-abusive email domains per policy, and require contact verification before first issue. Provide observability dashboards and alerts for spikes. All controls must be configurable within safe bounds and documented for firms. Ensure defenses do not unduly hinder legitimate clients on mobile networks.

Acceptance Criteria
Layered Issuance Throttles (Identity, Device, IP, Mobile-NAT Tolerance)
Given firm policy thresholds are set to identity=3 per 15m, device=3 per 15m, IP=30 per 5m (burst 60) When a client requests magic links repeatedly Then requests exceeding the identity limit within 15m are rejected with a generic response and a 429 is logged internally And requests exceeding the device limit within 15m are rejected with a generic response and a 429 is logged internally And requests exceeding the IP token-bucket are delayed or rejected with a generic response and a 429 is logged internally And throttle counters decay after their windows and issuance resumes automatically And rate limiting does not exceed a 5% false-positive rate for a test of 100 unique verified clients behind a single mobile NAT IP requesting 1 link each within 2 minutes And all throttle events are attributed to identity, device, and IP in logs with timestamps and policy version
Magic-Link Consumption Controls (Click Rate Limiting and One-Use Enforcement)
Given a magic link configured as one-use, expiring in 15 minutes, bound to device fingerprint D When the link is clicked multiple times before first successful sign-in Then no more than 3 validation attempts per 60 seconds are processed; excess clicks return the generic "link unavailable" response without state change And upon first successful consumption on device D, the link is invalidated for all devices And subsequent clicks return the same generic "link unavailable" response and are logged as reuse attempts And consumption on a non-matching device is rejected with the generic response and logged as device-mismatch And no additional links are auto-issued as a side effect of clicking
Enumeration-Resistant Messaging on Issue and Consume
Given an email address that is not registered, registered, or blocked by policy When a user requests a magic link Then the UI and API respond with the same generic success message and no timing side-channel exceeding 50ms median difference across cases And error details are only captured in server logs and metrics And HTTP status codes do not reveal existence or policy status of the identity (200/202 used consistently)
Disposable Domain Blocking and First-Issue Contact Verification
Given a denylist containing disposable.example and abusive.example and first-issue contact verification enabled When a user enters address user@disposable.example Then the request is not issued, the user sees the generic success message, and a "blocked_domain" event is logged with domain and policy reference When a new identity user@legit.example requests first magic link Then the system sends a 6-digit verification code to the contact channel per firm policy and requires successful entry before issuing the magic link And verification codes expire in 10 minutes, allow 5 attempts, and lock out for 15 minutes upon exhaustion with generic messaging And admins can override per domain via policy; changes are audited
Adaptive Human Verification After Abuse Thresholds
Given human verification is enabled with trigger rules: 2 throttles or 5 requests within 1 minute per identity or per IP When a client exceeds a trigger Then a human-verification challenge is required before further issuance attempts are processed And passing the challenge unblocks attempts for the next 30 minutes for that actor; failing or skipping keeps the block in place And the challenge is accessible (keyboard and screen-reader compatible) and available on mobile And admins can set provider and thresholds within safe bounds; all challenges and outcomes are logged
Anomaly Detection with Observability Dashboards and Alerts
Given dashboards expose metrics: issuance rate by identity/device/IP, throttle counts, blocked domains, challenges triggered/completed, click reuse attempts, error rate, and p95 latency When request volume or throttle rate deviates >3 standard deviations from the 7-day baseline for 5 consecutive minutes Then an alert is sent to configured channels (email and Slack/Webhook) with context (firm, metric, dimension, links to dashboard) And dashboards update within 1 minute and support filtering by firm and time window And all metrics are retained for at least 30 days and exportable as CSV and via API
Configurable Controls with Safe Bounds and Admin Documentation
Given an admin opens the Abuse Prevention settings When they view and edit thresholds and policies Then all controls are editable within enforced safe bounds (e.g., identity limit 1–20/15m, IP limit 10–200/5m, link expiry 5–60m, click rate 1–10/min) And invalid or unsafe values are rejected with inline guidance and links to documentation And changes require confirmation, are versioned with actor, timestamp, and diffs, and take effect within 5 minutes And a "Restore Defaults" action reverts to documented defaults and logs an audit event And in-product docs clearly describe each control, its impact, and recommended settings
Authentication Event Audit Trail
"As a compliance officer, I want a complete audit history of magic-link authentication events so that we can demonstrate due diligence and investigate incidents when needed."
Description

Record an immutable audit trail for the adaptive auth flow, including capability detection results, link issuance (policy snapshot, channel, TTL), delivery outcomes, redemption attempts, success/failure reasons, and final session creation. Associate events with the client, firm tenant, and relevant matter while redacting sensitive content. Provide time-filtered views and export (CSV/JSON) for compliance inquiries and incident response. Respect data retention policies per firm and regional requirements, and surface consent status for SMS where applicable.

Acceptance Criteria
Immutable Audit Store and Redacted Event Schema
Given the audit service is operational When an authentication-related event is emitted Then the event is written to an append-only store and update/delete operations via public APIs are disallowed And the event includes: event_type (from a controlled enum), ISO-8601 UTC timestamp with millisecond precision, client_id, firm_tenant_id, matter_id, and correlation_id (non-null) And sensitive values are redacted: magic_link token not stored, email stored as domain plus hashed local-part, phone stored as E.164 last-4 with full hashed value, IP stored as /24 (IPv4) or /64 (IPv6) network, device fingerprint stored as salted hash And each event includes an integrity_hash and previous_hash to form a tamper-evident chain per tenant-day And a Verify Integrity endpoint returns status=ok for a continuous chain over the requested range
Capability Detection Logged
Given a client opens the authentication portal When capability detection executes Then an audit event with event_type=capability_detected is recorded with fields: passkey_supported (boolean), platform, browser_name, browser_version, webauthn_available (boolean), fallback_reason (nullable) And the event is associated to client_id (if known), firm_tenant_id, matter_id (if known), and correlation_id And no device identifiers beyond salted hashes and user_agent string are stored
Magic Link Issuance Logged with Policy Snapshot
Given passkeys are unavailable or policy requires magic link fallback When a magic link is issued Then an audit event with event_type=magic_link_issued is recorded with fields: channel (email|sms), ttl_seconds, one_use (boolean), device_binding (boolean), policy_snapshot_id, correlation_id And the destination is redacted: for email store domain and hashed local-part; for SMS store country code and last-2 with hashed full number And the magic link token is stored only as a salted hash and never in plaintext And client_id, firm_tenant_id, and matter_id are present
Delivery Outcome and SMS Consent Status Logged
Given a magic link has been issued When the delivery provider returns a response Then an audit event with event_type=delivery_outcome is recorded with fields: provider, provider_message_id (hashed), status (sent|delivered|bounced|failed), provider_code, channel (email|sms), correlation_id And if channel=sms, the event includes sms_consent_status (consented|not_consented|unknown), consent_source, consent_timestamp (nullable) And if sms_consent_status is not_consented or unknown, an audit event with event_type=delivery_suppressed is recorded and no send is attempted
Redemption Attempts, Replay Protection, and Session Creation Logged
Given a magic link exists for a correlation_id When a user clicks the magic link Then an audit event with event_type=redemption_attempt is recorded with fields: device_binding_match (boolean), ip_truncated, user_agent, correlation_id And if the link is valid and device_binding_match is true and ttl not expired, an event event_type=redemption_succeeded is recorded And upon successful redemption, an event event_type=session_created is recorded with session_id_hash and session_expiry_utc And if redemption fails, an event event_type=redemption_failed is recorded with reason (expired|already_used|device_mismatch|invalid|throttled) And any subsequent use of an already used token records event_type=replay_detected linked to the original issuance And events for the same correlation_id are ordered by timestamp with millisecond precision in views and exports
Time-Filtered Views and Export (CSV/JSON) for Compliance
Given a firm admin with audit privileges opens the Audit Trail view When filters are applied for time range (UTC), event_type, client_id, matter_id, and correlation_id Then the list returns only matching events for the firm_tenant within 2 seconds for the first 100 results and supports pagination And timestamps display in admin-selected timezone while exports remain ISO-8601 UTC And when Export CSV is requested, a CSV is generated with a header row and redacted fields only; when Export JSON is requested, a JSON array is generated with the same field set And exports include metadata: generated_at_utc, filter_snapshot, total_count And exporting more than 100k events streams results without timeouts and preserves chronological order
Data Retention, Regional Policies, and Legal Hold Enforcement
Given a firm_tenant has a configured retention_ttl and data_region When an event ages beyond retention_ttl and no legal hold exists Then the event is purge-eligible and is hard-deleted within 24 hours and excluded from views and exports And a daily audit of purges records event counts by event_type and date without revealing redacted content And when a legal hold is applied to a client_id or matter_id, all related events are excluded from purge until the hold is removed And events are stored and exported from the configured data_region; cross-region export requests are denied

Trusted Delegate

Clients can securely delegate intake to a helper (spouse, translator, caregiver) via a restricted, expiring access link with configurable field visibility (e.g., hide SSN/DOB) and optional e-sign limits. All delegate actions are logged, reducing stalled intakes without exposing unnecessary PII.

Requirements

Secure Delegate Invitation & Expiring Access Links
"As a client, I want to securely invite a trusted helper via an expiring link so that they can complete my intake without risking my personal data."
Description

Enable clients to invite a trusted helper via email or SMS to complete intake through a short-lived, tokenized link with configurable expiration (e.g., 24–168 hours), one-time use, and optional SMS/OTP gate. Invitations are generated from the intake flow or client portal, can be resent, revoked, or extended, and are stored as hashed tokens with rate limiting and IP/device fingerprinting. The link routes the delegate into a restricted intake experience scoped to a single matter, honoring locale and mobile-first UX. Server-side enforcement validates token state on every request and denies access on expiration/revocation. Event hooks/webhooks allow downstream automations (e.g., notify staff, pause auto-assembly until review).

Acceptance Criteria
Invite Delegate from Intake Flow or Client Portal with Configurable Expiration
Given a client in the intake flow or client portal selects "Invite a delegate" And enters the delegate’s email or mobile number And sets an expiration between 24 and 168 hours (default 72) When the invitation is created Then a one-time, tokenized link scoped to the selected matter is generated And only a salted hash of the token is stored server-side And the system records inviter_id, matter_id, expiration_at, delivery_channel, and locale And the link is delivered via the chosen channel with the full URL redacted from logs And an audit event "delegate.invite.created" is recorded
One-Time Use Link with Per-Request Server-Side Validation
Given a valid, unexpired delegate token When the delegate opens the link for the first time Then access to the restricted delegate intake is granted And subsequent requests are validated server-side for token existence, expiration, revocation, matter scope, and single-use status And any second attempt to use the link from a different device/session or after completion returns HTTP 401 with a neutral message and no PII exposure And an audit event "delegate.link.reuse_blocked" is recorded on blocked attempts
Optional SMS/OTP Gate Before Delegate Access
Given OTP protection is enabled for the invitation When the delegate opens the link Then a 6-digit OTP is sent via the configured channel and expires in 10 minutes And a maximum of 5 verification attempts are allowed before the invitation is locked And successful verification grants access; failed or expired codes do not disclose PII And events "delegate.otp.sent" and "delegate.otp.verified" or "delegate.otp.failed" are emitted
Resend, Revoke, and Extend Invitation Controls
Given an active invitation When the inviter resends the invitation Then the same token is re-delivered and "delegate.invite.resent" is logged When the inviter revokes the invitation Then token status becomes "revoked" immediately; all subsequent requests return HTTP 401; "delegate.invite.revoked" is logged When the inviter extends expiration to a value within 24–168 hours from creation Then expiration_at updates and "delegate.invite.expiration.updated" is logged
Rate Limiting and IP/Device Fingerprinting for Delegate Endpoints
Given any delegate invitation token endpoint When more than 10 access requests per minute are made from the same IP+invitation_id Then subsequent requests within that minute return HTTP 429 And OTP verification is limited to 5 attempts per 10 minutes per invitation_id And resend actions are limited to 3 per hour and 10 per day per invitation_id And the system records IP address and device fingerprint on first successful access And security events are emitted on threshold breaches
Restricted Intake Scope, Field Visibility, Locale, and Mobile-First UX
Given delegate access is granted When the delegate views the intake Then only the delegated matter is accessible and navigation outside is blocked And fields flagged as hidden (e.g., SSN, DOB) are neither rendered in the UI nor returned by APIs And e-sign actions follow configured limits (e.g., disabled or limited to certain documents) And UI locale matches the inviter’s locale for language, date, and number formats And on a 375px-wide device over a 3G network, the first form view renders within 2 seconds, inputs are usable, and tap targets are at least 44x44px And all delegate actions (view, edit, save, submit) are logged with timestamp, IP, user agent, and field-level changes
Webhooks and Event Hooks for Delegate Lifecycle
Given webhooks are configured for delegate events When an invitation is created, opened, otp_verified, submitted, revoked, or expired Then a webhook is delivered within 10 seconds including event type, invitation_id, matter_id, occurred_at, and an HMAC-SHA256 signature And deliveries are idempotent via a unique event_id and retried with exponential backoff for up to 24 hours until a 2xx response is received And staff notifications are sent on "submitted" and "failed_verification" And matters with active delegate sessions pause automatic document assembly until delegate submission or staff override
Field-Level Visibility & Edit Controls
"As an attorney, I want to configure which fields a delegate can see or edit so that sensitive PII remains protected while still allowing intake to progress."
Description

Provide granular, backend-enforced controls that determine which questionnaire fields a delegate can view, see masked (e.g., SSN last4), edit, or are fully hidden. Controls are configurable at template level with presets (Sensitive PII, Financials, Government IDs) and overridable per matter by the attorney or client. Conditional logic respects visibility rules (hidden fields remain inaccessible even if triggered). UI clearly labels restricted sections and prevents uploads where disallowed. A delegate preview mode lets staff verify the experience before sending. All enforcement occurs server-side and propagates to APIs, exports, and document assembly, ensuring hidden data is never exposed or inferred. Changes to visibility settings trigger immediate session re-evaluation.

Acceptance Criteria
Template Presets Control Delegate Visibility
Given a questionnaire template with fields tagged to presets (Sensitive PII, Financials, Government IDs) And a matter selects the "Sensitive PII" preset for delegate intake When a delegate opens the intake link Then fields mapped as Hidden are not rendered client-side nor delivered by the API And fields mapped as Masked display masked values (e.g., SSN ****-**-1234, DOB mm/yyyy) And fields mapped as Read-Only show values but cannot be edited And an audit event "preset_applied" is recorded with preset name, templateVersion, matterId, actorId, and timestamp
Server-Side Blocking of Hidden Field Access
Given a delegate session with a valid token When the client or any API call requests a field marked Hidden for delegates Then the server responds 403 Forbidden with errorCode "FIELD_HIDDEN" and excludes the field from payloads And no partial value, metadata, or validation hints about the field are returned And an "access_blocked" audit entry is stored with fieldId, reason, ipAddress, userAgent, and timestamp
Conditional Logic Cannot Reveal Hidden Fields
Given field B is configured Hidden for delegates and is a dependency for conditional display of section C When the delegate provides answers that would normally display section C Then section C does not appear if it would expose field B or its value And no validation or progress indicators reference field B And server-side validation does not require field B for delegate submissions And computed labels, counts, or required markers do not change in a way that reveals field B exists
Per-Matter Overrides With Immediate Re-Evaluation
Given an attorney or client changes a field's delegate permission from Editable to Hidden on an active matter When the change is saved Then within 5 seconds the delegate session policy is re-evaluated and the field is removed from the UI and API responses And any in-flight autosave including the field is rejected with 409 Conflict; the submitted value is discarded server-side And an audit event "visibility_override" records before/after states, actorId, matterId, and timestamp
Delegate Preview Parity and Safety
Given staff opens Delegate Preview for a matter with specific presets and overrides When interacting with the form in preview Then visible fields, masking, editability, conditional behavior, and upload restrictions exactly match a real delegate session And preview writes to an isolated sandbox store; no production answers or audit entries are created And submission (including e-sign) is disabled in preview and clearly labeled "Preview"
Upload Restrictions Enforced and Labeled
Given a file upload field is configured as Disallowed for delegates When a delegate attempts to upload a file via the UI or direct upload endpoint Then the UI prevents file selection with a tooltip "Uploads not allowed for delegates" And any direct upload attempt is rejected server-side with 403 Forbidden and errorCode "UPLOAD_DISALLOWED" And no object storage artifacts are persisted; any pre-signed URLs are invalidated And the section header displays a "Restricted" label matching design spec
Data Propagation to APIs, Exports, and Document Assembly
Given a matter contains fields configured as Hidden and Masked for delegates When generating API responses, CSV/PDF exports, and assembled documents for that matter during a delegate session Then Hidden fields are omitted entirely (keys removed); Masked fields contain only masked values And merge tags for Hidden fields resolve to null/placeholder without leaking via formatting, comments, or revision metadata And derived/calculated fields do not reveal underlying hidden inputs And an automated compliance test verifies zero occurrences of hidden raw values across artifacts
Delegate Identity & Attestation Capture
"As a firm, I want to capture a delegate’s identity and authorization attestation so that I can document permission and translator certifications for compliance and quality control."
Description

Collect delegate name, contact details, relationship to client, preferred language, and optional identity proofing (ID upload or selfie check where permitted). Require an attestation at session start and submit that the delegate is authorized to provide information on the client’s behalf and that answers are truthful to the best of their knowledge. Provide a translator-specific certification flow with language pair, certification status, and e-sign for the attestation only. Persist these artifacts in the matter record and surface them in the final intake packet and audit exports.

Acceptance Criteria
Delegate Info Collection and Validation
Given a delegate opens a valid Trusted Delegate link on mobile or desktop When they begin the session Then the form requires Full Name, Email OR Mobile Phone, Relationship to Client, and Preferred Language before proceeding Given the delegate enters contact details When validation runs Then at least one contact method (email or phone) is present and valid (email format or E.164/10-digit phone) And inline errors display for invalid inputs And the Next/Continue button remains disabled until errors are resolved Given valid inputs are provided When the delegate saves Then the values are persisted to the matter record with created_at timestamp, link_id, and user_agent metadata Given the matter is re-opened by staff When viewing delegate details Then previously saved values are present and accurately reflect the last saved state
Dual Attestation at Session Start and Submission
Given the delegate reaches the welcome screen When proceeding to intake Then the authorization and truthfulness attestation is displayed and requires explicit affirmation (required checkbox plus typed full name or e-sign capture) before any questions are shown Given the delegate attempts to submit the intake When tapping Submit/Finish Then the same attestation text is re-presented for confirmation and requires explicit affirmation before submission is accepted Given both attestations are affirmed When persisting artifacts Then two distinct artifacts (start and submit) are stored with content hash, timestamp (ISO 8601), IP address, user_agent, and link_id; progression/submit is blocked if affirmation is missing
Optional Identity Proofing - ID Upload or Selfie Check
Given identity proofing is enabled for the firm and permitted in the delegate’s jurisdiction When the delegate reaches the Identity step Then they can choose Government ID Upload or Selfie/Liveness Check Given Government ID Upload is selected When images are uploaded Then only jpg, png, or pdf up to 10 MB each are accepted And successful upload stores encrypted artifacts and sets status to "verified" after automated checks; failures set status to "failed" with a machine-readable reason code Given Selfie/Liveness Check is selected When the check runs Then the system records pass/fail; on fail, one retry is offered; after retry, status is set to "failed" with reason or "verified" on pass Given identity proofing is configured as optional When the delegate chooses Skip Then status "skipped" is recorded with selected reason and intake continues Given identity proofing is disabled or not permitted When rendering the flow Then the Identity step is not shown
Translator Certification Flow
Given the delegate selects "Translator/Interpreter" as their role/relationship When proceeding Then a Translator Certification screen is shown capturing Source Language, Target Language, Certification Status (Certified/Not Certified), and optional Certification/License Number Given the translator completes the certification screen When presented with the translator attestation Then they must e-sign the translator attestation; the system must not prompt them to e-sign the full intake or retainer Given the translator attestation is affirmed When persisting Then the matter record stores language pair, certification status, e-sign artifact, timestamp, IP, and link_id Given the delegate is not a translator When proceeding through intake Then the Translator Certification screen and translator attestation are not shown
Persistence in Matter Record and Surfacing in Packet and Audit Exports
Given the delegate session is completed (submit) or partially completed (saved) When viewing the matter record in the admin UI or via API Then delegate profile fields, attestation artifacts (start and submit), identity proofing statuses/artifacts, and translator certification (if any) are present and queryable Given the final intake packet is generated When opening the PDF Then a Delegate section summarizes delegate identity fields, attestation timestamps, translator certification (if applicable), and identity proofing status; redacted media (e.g., ID images) are excluded unless explicitly configured to include Given an audit export is requested for the matter When exporting CSV/JSON Then it includes discrete events for attestation start, attestation submit, ID upload, selfie check, with event type, timestamp (ISO 8601 UTC), IP, user_agent, link_id, and outcome (verified/failed/skipped)
Localization and Accessibility for Delegate Flows
Given a Preferred Language is captured and supported When rendering attestation text, certification prompts, and identity instructions Then content is displayed in the preferred language; otherwise defaults to English with a notice Given the delegate uses a keyboard or screen reader When navigating attestation and identity steps Then all interactive controls are keyboard-operable, have accessible names, and meet WCAG 2.1 AA contrast ratios Given language pair and timestamps are stored When surfaced via API or export Then language tags conform to IETF BCP 47 and timestamps to ISO 8601
E-Sign Permission Limits & Routing Safeguards
"As an attorney, I want to limit which documents a delegate can e-sign so that only the client executes binding agreements while helpers can acknowledge limited attestations."
Description

Allow configuration of which documents a delegate may or may not sign (e.g., delegate may sign a translator attestation but not the retainer). Enforce routing so that legally binding signatures are sent only to the client, with optional SMS OTP or KBA. Block finalization steps until required client signatures are complete, and clearly label any signatures collected from a delegate in the signing certificate. Integrate with existing e-sign provider, preserving envelope IDs and audit metadata. Provide fallback flows (e.g., witness signature) when delegate is allowed to sign specific non-binding acknowledgments.

Acceptance Criteria
Delegate Signing Permissions: Non‑Binding Allowed, Binding Prohibited
Given a matter where "Translator Attestation" is marked delegate-signable and "Retainer Agreement" is marked client-only When the delegate opens the signing package via their restricted link Then the "Translator Attestation" displays active signature fields for the delegate And the "Retainer Agreement" is not signable by the delegate (no signature controls) and any direct-sign attempts are blocked with an authorization error And an audit entry is recorded with actor=delegate, action=sign_blocked, document="Retainer Agreement"
Routing Safeguards: Client‑Only Binding Signature With Optional OTP/KBA
Given a retainer that requires a legally binding client signature and verification settings are configured (SMS OTP and/or KBA) When the client opens their signing request Then the client must successfully complete the configured verification step(s) before any signature field becomes actionable And if verification fails, the signature is not accepted and an audit entry records failure reason and method And no binding signature request is ever sent to the delegate
Finalization Blocked Until Client Signatures Complete
Given a matter with one or more required client signatures outstanding When a user attempts to finalize the matter or send court-ready documents Then the action is prevented And the UI lists the specific documents and signature roles that are incomplete And the system allows the action only after the required client signatures are completed
Delegate Signature Labeling in Signing Certificate
Given a document signed by a delegate When the signing certificate/audit trail is generated Then the certificate clearly labels the signer as "Delegate" and includes delegate name, relationship (if provided), and verification method And delegate-signed fields are distinctly marked as non-binding or acknowledgment-only per configuration
E‑Sign Provider Integration: Envelope ID and Audit Preservation
Given an envelope is created through the existing e-sign provider When signatures are collected from client and/or delegate Then the original provider envelope ID is stored with the matter and shown in activity logs and the certificate of completion And provider-native audit metadata (timestamps, IPs, signer roles) remains intact and accessible from Briefly
Configurable Per‑Document Delegate Sign Policy
Given an admin configures per-document settings to allow or disallow delegate signatures When the settings are saved Then new signing packages honor the updated policy for each document And previously sent envelopes retain their original policy and are unaffected And the API exposes the effective sign policy for each document in the matter
Fallback Witness Flow for Delegate‑Signed Acknowledgment
Given a non-binding acknowledgment is configured to require a witness when signed by a delegate When the delegate completes their signature on that acknowledgment Then the system automatically routes a witness signature request to the designated witness And the document is marked complete only after the witness signature is captured And the audit trail reflects the witness's details and the dependency on the delegate's signature
Audit Trail & Immutable Activity Log
"As an attorney, I want a complete, immutable audit trail of delegate actions so that I can demonstrate chain of custody and resolve disputes about who did what and when."
Description

Record a tamper-evident, time-stamped log of all delegate-related events: invitations sent, link views, authentications, field views/edits with before/after diffs, file uploads, e-sign actions, revocations/expirations, IP/device, and user agent. Present this timeline within the matter and make it exportable as PDF/JSON with hash-based integrity verification. Provide filters to isolate delegate actions versus client actions and highlight any edits to sensitive fields. Store retention consistent with firm policy and surface alerts on anomalous patterns (e.g., rapid multi-field changes from new device).

Acceptance Criteria
Delegate Invitation and Access Events Logged
Given a matter with Trusted Delegate enabled When an attorney sends a delegate invitation Then an "invitation_sent" event is recorded with matter_id, actor_id, delegate_contact_redacted, visibility_profile_id, esign_limits, invite_token_id, expires_at (UTC), created_at (UTC), actor_ip, actor_user_agent, actor_device_id When the delegate opens the invitation link Then a "link_viewed" event is recorded with created_at (UTC), delegate_ip, delegate_user_agent, delegate_device_id When the delegate attempts authentication Then a "delegate_auth" event is recorded with outcome (success|fail), method, created_at (UTC), ip, device_id, user_agent When the attorney revokes the invitation Then an "invite_revoked" event is recorded with revoked_by, created_at (UTC) When the invitation expires unused Then an "invite_expired" event is recorded with expires_at (UTC) Then all events include unique event_id and are timestamped in UTC with millisecond precision
Field Views, Edits, and Sensitive Highlighting
Given a delegate is authenticated on a matter When the delegate views a form field Then a "field_viewed" event is recorded with field_key, is_sensitive (true|false), created_at (UTC), ip, device_id When the delegate edits a form field Then a "field_edited" event is recorded with field_key, is_sensitive, previous_value_sha256, new_value_sha256, text_diff (if applicable), edited_by (delegate_id), created_at (UTC), ip, device_id Then sensitive fields (e.g., SSN, DOB) are masked in UI and exports, showing only a redacted preview while hashes/diffs remain verifiable And the timeline visually flags any field_edited where is_sensitive = true
File Uploads and E‑Sign Actions Logged
Given a delegate has access to the matter When the delegate uploads a file Then a "file_uploaded" event is recorded with file_id, original_filename, mime_type, size_bytes, file_sha256, storage_location_id, uploaded_by, created_at (UTC), ip, device_id, antivirus_scan_result When any user views, consents, signs, or declines an e‑sign document Then an "esign_action" event is recorded with doc_id, doc_sha256, action (view|consent|sign|decline), actor_type (delegate|client|attorney), actor_id, created_at (UTC), ip, device_id, user_agent, signature_method (typed|drawn|stamp|NA), action_result (success|denied) When a delegate attempts a disallowed e‑sign action due to e‑sign limits Then the action is blocked and an "esign_denied" event is recorded with reason, created_at (UTC)
Immutable Audit Log and Verifiable Export
Given the audit store is operational When an event is written Then it is assigned immutable event_id and content_sha256 and linked via previous_event_sha256 to form an append‑only hash chain When any process attempts to update or delete an existing event Then the operation is rejected and an "audit_write_violation" event is appended without altering the original When the verification endpoint is called with a matter_id or export package Then it recomputes the chain and returns status "valid" if all hashes match, else "invalid" with the first mismatched event_id When the user exports the audit trail to JSON Then the file contains schema_version (semantic version), the selected event set, per‑event content_sha256 and previous_event_sha256, an overall audit_sha256, and generated_at (UTC) When the user exports the audit trail to PDF Then the PDF contains the same event set, a summary page with audit_sha256, generated_at (UTC), and a QR/URL to the verification endpoint When the verification endpoint is called with the export audit_sha256 Then it returns "valid" if the export matches the server’s chain for that event set, else "invalid"
Matter Timeline View with Filters and Sensitive Highlights
Given a matter with recorded audit events When the user opens the Audit Trail tab Then a reverse‑chronological timeline is displayed with event_type, actor_type, summary, timestamp (UTC), and access to ip/device/user_agent details When the user applies filters (actor_type = delegate, event_type in [field_edited, file_uploaded, esign_action], and a date_range) Then only matching events are shown and counts reflect the filtered set When the "Show sensitive edits only" toggle is enabled Then only events where is_sensitive = true are displayed and visually highlighted When "Compare change" is clicked on a field_edited event Then a redacted diff view is shown without exposing full sensitive values
Retention Policy Enforcement and Purge Markers
Given the firm retention policy is configured (e.g., 7 years) When an event’s age exceeds the retention period Then it is purged by the retention job and a "retention_purge" marker event is appended with purge_window, count_purged, hash_of_last_purged, and created_at (UTC) When an export is generated after a purge Then purged events are excluded and the corresponding retention_purge marker(s) are included When an admin updates the retention policy Then a "retention_policy_changed" event is recorded with old_value, new_value, actor_id, and created_at (UTC), and the new policy applies to subsequent purges
Anomalous Activity Detection and Alerts
Given anomaly detection is enabled with default thresholds When a new device_id performs 10 or more field_edited events within 2 minutes on a matter Then an "anomaly_alert" event is recorded with rule_id, device_id, ip, geo, edit_count, window_seconds, first_event_at (UTC), last_event_at (UTC) Then the assigned attorney receives an in‑app alert within 30 seconds and an email within 2 minutes containing the anomaly summary and a link to the matter timeline When the attorney acknowledges the alert Then an "anomaly_acknowledged" event is recorded with actor_id and created_at (UTC) and the alert state is updated to Acknowledged
Revocation, Expiry & Session Management
"As a client, I want to revoke or extend my helper’s access at any time so that I stay in control of who can view or change my information."
Description

Allow clients and firm staff to revoke delegate access instantly from the matter or portal. Support configurable invitation lifetimes, inactivity timeouts, and single-device session locks. On revocation or settings changes, immediately invalidate tokens and end active sessions, displaying an informative expired page with contact options. Provide one-click extension and regeneration flows that preserve prior progress. Surface current status (Active, Expiring Soon, Revoked, Expired) and last activity in the matter overview.

Acceptance Criteria
Instant Revocation (Client or Staff)
Given a delegate invitation is Active and the delegate has an open session And the actor is authenticated as either the Client (via portal) or Firm Staff (via matter) When the actor clicks "Revoke Access" and confirms Then the system invalidates the invitation token within 5 seconds And all active delegate sessions are terminated within 5 seconds And any subsequent access to the link shows an Expired page explaining "Access revoked" with firm contact options (phone, email) and matter reference And the matter overview immediately shows status "Revoked" and updates Last Activity to the revocation timestamp And an immutable audit log entry is recorded with actor role, actor ID, IP address, timestamp, and reason "Revoked"
Configurable Invitation Lifetime and Expiry Handling
Given an invitation is created with a configurable lifetime and an "Expiring Soon" threshold (default 7 days lifetime, 24 hours threshold unless overridden) When the current time exceeds the configured lifetime Then the invitation token is automatically invalidated And any active delegate session ends within 5 seconds and redirects to an Expired page explaining "Link expired" with firm contact options And the matter overview updates status to "Expired" and Last Activity reflects the auto-expiry time When the remaining lifetime drops below the threshold Then the matter overview shows status "Expiring Soon" and displays remaining time (HH:MM)
Inactivity Timeout Enforcement with Warning and Auto-Save
Given an invitation has an inactivity timeout configured (default 15 minutes unless overridden) When the delegate is idle for (timeout - 60 seconds) Then a visible warning banner appears with a 60-second countdown and a "Stay Signed In" action When the countdown reaches 0 without user interaction Then the session terminates, unsaved answers are auto-saved, and the user is redirected to an Expired page explaining "Session timed out" And the matter overview Last Activity is updated to the timeout timestamp And if the link remains valid (not revoked/expired), re-accessing it resumes with saved progress
Single-Device Session Lock Enforcement
Given single-device session lock is enabled for delegate invitations And a delegate session is active on Device A (browser profile A) When the invitation link is opened on Device B or a different browser profile Then access is denied within 2 seconds and a "Session in use on another device" page is shown with instructions to close the other session And no matter data or PII is displayed on Device B And Device A retains uninterrupted access When the Device A session ends (logout, timeout, revocation, or expiry) Then the link may be used to start a new session on a device permitted by current settings
Immediate Invalidation on Settings Change
Given an invitation is Active and firm staff edit its access settings (e.g., lifetime, inactivity timeout, device lock) When the staff user saves changes Then existing invitation tokens are invalidated within 5 seconds and all active delegate sessions end within 5 seconds And delegates are redirected to an Expired page explaining "Access settings changed" with firm contact options And the matter overview reflects the new settings and updates Last Activity to the settings-change timestamp And no new token is issued unless the user explicitly selects Regenerate
One-Click Extension and Regeneration Preserve Progress
Given an invitation is Active, Expiring Soon, or Expired When a staff user selects "Extend Link" from the matter overview and chooses a new expiry within policy limits Then the extension completes in no more than 2 clicks, the existing token remains valid, and the new expiry is applied within 5 seconds And the invitation status updates accordingly and all saved progress remains available to the delegate When a staff user selects "Regenerate Link" Then a new token is issued within 5 seconds, old tokens are invalidated immediately, any active sessions end, and the new link is displayed/copied And upon accessing via the new link, previously saved answers and the last visited step are available And both actions create audit log entries including actor, timestamp, and before/after expiry values
Matter Overview Shows Status and Last Activity
Given a matter with a delegate invitation in any state (Active, Expiring Soon, Revoked, Expired) When a user opens or refreshes the matter overview Then the current status is displayed as one of the four states with a distinct badge And Last Activity shows the most recent event timestamp in the firm’s timezone and a relative time (e.g., "5 minutes ago") And the Last Activity entry includes actor (Delegate/Client/Staff) and event type (e.g., Opened, Submitted Page, Revoked, Expired, Settings Changed) And after any state change, the correct status and updated Last Activity are visible on the next page load and within 5 seconds of refresh
Notifications, Reminders & Progress Tracking
"As a firm, I want automated reminders and clear progress tracking for delegated intakes so that matters don’t stall and my team stays informed without manual follow-up."
Description

Send real-time notifications to the client and optional firm assignee when a delegate accepts an invite, starts, or completes intake, and when the link is nearing expiration. Provide configurable reminder cadence via email/SMS with localization and quiet hours. Display delegate completion percentage and outstanding required items in the matter dashboard, and auto-nudge for blockers (e.g., missing uploads). Respect opt-outs and throttle rules to prevent spam. Expose notification events to integrations via webhooks.

Acceptance Criteria
Real-time Notifications on Delegate Lifecycle Events
Given a matter with a client and an optional firm assignee And the client has invited a delegate via a restricted link When the delegate accepts the invite Then the client and firm assignee (if configured) receive a notification via each enabled channel within 60 seconds And the notification includes event type, matter ID, delegate display name, and an ISO 8601 timestamp When the delegate starts the intake Then the client and firm assignee (if configured) receive a start notification within 60 seconds, respecting opt-outs and throttle rules When the delegate completes the intake Then the client and firm assignee (if configured) receive a completion notification within 60 seconds, respecting opt-outs and throttle rules And duplicate notifications for the same event are not sent within a 5-minute window
Expiration Warning Notifications for Delegate Link
Given a delegate access link with an expiration timestamp And warning thresholds configured at T-24h and T-1h When current time crosses a warning threshold Then send a single expiration warning to the client and firm assignee (if configured) within 60 seconds And the message includes the expiration time in the recipient’s local timezone and a regenerate-link call to action for the firm And no more than one warning per threshold per link is sent And if the link is regenerated or its expiration is extended, pending warnings for the old link are canceled and no further warnings for the old link are sent And all warnings respect opt-outs, quiet hours, localization, and throttle rules
Configurable Reminder Cadence with Quiet Hours and Localization
Given reminders are enabled for a matter with an invited delegate who has not completed intake And a reminder cadence is configured (default every 48 hours) with channels (email/SMS) When no qualifying activity occurs for the duration of the cadence Then send a reminder via each enabled channel within 10 minutes of the interval elapsing And messages respect quiet hours (deferred to next allowed window) and recipient opt-outs And content is localized to the recipient’s preferred language with fallback to English And no more than 3 reminders per 7-day period per channel per matter are sent And changing cadence or quiet hours updates future scheduling without sending immediate catch-up reminders
Matter Dashboard Progress and Outstanding Items
Given a matter with delegate intake in progress When the delegate completes fields or uploads documents Then the matter dashboard updates the delegate completion percentage within 10 seconds And percentage equals completed required items divided by total required items, capped at 100% And the dashboard lists outstanding required items with human-readable labels and deep links to each item And the dashboard displays last delegate activity timestamp and current link expiration time And when all required items are complete, the dashboard shows status "Ready for e-sign" and no outstanding items
Auto-Nudges for Blockers (Missing Uploads)
Given auto-nudges are enabled and at least one required upload blocks progress When the blocker persists for 12 hours since the last delegate activity Then send a single nudge to the client within 10 minutes, respecting quiet hours, opt-outs, localization, and throttle limits And the nudge includes a secure deep link to the blocker section and a checklist of missing items And do not send more than one nudge per blocker in any 24-hour period And cancel pending nudges if the blocker is resolved before the scheduled send time
Opt-Outs and Throttle Rules Enforcement
Given recipient-level notification preferences include per-channel opt-out and global opt-out And throttle limits are set to a maximum of 3 notifications per 24 hours per channel per matter When any notification is generated Then the system enforces opt-outs, sending only to allowed channels And the system suppresses messages that would exceed throttle limits, ensuring no more than 3 are sent within any rolling 24-hour window per channel per matter And identical notifications for the same event are deduplicated within 5 minutes
Webhook Events for Notifications
Given a configured webhook endpoint with a valid signing secret When notification events occur (delegate.accepted, delegate.started, delegate.completed, link.expiring, reminder.sent, nudge.sent) Then a webhook is delivered within 60 seconds per event with a JSON payload containing event_id, event_type, matter_id, delegate_id (if available), recipient_role, channel, locale, and ISO 8601 timestamp And webhooks are HMAC SHA-256 signed and include an idempotency key And deliveries are retried with exponential backoff for up to 24 hours until a 2xx response is received And no duplicate delivery with the same event_id is sent to the same endpoint

Device Trust Manager

A self-serve dashboard shows the client’s authorized devices and recent sign-ins. Clients can revoke lost devices in one tap and receive alerts on new device access. Firms can force sign-outs across all sessions for a matter, increasing security assurance for sensitive consumer cases.

Requirements

Device Inventory Dashboard
"As a client, I want to see and manage all devices currently signed in to my account so that I can quickly identify unfamiliar access and keep my matter information secure."
Description

A mobile-first dashboard in the client portal that lists all authorized devices with friendly labels, device type, OS, browser, last active timestamp, approximate location derived from IP, and trust status. Provides per-matter scoping so firms and clients can view sessions relevant to a specific case, plus global view for the user. Supports quick actions (set primary, revoke) and pagination for high-volume matters. Integrates with the authentication/session service to enumerate active sessions and refresh tokens, with real-time updates via websockets or long polling. Improves transparency, reduces support burden, and empowers clients to self-manage access while meeting security expectations for sensitive consumer cases.

Acceptance Criteria
Global Device List Displays Authorized Devices and Metadata
Given an authenticated client is on the Device Inventory Dashboard in global view When the dashboard loads Then the list displays all authorized devices aggregated from active sessions and refresh tokens via the authentication/session service And each row shows: friendly label, device type, OS, browser, last active timestamp in the user’s local timezone (ISO 8601), approximate location (city/region/country) derived from IP, and trust status (Trusted/Untrusted/Revoked) And rows are sorted by Last Active in descending order by default
Per‑Matter Scoping and Role‑Based Visibility
Given a user with access to multiple matters When the user selects a specific matter filter on the dashboard Then only devices/sessions associated with that matter are listed And switching to Global view shows all devices for the user And client users can view only their own devices; firm users with the “Security:View Sessions” permission can view client devices in matter scope And the selected filter persists across pagination and refresh within the session
Set Primary Device Quick Action
Given the user has at least two devices listed When the user taps Set Primary on a non‑primary device Then that device becomes marked as Primary And any previously primary device loses the Primary designation And the primary state is persisted server‑side and reflected across sessions within 2 seconds And the Set Primary action is disabled for the currently primary device
Revoke Device Quick Action
Given a device is listed with an active trust status When the user taps Revoke and confirms the action Then all active sessions and refresh tokens for that device are invalidated via the authentication/session service within 5 seconds And the device’s trust status updates to Revoked and the UI reflects the change immediately And subsequent API calls from that device require re‑authentication And if the device is the current session, the user is warned and, upon confirmation, signed out of the current session
Real‑Time Updates for New Sign‑Ins and Revocations
Given the dashboard is open When a new device signs in or an existing device is revoked from another client or admin action Then the device list updates within 5 seconds without manual refresh via WebSocket push And if the WebSocket is unavailable, long polling updates the list at least every 30 seconds And updates respect the current matter filter and pagination page
Pagination, Sorting, and Performance at Scale
Given a user with more than 50 devices/sessions When the dashboard loads Then results are paginated server‑side with a default page size of 20 and controls to navigate pages And Last Active is the default sort; the user can sort by Device, OS, Browser, and Trust Status And initial page render completes within 1.5 seconds p95 on a 4G mobile network; subsequent page or sort changes complete within 1.0 seconds p95 And filter and sort selections persist when navigating between pages
Accessibility and Mobile Responsiveness
Given access from a mobile device at 360px viewport width When viewing and interacting with the dashboard Then all columns and actions are readable and operable without horizontal scrolling And all interactive elements have a minimum 44x44px touch target And the page meets WCAG 2.1 AA for color contrast, focus order, keyboard navigation, and screen reader labels for columns and quick actions
One-Tap Device Revocation & Session Kill
"As a client, I want to revoke a lost or unfamiliar device in one tap so that access to my legal documents is immediately cut off."
Description

Enable immediate revocation of a selected device, invalidating refresh and access tokens and triggering a server-initiated logout across web and mobile for that device. Propagate revocation to edge caches and gateways, with a short-lived denylist to prevent token reuse. Provide clear confirmation and post-action feedback, handle offline devices gracefully, and ensure idempotent, auditable operations. Prevent re-authentication from the same device until the user completes re-verification. Reduces exposure from lost or stolen devices and simplifies secure account recovery.

Acceptance Criteria
Immediate Revocation and Session Termination for Selected Device
Given the client is authenticated and viewing Device Trust Manager with a selected device D that has active sessions When the client taps Revoke on device D and confirms the action Then all access and refresh tokens scoped to device D are invalidated within 5 seconds of confirmation And subsequent API calls from device D receive 401 "revoked_device" And active web and mobile sessions on device D are terminated on the next request And the UI displays a success confirmation with device alias and a server timestamp And device D is marked "Revoked" in the device list within 2 seconds of server acknowledgment
Edge Propagation and Token Denylist Enforcement
Given tokens tied to device D may exist in API gateways, CDNs, or downstream services When revocation for device D is confirmed Then revocation status is propagated to all edges within 10 seconds (p95) And after 10 seconds, no requests authenticated by tokens tied to device D are accepted by any edge And refresh token exchange for tokens tied to device D is denied for at least 15 minutes via a denylist And monitoring emits revocation_propagation_latency and denylist_hit metrics for the event
Offline Device Handling with Deferred Logout
Given device D is offline at the time of revocation When device D reconnects and makes any authenticated request using pre-revocation tokens Then the request is rejected with 401 "revoked_device" and sessions on device D are destroyed And the first rejected request is logged as revocation_delivery with timestamp And until reconnection, the dashboard shows device D as "Revoked — awaiting device connection" with last-seen time And no push notifications or content payloads are delivered to device D after revocation
Idempotent Revocation with Safe Retries
Given the revoke endpoint is called multiple times for the same device D due to user retries or network retries When duplicate requests are received within 24 hours with the same idempotency key Then only one revocation is executed and subsequent calls return 200 with an idempotent-replay indicator And the resulting state for device D remains "Revoked" with no additional side effects And a single audit entry is created for the revocation, with duplicates linked by correlation_id
Audit Logging and Traceability of Revocation
Given a revocation event for device D is initiated When the operation completes (success or failure) Then an immutable audit record is written containing actor_id, user_id, device_id, device_fingerprint, device_alias, ip, user_agent, reason, idempotency_key, initiated_at, completed_at, outcome And the record is queryable via audit UI/API within 5 seconds of completion And the record is tamper-evident via checksum or signature
Block Re-Authentication from Revoked Device Until Re-Verification
Given device D was revoked When a sign-in attempt originates from device D using stored credentials or session restore Then authentication is blocked with an error requiring re-verification via OTP or magic link And until re-verification succeeds, no new tokens are issued to device D And upon successful re-verification, a new device_id is assigned and prior tokens remain unusable
User-Facing Confirmation and Post-Action Feedback
Given the user initiates revocation of device D When the server acknowledges success Then the user sees a confirmation message including device alias and timestamp and a summary of the effects (logout and access blocked) And the device list updates to reflect the revoked state and moves device D to a Revoked section And a confirmation email and push notification are sent within 30 seconds with recovery steps
New Device Sign-in Alerts
"As a client, I want to receive instant notifications for new device sign-ins so that I can act quickly if someone else accesses my account."
Description

Send real-time alerts when an account is accessed from a new or materially changed device fingerprint. Deliver via email, SMS, and in-app notifications with throttling and timezone-aware timestamps. Include device metadata, location approximation, and a secure deep link to review devices and revoke if needed. Allow users and firms to configure channels and frequency, with localized templates and compliant opt-out for non-essential channels. Improves early detection of account takeover and guides users to remediation in a single click.

Acceptance Criteria
New device or materially changed fingerprint triggers alert event
Given a user with at least one recognized device fingerprint And per-user and firm alert preferences are configured When the user successfully signs in from a device that is not recognized or is classified as materially changed Then the system emits exactly one NewDeviceAccess event within 2 seconds of session establishment And the event includes userId, deviceId, eventType (new|changed), occurredAt (UTC), userTimezone, and riskScore And no duplicate NewDeviceAccess event is emitted for the same device within a 10-minute throttle window
Multi-channel delivery with throttling and deduplication
Given a NewDeviceAccess event is emitted And the user has Email and SMS enabled and In‑app is required by firm policy When the event is processed Then an in‑app notification is delivered within 5 seconds And an email is sent within 60 seconds and an SMS is sent within 60 seconds And each channel delivers at most one notification per event And repeated events for the same device within the throttle window are summarized into a single notification per channel with a count And notification delivery outcomes are recorded with a correlationId for auditability
Alert content includes metadata, location approximation, and secure deep link
Given a NewDeviceAccess notification is generated When the notification is rendered for any channel Then it includes device type, OS name and version, browser name and version, and approximate location (city, region, country) And the IP address is partially masked (last octet redacted) And the sign‑in timestamp is displayed in the user’s configured timezone with the timezone abbreviation And localized templates are used based on user.locale with fallback to firm default, then en‑US And it contains a signed, single‑use deep link to the Device Trust Manager that expires between 15 and 60 minutes after issuance And expired or reused links redirect to a safe page prompting re‑authentication
Review devices and one‑tap revoke from alert deep link
Given a user clicks the secure deep link from a NewDeviceAccess notification When the link is validated and the user is authenticated (with step‑up required if riskScore ≥ threshold) Then the Device Trust Manager opens with the new/changed device pre‑selected And the user can revoke the device in one action And revocation forces sign‑out of active sessions on that device within 30 seconds And an audit log entry is recorded with actor, deviceId, action, and timestamp And the user receives a confirmation in‑app and by email (if enabled) of the revocation
User and firm configuration of channels, frequency, and compliant opt‑out
Given a user and a firm admin are managing alert settings When the user updates personal preferences for channels (Email, SMS, In‑app) and frequency (Immediate, Daily Digest, Off where permitted) Then changes take effect within 1 minute for new events And firm admins can set organization defaults and minimum enforced channels (e.g., In‑app required) And non‑essential channels (Email, SMS) include compliant opt‑out mechanisms (unsubscribe link for email, STOP for SMS) that suppress future sends within 1 minute of request And all preference changes and opt‑outs are captured in the audit log with actor and timestamp
Material change classification reduces noise while catching risk
Given device fingerprints are composed of hardware/deviceId, OS major version, browser family/version, and network/ASN + region When a sign‑in occurs with differences from the last recognized fingerprint Then classify as Materially Changed if deviceId is new OR at least two components change (e.g., OS major version and browser family) OR geolocation region changes > 500 km with different ASN And classify as Not Material if only browser patch level changes or DST offset shifts And unit tests verify that a major iOS upgrade is Material and a Chrome minor patch is Not Material And only Material or New devices trigger NewDeviceAccess events
Localization, accessibility, and resilient rendering across channels
Given notifications are generated for diverse locales and devices When content is delivered by Email, SMS, and In‑app Then date/time and number formats match the user’s locale settings And right‑to‑left languages render correctly And SMS messages fit within 160 GSM-7 characters where possible; multi‑part messages include proper UDH segmentation And email and in‑app content meet WCAG 2.1 AA for contrast and alt text And if approximate location is unavailable, the message displays an explicit 'Location unavailable' placeholder without breaking layout
Firm-Wide Force Sign-Out by Matter
"As a firm admin, I want to force sign-out for all sessions on a matter so that I can protect sensitive case information during security events or policy changes."
Description

Allow authorized firm users to force sign-out across all client sessions tied to a specific matter or client. Provide a dry-run count of affected sessions, a confirmation step, and an optional reason code. Immediately invalidate tokens, clear server-side sessions, and require re-authentication with optional step-up on re-entry. Integrate with the matter service to scope sessions accurately and with audit logging for compliance. Enhances security posture during suspected compromise, staff offboarding, or sensitive document updates.

Acceptance Criteria
Dry-Run Session Count for Selected Matter
Given an authorized firm user is on a matter's Device Trust Manager with at least one active client session When they trigger "Dry Run" for Force Sign-Out Then the system returns the exact count of client sessions that would be terminated for the selected matter only And excludes expired, revoked, or staff sessions And completes within 2 seconds for up to 10,000 sessions (p95) and within 5 seconds (p99) And shows 0 and a "No active sessions" notice when none would be affected And no sessions or tokens are modified
Confirmation Modal with Optional Reason Code
Given a successful dry run has been performed within the last 5 minutes for the same scope When the user initiates "Force Sign-Out" Then a confirmation modal displays the matter name/ID, scoped client name(s), and the dry-run count And the user may optionally provide a reason code (predefined list or free text up to 120 characters); leaving it blank is allowed And the primary Confirm button is disabled until the summary is loaded And selecting Cancel closes the modal with no side effects And selecting Confirm executes the operation exactly once
Immediate Token and Session Invalidation on Force Sign-Out
Given the user confirms the force sign-out When the operation executes Then all in-scope access tokens, refresh tokens, and server-side sessions for the scoped client identities are invalidated And subsequent API requests using those tokens receive HTTP 401 with reason "token_revoked" within 5 seconds (p95) and 30 seconds (p99) And open WebSocket or SSE connections for those sessions are closed within 5 seconds And the operation is idempotent; re-executing within 10 minutes produces no additional revocations and returns the same affected count
Scope Accuracy: Matter vs Client-Level Targeting
Given the system is provided a scope of "matter" or "client" When executing force sign-out for Matter M Then only sessions linked to Client C for Matter M are terminated; Client C's sessions on other matters remain active And collaborator or firm staff sessions are never affected And if scope "client" is selected for Client C, sessions across all matters for Client C are terminated And sessions started between dry-run and execution are included; sessions that end naturally before execution are excluded And scoping information is retrieved from the Matter Service; if the Matter Service is unavailable, the operation aborts with a retriable error and no sessions are revoked
Re-Authentication with Optional Step-Up on Re-Entry
Given a client's session was terminated by force sign-out When the client next accesses a protected resource Then they are redirected to the sign-in flow with a notice "Your session was ended by your law firm" And after successful sign-in, if step-up authentication is enabled for the matter or client, an OTP challenge is required before access is granted And the client cannot view or download protected documents for the affected scope until step-up (if required) is passed And a new session is established with a new token set; previous tokens remain invalid
Audit Logging and Traceability
Given a force sign-out is initiated When the operation completes (success or failure) Then an immutable audit record is persisted containing: timestamp (UTC), actor user ID, firm ID, scope type (matter/client), matter ID(s) and/or client ID, number of sessions targeted and revoked, optional reason code, latency, outcome (success/failure), and correlation ID And the audit record is queryable via Audit API/UI within 60 seconds (p95) And no raw tokens, secrets, or PII beyond stable IDs are stored And creation of audit record and execution of revocations are transactional; if audit persistence fails, no revocations are applied and the user sees an error
Authorization and Access Control
Given firm RBAC policies When a user without "Manage Sessions" capability for the firm or matter attempts a dry run or execution Then the system returns HTTP 403 and does not reveal counts or scope details And users with Firm Owner/Admin role or users assigned to the matter with "Manage Sessions" may perform the action And all actions are logged with the actor's identity And interactive endpoints enforce CSRF protections and API endpoints require authenticated, firm-scoped credentials
Risk-Based Authentication for Untrusted Devices
"As a user, I want extra verification when signing in from a new or risky device so that my account stays protected without making everyday logins painful."
Description

Assess device and sign-in context to compute a risk score using signals such as geo-velocity, IP reputation, device fingerprint change, and atypical access times. For medium/high-risk events, require step-up verification (email or SMS OTP) before granting access. After successful verification, allow users to mark the device as trusted from the dashboard. Integrate with existing authentication flows and respect user notification preferences. Reduces friction for normal use while mitigating account takeover risk.

Acceptance Criteria
Step-up Required for Medium/High Risk Sign-in
Given an untrusted device submits valid primary credentials And the computed risk score is >= 40 (Medium/High) When the authentication decision is evaluated Then the user is blocked from session issuance until step-up verification succeeds And the OTP challenge screen is presented within 1 second of evaluation And no session token or cookie is created prior to successful step-up
Low-Risk Sign-in Proceeds Without Step-up
Given an untrusted device submits valid primary credentials And the computed risk score is < 40 (Low) When the authentication decision is evaluated Then the user is granted a session without any step-up prompt And the sign-in event is logged with risk score and contributing signals And time-to-first-authenticated-view is <= 2 seconds at p95
OTP Delivery, Validity, and Fallback
Rule: OTP is a 6-digit numeric code, single-use, expires in 10 minutes Rule: A maximum of 5 OTP entry attempts per sign-in are allowed; exceeding locks sign-in for 15 minutes Rule: A maximum of 10 OTP sends per hour and 3 per minute per account; excess requests are throttled Given the user has both verified email and SMS When step-up is required Then both channels are offered with the user’s preferred method preselected And if the preferred channel fails delivery (provider error or no delivery confirmation within 60 seconds), the user can switch to the alternate channel and a new OTP is issued And OTPs are stored hashed and are invalidated immediately upon successful verification
Trust Device After Successful Step-up
Given step-up verification succeeds on an untrusted device When the user selects "Trust this device" from the dashboard Then the device fingerprint is stored as trusted for 90 days And subsequent sign-ins from this device bypass step-up when risk score < 40 And the trusted device appears in the Device Trust Manager with last seen time and revoke option And revoking trust removes the device from trusted list and enforces step-up on next sign-in if risk score >= 40
Risk Score Computation from Signals
Rule: Risk score is an integer 0–100 derived from weighted signals Rule: Geo-velocity > 500 km between last successful login and current attempt within 60 minutes adds >= 30 points Rule: IP reputation flagged malicious or anonymizer/VPN adds >= 40 points; unknown adds 10 points Rule: Device fingerprint change from last trusted sign-in adds >= 30 points Rule: Atypical access time (00:00–04:00 in user’s local time outside user’s normal pattern) adds >= 20 points Given the same inputs, the same risk score and contributing factors are logged and reproducible for audit
Auth Flow Integration and Session Gating
Given the user submits valid primary credentials When risk score >= 40 Then the step-up challenge occurs after primary credential verification and before session token issuance And on step-up failure or timeout, no session or refresh token is issued and the attempt is logged with reason And on step-up success, the session and refresh tokens are issued with standard TTL and scopes identical to low-risk sign-ins
New Device Alerts Respect Notification Preferences
Given an untrusted device sign-in attempt occurs And the user’s notification preferences for "New device access" are enabled for Email and disabled for SMS When the attempt results in a successful sign-in (with or without step-up) Then an email alert is sent within 60 seconds and no SMS is sent And if preferences are disabled for all channels, no alert is sent And the alert includes device, approximate location, timestamp, and a "This wasn’t me" link that triggers immediate invalidation of active sessions and flags the device as untrusted
Device Activity Audit Log with Export
"As a firm user, I want a detailed audit log of device activity so that I can verify actions, investigate issues, and meet compliance obligations."
Description

Maintain an immutable, searchable audit trail of device-related events including sign-ins, revocations, alerts sent, and force sign-outs, with timestamps, actor, IP, device metadata, and matter context. Provide filters by date range, user, matter, and event type, plus CSV export to support compliance, discovery, and client communications. Implement retention policies and access controls aligned with firm roles. Offers defensible evidence and simplifies investigations and regulatory responses.

Acceptance Criteria
Immutable device event capture
Given a successful sign-in, device revocation, alert dispatch, or force sign-out occurs, When the event is committed, Then an audit log entry is created with fields: event_id (UUID), occurred_at (ISO 8601 UTC), event_type ∈ {sign_in, device_revoked, alert_sent, force_sign_out, session_terminated}, actor_type ∈ {client, firm_user, system}, actor_id, actor_role (if firm_user), ip_address (IPv4/IPv6), device_id, device_user_agent, device_os, device_browser, device_name (nullable), matter_id (nullable), matter_name (snapshot), metadata (JSON). Given an audit entry exists, When any user attempts to modify or delete it, Then the system rejects the request (405/403) and no change occurs, And a new audit event "audit_access_denied" is recorded capturing the attempted action. Given a new audit entry is written, Then it becomes queryable via UI and API within 5 seconds at p95. Given client-supplied timestamps, Then server-side UTC time is authoritative and stored; client timestamps are ignored for occurred_at.
Search, filter, and pagination
Given the audit log has ≥100,000 entries for a firm, When filters are applied (date range, user, matter, event_type), Then results include only entries matching all filters (AND semantics), And the date range is inclusive of start and end using occurred_at (UTC). When no filters are applied, Then the default view shows the last 30 days of events. Then the default sort is occurred_at descending with a stable tiebreaker on event_id. When requesting a page of results, Then default page_size=50 and max page_size=500, And a next_page_token is returned if more results remain. Performance: first page response time <= 2s p95; subsequent pages <= 1.5s p95 for up to 100k matching entries.
CSV export of filtered audit log
Given any active filter set, When an authorized user requests Export CSV, Then the export contains only the filtered results and columns in this order: event_id, occurred_at_utc, event_type, actor_type, actor_id, actor_role, ip_address, device_id, device_os, device_browser, device_user_agent, device_name, matter_id, matter_name, metadata_json. Then the CSV is UTF-8 encoded with a header row, CRLF line endings, fields containing commas/newlines are quoted, and nulls are empty strings. For <= 100,000 rows, Then the export completes and is available to download within 5 minutes p95; For > 100,000 and ≤ 1,000,000 rows, Then the export is chunked and delivered as a ZIP within 15 minutes p95. The download link is a tenant-scoped signed URL that expires in 24 hours; access after expiry returns 410 Gone. Each export creates an "audit_export_created" event with requester, filter summary, row count, and file checksum (SHA-256).
Role-based access control and matter scoping
Given role Firm Owner/Admin or Compliance Officer, When accessing the audit log UI or API, Then full-firm visibility is granted; When requesting CSV export, Then the request is allowed. Given role Attorney, When accessing, Then only events for matters where the user is assigned are visible; CSV export is allowed only if the user has permission "Export Audit Log". Given role Staff, When accessing, Then visibility is limited to matters per explicit permission; CSV export requires "Export Audit Log" permission. Given role Client, When accessing, Then only their own account’s device events are visible; IP address is truncated (/24 for IPv4, /48 for IPv6) and CSV export is not available. Unauthorized access attempts return 403 and create an "audit_access_denied" event with actor, scope requested, and reason.
Retention policy and legal hold
Given a firm retention policy is configured in days, When the nightly purge job runs at 02:00 UTC, Then events older than the retention threshold are permanently deleted, and an "audit_purge_completed" event is written with purged counts. Given a matter- or firm-level legal hold is active, When the purge job runs, Then events under hold are excluded from deletion. When a retention policy is created, updated, or removed, Then the action requires Firm Owner/Admin, triggers 2FA, and writes an "audit_retention_changed" event with old/new values and reason. When a legal hold is created or released, Then an "audit_legal_hold_changed" event is recorded with scope, actor, and justification. Exports never include purged events; requesting an export over a fully purged time range returns 204 No Content.
Force sign-out auditability
Given a Firm Admin initiates force sign-out for a matter, When executed, Then all active sessions tied to the matter are invalidated within 60 seconds p95. Then a "force_sign_out" audit entry is created with actor, matter_id, total_sessions_terminated, and rationale. For each device session terminated, Then a "session_terminated" audit event is recorded with device_id, user_id, and occurred_at. Attempting force sign-out without permission returns 403 and logs an "audit_access_denied" event.
Alert dispatch event logging
Given a new device access triggers an alert, When the alert is sent, Then an "alert_sent" audit event is recorded with channel ∈ {email, sms, push}, provider_message_id, delivery_status ∈ {queued, sent, delivered, failed}, and occurred_at. If multiple alerts would trigger for the same device and user within 10 minutes, Then duplicates are suppressed and a single audit entry is created with a deduplication_key. Retries and failures produce additional "alert_sent" entries with attempt number and final status. If a user’s alerts are disabled by policy, Then an "alert_suppressed" audit event is recorded with the reason.
Privacy & Data Minimization Controls
"As a privacy-conscious client, I want clear control over what device data is stored and how I’m notified so that I can protect my privacy without sacrificing security."
Description

Collect only necessary device metadata (hashed device ID, user agent, OS version, coarse location) and rotate or truncate full IP addresses per retention policy. Present a concise privacy notice explaining device tracking and alerts, obtain consent where required, and allow channel-level opt-in/out for non-essential notifications. Provide data deletion workflows tied to matter closure and account deletion. Aligns the feature with privacy obligations and client expectations while preserving security value.

Acceptance Criteria
Minimal Metadata Capture on Sign-In
Given a user signs in on a device When device metadata is stored Then only hashed_device_id (SHA-256 with per-tenant salt), user_agent, os_version, coarse_location (city or geohash-4), truncated_ip, and timestamp are persisted And no hardware identifiers (IMEI, MAC), advertising IDs, precise GPS (<5 km), or full IP addresses are stored And schema validation rejects payloads containing disallowed fields with HTTP 400 and an audit log entry And the salt for hashing is not stored client-side and is rotated per policy without breaking device continuity tests
IP Address Truncation and Rotation Policy Enforcement
Given a sign-in event captures an IP address When persisting the IP Then IPv4 is truncated to /24 and IPv6 to /56 before storage And queries and exports never return full IP values Given IP_RETENTION_DAYS is configured (default 30) When a stored IP reaches IP_RETENTION_DAYS Then a nightly job replaces truncated_ip with null while retaining city-level location And the job logs affected record counts and alerts on failures
Privacy Notice Display and Consent Recording
Given a user first encounters Device Trust Manager features When the privacy notice is shown Then the notice clearly states purposes, data types collected, retention, opt-out options, and links to the privacy policy And the user must acknowledge to proceed And where local rules require consent for non-essential tracking, explicit opt-in is required and recorded And a consent record is stored with timestamp, notice_version, jurisdiction, and selected channels And when notice_version changes, users are re-prompted at next sign-in and a new consent record is created
Channel-Level Opt-In/Out for Non-Essential Notifications
Given notification settings are opened When the user toggles non-essential alerts per channel (email, SMS, push) Then preferences are saved immediately and are effective within 60 seconds And essential security notifications (e.g., password reset, forced sign-out) cannot be disabled Given a new device access is detected When notifications are sent Then only channels with explicit opt-in are used where consent is required, and unsubscribes update preferences in real time
Automated Data Deletion on Matter Closure
Given a matter is marked Closed When the closure date is set Then all device trust events and alert logs linked to that matter are queued for deletion after MATTER_DATA_RETENTION_DAYS (default 7) unless a legal hold is present And deletion removes records and detaches device associations from the matter while preserving non-identifiable aggregate counts And an immutable audit log records deletion time, actor, counts, and any legal hold exceptions
Account Deletion: Privacy Data Erasure and Revocation
Given a verified account deletion request When the erasure workflow starts Then all device trust metadata, consents, and notification preferences for the account are deleted within ACCOUNT_ERASURE_SLA_HOURS (default 24), subject to documented legal retention exceptions And all active sessions are revoked across devices and matters And backups containing the deleted data are purged within BACKUP_PURGE_DAYS (default 30) per backup policy And a deletion confirmation is provided with a reference ID

QR Handoff

Seamlessly move an intake session from a shared or clinic device to the client’s phone by scanning a short-lived QR code. The session resumes on the personal device and prompts passkey creation there, minimizing data entry on public devices and accelerating curbside or clinic workflows.

Requirements

Ephemeral QR Code Generation
"As a clinic staffer using a shared tablet, I want to generate a short-lived QR tied to the current intake so that the client can seamlessly continue on their own phone without re-entering information."
Description

Generate a short‑lived, single‑use QR code bound to the active intake session on a shared or clinic device. The QR encodes a secure, signed short URL/token with a strict TTL (e.g., 2 minutes) and rotates on demand. The module must be compatible with default iOS/Android cameras, support universal/deep links, display a visible expiry countdown, and allow quick regeneration. On expiry or regeneration, all prior tokens are invalidated. The feature integrates with Briefly’s session service to associate the token with the intake draft and requester role, enabling safe transfer without exposing PII in the code payload.

Acceptance Criteria
Generate short-lived QR with countdown
Given an authenticated user is on a shared device with an active intake session When they tap "Show QR Handoff" Then the system generates a QR encoding a signed short URL/token with a server-enforced TTL of 120 seconds And a visible countdown appears and starts at 120 seconds And the countdown remains in sync with server time within ±2 seconds when checked at 60s and 5s remaining And the encoded URL length is ≤ 120 characters And the QR renders within 300 ms of the tap
Single-use token claim and session resume
Given a displayed QR token that is unexpired and unconsumed When a client scans it with a default phone camera and opens the link Then the session service binds the token to the originating intake draft and requester role And the token is marked consumed and cannot be reused And the intake draft opens on the personal device at the same step as on the shared device within 1 second of link open And any subsequent attempt to open the same link returns HTTP 410 (Gone) with message "Code already used" within 200 ms
Token expiration handling
Given a QR token is displayed When 120 seconds elapse from server-recorded issuance Then the server rejects the token with HTTP 410 (Gone) and reason "Expired" And the shared device UI changes state to "Expired" and shows a "Regenerate" action without page reload within 200 ms And scanning an expired code shows an expiration message and does not reveal any session identifiers
Regeneration invalidates prior tokens
Given an active QR token is displayed for a session When the user taps "Regenerate" Then a new token and QR are minted and displayed within 500 ms with a fresh 120-second TTL And all prior tokens for that session become invalid immediately regardless of remaining TTL And scanning any prior token returns HTTP 410 (Gone) with reason "Invalidated" And the newly generated token value differs from all prior tokens for that session
No PII in QR payload and signed token integrity
Given a generated QR and its underlying token When the token is inspected or decoded Then no PII (name, email, phone, address, case facts) is present in the URL or token claims And the token includes only non-identifying claims (e.g., token_id, session_hash, iat, exp, nonce, audience) and is signed And the server verifies the signature and audience before accepting the token And any tampering or replay attempt results in rejection with 401/403 within 200 ms and no leakage of session details
Camera compatibility and universal/deep link routing
Given a QR is displayed on the shared device When scanned by the default iOS Camera (iOS 15+) or Android Camera (Android 10+) from 25–40 cm under normal indoor lighting Then the scanner recognizes the QR and offers to open the HTTPS link on first attempt And if the Briefly app is installed, the universal/deep link opens the app at the handoff route; otherwise it opens the web fallback in the default browser And in both cases the intake draft resumes with the bound session and requester role within 2 seconds of link open And measured scan success rate is ≥ 99% over 10 consecutive scans per platform
Cross-Device Session Resume
"As a client starting intake on a kiosk, I want the same questionnaire to open on my phone at the exact step I left off so that I don’t lose progress or repeat questions."
Description

Upon QR scan, the mobile device verifies the token server‑side and hydrates the client’s intake session at the exact step last completed, including partial answers, uploaded files, and validation state. The shared device session is immediately invalidated and replaced with a sanitized confirmation screen. Transfer is atomic to prevent duplication, with retries that are idempotent. The flow preserves analytics attribution and context (matter type, source) and gracefully handles edge cases such as expired tokens, different browser profiles, or intermittent connectivity with clear recovery actions.

Acceptance Criteria
Resume Session at Exact Step on Mobile After QR Scan
Given a valid, unexpired QR token linked to session S with partial answers, uploaded files, and per-field validation state saved server-side When the client scans the QR and opens the link on a mobile browser Then the server verifies the token and binds the mobile device to session S, returning 200 within 2 seconds at the 95th percentile And the mobile client renders the intake at the exact last completed step (same step index) with all field values, validation states, and uploaded file metadata intact And no previously completed answers are lost, altered, or duplicated And a passkey/WebAuthn creation prompt is displayed on the mobile device before proceeding if no credential is bound to the user And client-side analytics/session identifiers are stitched to the existing server-side session and intake_id
Invalidate Shared Device Session with Sanitized Confirmation Screen
Given the session has been successfully resumed on the mobile device When the shared device attempts any further interaction with the prior intake session Then the shared device’s session token is invalidated within 1 second And refreshing or navigating shows a sanitized confirmation screen containing no PII, only a generic "Continue on your device" message and help actions And localStorage, sessionStorage, cookies for the app domain, and client caches are cleared of session data And any attempt to submit or navigate protected routes returns 401 and redirects to the sanitized screen And an audit log entry records transfer completion with timestamp and device context
Atomic Transfer and Idempotent Retries
Given multiple redemption requests for the same QR token (e.g., two devices or network retries) When the server processes token redemption Then exactly one device becomes the definitive owner of the session via an atomic compare-and-set operation And subsequent redemption attempts with the same token receive a deterministic 409 TransferAlreadyCompleted with the winner’s binding info (no new session created) And there is no interval in which both devices can submit intake data; secondary attempts are rejected with 401/409 And audit logs contain a single transfer event with a unique correlation ID And repeated client retries return the same outcome without duplicating uploads, answers, or events
Preserve Analytics Attribution and Context Across Devices
Given an active intake with analytics attribution (matter_type, source, campaign/UTM, referrer, intake_id) When the session resumes on the mobile device via QR Then the same attribution fields and identifiers are preserved server-side and rehydrated client-side And downstream document assembly and e-sign flows receive the same context values And analytics platforms show one continuous session without double-counting pre- and post-handoff events And if client tracking is blocked on mobile, server-side attribution persists and is associated to the intake record
Expired or Invalid Token Handling with Clear Recovery
Given a QR token is expired (TTL 5 minutes) or invalid When it is scanned or opened on a mobile device Then the mobile UI shows a clear, non-PII error state with options to request a new QR on the shared device or restart intake And the server responds with 410 Gone for expired tokens and 404 Not Found for invalid tokens, including retry_after guidance where applicable And no session data is exposed on the mobile device And the shared device is prompted to generate a fresh QR without leaving orphaned sessions And all events are logged with reason codes for observability
Different Browser Profiles and Authentication/Passkey Creation
Given the mobile device/browser profile differs from the shared device When the user resumes the session on mobile Then the user is required to create or bind a passkey/WebAuthn credential before continuing And if passkey creation fails or is declined, an SMS magic link fallback is offered and completes authentication within 60 seconds at p95 And after successful authentication, the intake resumes at the exact last step with no loss of data And subsequent scans from the same mobile browser bypass re-auth and go directly to the resumed step
Intermittent Connectivity During Handoff
Given network connectivity drops during QR redemption or initial hydration When connectivity is restored within 2 minutes Then the client automatically retries redemption with exponential backoff up to 4 attempts using the same token And a visible progress indicator and cancel action are displayed during retry And if retries are exhausted, the user is shown recovery instructions and an option to request a new QR on the shared device And partial writes do not corrupt state; uploaded files are verified by checksum and deduplicated on resume
On-Device Passkey Enrollment
"As a client, I want to create a secure passkey on my phone during handoff so that I can quickly sign my retainer and return later without passwords or codes."
Description

After successful handoff, prompt the client to create a passkey on their phone using WebAuthn/FIDO2. Link the credential to the intake record and future client portal access, enabling instant re-auth and e‑sign without passwords. Provide non-blocking fallbacks (SMS/email magic link) if the device or browser does not support passkeys. Ensure step‑up authentication before accessing sensitive documents, store only server‑side public credentials, and support cross‑platform testing for iOS Safari/Chrome and Android Chrome. The flow should be localized and explain benefits to maximize adoption.

Acceptance Criteria
Passkey Prompt After QR Handoff
Given a client has successfully transferred their intake session via QR handoff to their personal device When the session resumes on iOS Safari, iOS Chrome, or Android Chrome Then the app immediately displays a non-modal passkey creation prompt using a platform authenticator via WebAuthn And the prompt includes clear benefits copy and a "Skip for now" option And the flow does not require additional data entry beyond device authentication And the prompt does not block continuing the intake if dismissed
Successful Passkey Registration and Linking
Given the user consents to create a passkey When navigator.credentials.create (WebAuthn registration) completes successfully with the configured RP ID Then the server stores only credential ID, public key, sign count, transports, and permissible metadata (no private key or biometric data) And the credential is linked to the active intake record and the client's account identifier And a success confirmation is shown and the flow advances automatically without page reload And an audit log records timestamp, device platform, browser, and RP ID used
Non-Blocking Fallback When Passkeys Unsupported or Declined
Given the device/browser lacks passkey support or the user taps Skip When the fallback path is triggered Then the user is offered SMS and email magic link options in-line without leaving the intake flow And verified contact methods are prefilled; otherwise a single verification step collects them And sending a magic link completes within 3 seconds and is rate-limited to 3 attempts per 10 minutes per user And successful magic link authentication marks passkey enrollment as Deferred and allows intake to proceed
Step-Up Authentication Before Sensitive Documents
Given the client attempts to access the retainer or court-ready draft When the last strong authentication (passkey assertion or verified magic link) occurred more than 15 minutes ago Then prompt for a WebAuthn.get assertion using the stored credential on the current device And on failure or absence of a credential, offer magic link fallback And grant access only after successful step-up; otherwise keep documents redacted/locked And log the step-up event with reason, method used, and outcome
Passwordless Re-Auth and E‑Sign Using Passkey
Given the client has a linked passkey When returning to the client portal or e‑sign step on a supported device Then the app offers passkey sign-in via WebAuthn without requiring a password And a successful assertion restores the session and proceeds directly to e‑sign without re-entering personal data And median time from auth prompt to e‑sign ready is under 10 seconds on reference devices And unsuccessful assertions provide a retry and fallback without losing form state
Cross-Platform Compatibility and Origin Security
Given testing on iOS 16.4+ Safari, iOS 16.4+ Chrome, and Android 10+ Chrome When performing passkey registration and authentication Then both flows succeed using user-verifying platform authenticators on each browser And RP ID and origin validation pass (no cross-origin or third-party iframe issues) And native OS passkey UI is presented on both Android and iOS And conditional mediation is disabled during registration and enabled for sign-in where supported
Localization and Adoption Messaging
Given the device locale is supported (at minimum English and Spanish) When displaying the passkey prompt, errors, and fallback options Then all copy and labels are localized and consistent with product terminology And the user can override the detected language from the prompt And analytics track enrollment offer shown, accepted, and declined by locale And achieve ≥70% passkey enrollment on supported devices, reported weekly
Shared Device Privacy Lock & Data Wipe
"As a clinic operator, I want the shared device to automatically clear and lock after handoff so that client data isn’t exposed to the next user."
Description

When handoff completes or times out, the shared device automatically masks the intake view, clears form values, session cookies, caches, and temporary uploads, and displays a neutral confirmation screen. Implement inactivity auto‑lock and admin‑configurable timeouts. Disable OS/browser autofill on intake fields while the QR is visible, and prevent screenshots if supported. Ensure no PII persists in DOM, logs, or local storage. Provide a staff‑only shortcut to start a new intake safely. This protects client privacy in clinics and curbside settings and supports compliance expectations.

Acceptance Criteria
Handoff Completion: Mask and Wipe
Given a client completes QR handoff to their personal device When the shared device receives the handoff-complete event Then within 1 second the intake view is replaced by a neutral confirmation screen with no PII And all form inputs in memory are cleared And intake-scoped session cookies are deleted And localStorage, sessionStorage, IndexedDB, and CacheStorage for the intake origin are cleared And any temporary upload blobs/files are deleted from sandboxed storage And using the browser Back/Forward buttons does not reveal prior intake content, only the neutral screen
Handoff Timeout: Auto-Lock and Admin-Configurable Timeouts
Given there is no touch/keyboard/mouse activity on the shared device When the configured inactivity timeout elapses Then the intake view is masked and the same wipe actions are executed as on handoff completion And the QR code is invalidated and cannot be used to resume on the shared device And an admin can configure the inactivity timeout between 30 seconds and 10 minutes (default 2 minutes) And configuration changes take effect within 60 seconds without requiring app redeploy And an optional 15-second pre-timeout warning banner is displayed if enabled
QR Visible: Autofill Disabled on Intake Fields
Given the QR handoff screen is visible on a shared device When a user focuses any intake field Then browser/OS autofill and password managers do not suggest or auto-populate values And HTML attributes (e.g., autocomplete="off"/"new-password") are applied to all intake inputs while QR is visible And no previously saved values appear in any intake fields until after the session is safely resumed on the personal device
Screenshot Protection and Task Switcher Masking
Given the intake or QR handoff screen is displaying sensitive content When a screenshot or screen recording is attempted in supported environments (e.g., Android WebView/TWA) Then screenshots/recordings capture a blank/blocked frame When running in standard browsers where screenshot prevention is not supported Then on page visibility change or blur, sensitive sections are replaced by a neutral placeholder within 200 ms And OS task switcher/app preview thumbnails show only the neutral placeholder, not PII
Post-Wipe PII Eradication: DOM, Storage, Logs
Given a wipe has been triggered by handoff completion or timeout When the page remains loaded or is reloaded Then no PII or form values remain in the DOM And localStorage, sessionStorage, IndexedDB, and CacheStorage contain no PII or intake artifacts for the origin And session cookies for the intake flow are absent And client-side logs and analytics events after the wipe contain no PII keys or values And subsequent network requests from the shared device exclude PII in headers, URLs, and bodies
Neutral Confirmation Screen Behavior and Navigation Guard
Given the shared device has been masked When the neutral confirmation screen is displayed Then it contains no client identifiers or PII and uses generic language only And it provides no navigation path back into the previous intake And using Back/Forward, refresh, or reopening the tab does not restore prior intake state or PII And the neutral screen remains accessible and responsive within 500 ms of trigger
Staff-Only Safe New Intake Shortcut
Given the neutral confirmation screen is displayed on a shared device When a staff member invokes the "Start New Intake" shortcut Then the system prompts for staff authentication (e.g., PIN/SSO) And upon successful authentication a fresh intake session with a new session ID is created And any residual data from the prior session remains unrecoverable via navigation or storage And if authentication fails, no intake is started and no PII is revealed
Accessible QR Scan UX
"As a client with varying device capabilities, I want clear scan instructions and fallbacks so that I can complete handoff even if my camera or network has issues."
Description

Deliver a guided, accessible UI for both devices: large high‑contrast QR, readable instructions, progress indicators, and clear success/failure states. Include localization, screen reader labels, and sufficient touch targets. Offer fallbacks when scanning fails: short URL, alphanumeric session code, and copyable link with universal link support. Handle permissions and network issues with actionable prompts and a one‑tap refresh. Provide an explicit cancel/restart path that safely invalidates prior tokens and does not orphan sessions.

Acceptance Criteria
Accessible QR and Instruction UI on Clinic Device
Given a user initiates QR Handoff on a clinic/shared device When the QR screen is displayed Then the QR code renders at a minimum of 240x240 px on phones and 360x360 px on tablets/desktop with a 4-module quiet zone and contrast ratio ≥ 3:1 against the background And the QR encodes only an ephemeral, non-PII token scoped to the session and device And the token auto-rotates every 120 seconds with a visible countdown timer and the prior token is invalidated on rotation And primary actions (Scan with my phone, Copy link, Enter code, Cancel) have touch targets ≥ 44x44 dp (or 48x48 px on web) And instructional text is present at reading level ≤ 8th grade, font size ≥ 16 px (scales with OS text size), line height ≥ 1.5 And all text and interactive elements meet WCAG 2.1 AA contrast (text ≥ 4.5:1; non-text UI ≥ 3:1)
Screen Reader and Focus Navigation Accessibility
Given a user relies on assistive technologies When navigating the QR Handoff screens on either device Then all actionable elements have meaningful accessible names, roles, and states (e.g., aria-labels, hints) including the QR image (labeled as Scannable code to resume intake) And focus order follows visual order without traps and returns to a logical position after modal dialogs close And progress/status updates (e.g., Connecting…, Session found, Error messages) are announced via aria-live polite within 500 ms And all controls are reachable via keyboard/switch access with visible focus indicators ≥ 3:1 contrast And motion/animation is reduced when OS Reduce Motion is enabled without loss of information
Localization and RTL Support
Given the app is configured for multiple locales When the QR Handoff UI is viewed in English and Spanish (es) and an RTL language (e.g., Arabic) Then all user-facing strings are localized with no truncation or overlap at base and 150% text sizes And layout mirrors correctly for RTL, including progress indicators and back navigation And dates/times/numbers in countdowns follow locale formats And if a string is missing for a locale, English falls back gracefully without placeholder keys
Camera Permission Handling with Actionable Alternatives
Given a user opens the QR scanning view on their personal device When camera permission is not yet granted Then the system permission prompt is triggered once with an in-context rationale And if the user denies or the device lacks a camera, the UI surfaces alternatives: Enter code, Open short link, or Paste copied link, all available above the fold And a persistent banner explains how to enable the camera with a one-tap link to Settings (where supported) And the scanning view clearly indicates current state: Ready to scan, Requesting permission, Permission denied, or No camera detected
Fallbacks: Short URL, Session Code, and Copyable Universal Link
Given scanning is unavailable or fails When the user selects a fallback option Then a short HTTPS URL ≤ 30 characters is shown and copyable with one tap, and opening it on the phone resumes the exact intake session And an alphanumeric session code (10 chars, Base32 without 0,O,1,I,L) is displayed with input validation and masked grouping (e.g., ABCD-EFGH-J) And universal link/deep link opens the native app if installed; otherwise it opens the mobile web and resumes the session And copied links and codes confirm via toast within 1 second and are available in the clipboard And all fallback tokens expire in 10 minutes or upon successful handoff, whichever comes first
Network Reliability and One-Tap Refresh
Given intermittent or lost connectivity occurs on either device during handoff When the app detects offline status or a retryable server error (HTTP 5xx, 429, or timeout) Then a non-blocking banner appears with plain-language guidance and a single prominent Refresh/Retry action And tapping Refresh re-attempts the last operation within 1 second and preserves user state without duplicating sessions And countdown timers pause while offline and resume when online And non-retryable errors (e.g., 410 expired token) present a Restart option that generates a new token and clearly explains what happened
Successful Handoff, Progress, and Passkey Prompt
Given the client scans the QR or opens a valid fallback link on their personal device When the session is matched on the server Then the personal device displays a Connecting → Session found → Resumed sequence within 3 seconds total in 95% of trials And the personal device immediately prompts for passkey creation/selection per platform standards, with Cancel and Use another method options And the clinic device transitions to a Success state that automatically hides sensitive data, confirms handoff, and offers a Done button to return to the start screen And if matching fails (invalid/expired token), both devices show a failure state with clear next steps (Refresh or Restart) and do not orphan the intake session And only one device can resume a given token; subsequent attempts are rejected with guidance to restart
Cancel/Restart Safely Invalidates Tokens Without Orphaning
Given a user selects Cancel or Restart from either device during handoff When the action is confirmed Then all active tokens (QR, short URL, universal link, session code) associated with that attempt are immediately invalidated server-side And the original intake session remains recoverable on the originating device via Start over, generating a fresh token set with a new identifier And no partially transferred session persists on the personal device after cancel; cached data is cleared and the user is returned to a neutral screen And audit logs record cancel/restart events with timestamps and token IDs (hashed) for troubleshooting
Handoff Security & Abuse Mitigation
"As a product owner, I want robust security controls on QR handoff so that client data cannot be intercepted or misused."
Description

Protect the flow with signed, audience‑bound tokens (short TTL, one‑time use), replay detection, CSRF protections, and domain pinning for deep links. Apply rate limiting and bot detection on QR generation and token redemption. Bind tokens to intake context and soft‑bind to originating device/IP where feasible without harming usability. Encrypt all transport, redact PII from URLs, and produce audit logs for token creation, redemption, and invalidation. Provide admin alerts and dashboards for anomaly spikes.

Acceptance Criteria
Signed Short-TTL Audience-Bound One-Time Token Issuance
Given an authenticated staff user initiates a QR handoff for an active intake session When a QR code is generated Then the backend issues a token that is cryptographically signed by the platform key, includes aud=handoff.mobile, exp <= 120 seconds from issuance, a unique jti, and the intakeSessionId, and is flagged one-time-use And Then no PII (name, email, phone, SSN, DOB, address) is present in the token claims or embedded in the QR payload, which contains only an opaque code or short URL And Then the token cannot be used to enumerate sessions and is not persisted client-side beyond QR rendering; server stores only jti status and minimal context for validation
Redemption Validation, Replay Detection, and CSRF Protection
Given a mobile device opens the handoff link When the token is redeemed via POST over HTTPS Then the server validates signature, audience, expiration, one-time jti status, and intakeSessionId before resuming the session And Then the first valid redemption returns 200 and resumes the exact intake context; any subsequent attempt with the same jti returns 409 (replay detected) without revealing session details and is audit-logged with reason=replay And Then cross-origin requests without a valid CSRF token/cookie are rejected with 403 and audit-logged; same-site redemption succeeds
Soft-Bind to Originating Device/IP with Graceful Fallback
Given a QR is generated on Device A and IP A When the token is redeemed on Device B Then the server evaluates a soft-binding policy comparing originating IP and optional device fingerprint; if risk score < threshold, redemption proceeds; if >= threshold, a one-tap verification on Device A or SMS code to the client is required before proceeding And Then successful fallback verification completes without re-entering PII and within median <= 30 seconds; failed or declined verification denies redemption and logs reason=binding_mismatch
Deep Link Domain Pinning and HTTPS Enforcement
Given any QR handoff URL is generated Then the URL scheme is https and host is in the approved allowlist; no http links or unapproved subdomains are produced When a handoff is attempted via http or an unapproved domain/subdomain Then the server rejects redemption with 400/403, performs no redirects to external domains, and audit-logs reason=domain_pinning_violation And Then HSTS is enabled for pinned domains (max-age >= 15552000 seconds, includeSubDomains) and TLS >= 1.2 with approved ciphers is enforced
Rate Limiting and Bot Detection on QR Generation and Redemption
Given the QR generation endpoint When a single user or IP requests > 30 QR codes within 60 seconds Then subsequent requests receive 429 with a Retry-After header, no tokens are issued, and events are audit-logged with rate_limit=true Given the token redemption endpoint When an IP or subnet attempts > 60 redemptions or > 10 failed validations within 60 seconds Then bot detection enforces a challenge or blocks with 429/403; valid redemptions with compliant traffic are unaffected
URL and Token Hygiene: PII Redaction and Context Binding Only
Given any handoff URL or token Then it contains only an opaque code and no query/path value matches PII patterns (name, email, phone, address, DOB, SSN, government IDs) And Then server-side mapping resolves only to intakeSessionId and organizationId; any additional identifiers provided in the URL are ignored and audit-logged And Then an automated test sampling 10,000 generated handoff URLs/tokens finds 0 instances containing PII
Comprehensive Audit Logging and Admin Anomaly Alerts
Given token lifecycle events (creation, redemption, invalidation, replay, CSRF rejection, domain pinning violation, rate limit) Then each event writes an immutable log entry with timestamp (UTC), jti, intakeSessionId, staffUserId (if applicable), clientUserId (if known), source IP, user-agent/device (if available), outcome, reason code, correlationId; entries are retained >= 365 days and searchable by jti and session When thresholds are met (e.g., > 5 replay rejections from one IP in 1 minute; > 20 failed validations in 5 minutes per org; redemption rate > 200% of 7-day baseline) Then admin alerts are sent to configured channels (email and in-app) within <= 2 minutes and populate the Security dashboard with trend charts And Then admins can acknowledge/resolve alerts; the dashboard shows engaged rate limits, top offending IPs/orgs, and last 24h event counts; CSV export for a selected date range succeeds
Handoff Analytics & Success Metrics
"As an attorney, I want visibility into handoff success and drop-offs so that I can optimize my intake flow and staff coaching."
Description

Instrument end‑to‑end events: QR generated, displayed, scanned, token verified, session resumed, passkey created, timeout, cancel, and error reasons. Capture device/browser, locale, and location context (clinic vs. curbside) while honoring consent and privacy settings. Expose funnel metrics (time‑to‑resume, success rate, drop‑off points) in a reporting dashboard and forward events to the analytics stack. Enable A/B testing of copy and UI variants to improve handoff completion and passkey adoption.

Acceptance Criteria
End-to-End Handoff Event Instrumentation
Rules: - The system emits analytics events for these steps: qr_generated, qr_displayed, qr_scanned, token_verified, session_resumed, passkey_created, timeout, cancel, error. - Each event includes: event_id (UUID), handoff_id (UUID), session_id (UUID), device_role (shared|personal), event_name, timestamp_utc (ISO 8601), sequence (monotonic int per handoff_id), browser_name, browser_version, os_name, app_version, locale, location_context (clinic|curbside|unknown), consent_status (granted|denied|unknown), ab_variant (string or null). - error events include error_code (enum) and error_reason (string up to 120 chars); timeout and cancel events include reason (enum) and duration_ms. - Events are published within 200 ms of the triggering action and are idempotent by event_id; duplicates are not stored twice downstream. - Event ordering is preserved per handoff_id by sequence; session_resumed can only occur after token_verified; passkey_created can only occur after session_resumed. - time_to_resume_ms is computed as timestamp(session_resumed) − timestamp(qr_displayed) and stored/derivable for each handoff. - Event payloads validate against a versioned JSON schema (schema_ver), and 100% of events in test pass schema validation.
Privacy-Respecting Analytics Collection
Rules: - No PII (names, emails, phone numbers, addresses, case details, free text inputs) is included in any analytics payload; automated validator rejects payloads containing disallowed keys/regexes. - When consent_status = denied, no analytics events are forwarded to external destinations; only minimal operational counters are kept server-side without identifiers. - Consent changes take effect within 1 second for subsequent events in the same session and are reflected in consent_status. - Location attribution does not use GPS; IP addresses are neither stored nor forwarded; location_context derives only from explicit staff selection or configured clinic device flags. - Data retention for analytics events is limited to a configurable maximum of 13 months; a deletion request by handoff_id removes all related analytics data within 24 hours and is verifiable by query returning zero results. - For EU locales, default consent is denied until explicitly granted; pre-consent event forwarding rate is 0%.
Device, Browser, Locale, and Location Context Attribution
Rules: - browser_name, browser_version, os_name, and app_version are parsed and populated for ≥98% of events; unknown values default to "unknown". - locale reflects the active UI language/Accept-Language at event time; changes are captured in subsequent events. - location_context is captured as clinic or curbside based on staff selection or device configuration; if not set, value is unknown and visible in dashboards for data-quality monitoring. - device_role is shared for events on the clinic/shared device and personal for events on the client device; both roles for the same handoff share the same handoff_id. - Attribution accuracy for device_role and location_context is ≥99% in integration tests across supported browsers and devices.
Funnel Metrics Dashboard (Resume Time, Success, Drop-offs)
Rules: - The dashboard displays counts and conversion rates for each funnel step: qr_generated → qr_displayed → qr_scanned → token_verified → session_resumed → passkey_created. - Success rate and step-to-step conversion rates are visible for any selected date range; time_to_resume p50 and p90 are displayed. - Metrics can be filtered by location_context, device_role, browser_name, locale, and ab_variant; multiple filters can be combined. - Data freshness: 95th percentile end-to-end latency from event to dashboard ≤ 5 minutes. - Dashboard totals match the underlying event store within ±1% for daily aggregates in backfills and streaming modes. - Users with analyst or admin roles can export CSV for the selected range; unauthorized roles cannot access the dashboard (HTTP 403).
Analytics Event Forwarding to External Stack
Rules: - Events are forwarded to the configured destinations (e.g., Segment, GA4, Kafka) with at-least-once delivery; duplicates carry the same event_id for downstream de-duplication. - p95 delivery latency from emission to destination acknowledgement ≤ 120 seconds; rolling 24h delivery success rate ≥ 99.9%. - Destination-specific payloads conform to naming/type constraints; validation failures are < 0.1% of events and are retried with exponential backoff up to 24 hours. - Tenant-level toggles can enable/disable each destination; changes take effect within 60 seconds and are auditable. - Forwarding respects consent_status; when consent is denied, no events are sent to external destinations for that handoff/session.
A/B Testing for Handoff Copy and UI Variants
Rules: - Experiments can define 2+ variants with target allocation (default 50/50); observed allocation over ≥1000 handoffs is within ±5% of target, stratified by location_context. - Variant assignment occurs at handoff_id and persists across devices; ab_variant is included on all events for that handoff. - Primary KPI is handoff completion (session_resumed); secondary KPI is passkey_created; the experiment view shows conversion lift, 95% CI, and p-values. - Experiments can be started/paused/stopped via admin UI; state changes are logged with actor and timestamp; paused/stopped experiments stop assigning new variants immediately. - A minimum sample size guard prevents automatic conclusions until the pre-set threshold is met; early stopping is disallowed unless an admin overrides with justification.
Error, Timeout, and Cancel Reason Taxonomy and Reporting
Rules: - timeout events fire when no session_resumed occurs before the configured TTL; include duration_ms and timeout_reason (qr_expired|inactivity|network). - cancel events include actor (staff|client), origin (shared|personal), and reason (user_backed_out|device_switch|privacy_declined). - error events use a controlled error_code set including at least: token_invalid, token_redeemed, token_expired, camera_permission_denied, browser_blocked_camera, network_error, server_error, analytics_forwarding_error; error_reason provides a short human-readable string. - Dashboard exposes error/timeout/cancel breakdowns by count and rate, trendable over time, and filterable by location_context and ab_variant. - Data-quality guard: if token_invalid/expired/redeemed occurs, no subsequent session_resumed event is recorded for that handoff; violations are <0.1% of handoffs and raise an internal alert.

PII Shield

Until a passkey login is completed, sensitive data stays redacted in the portal and notifications show only safe, minimal context. Download controls and screenshots are limited pre-auth, reducing accidental exposure if links are forwarded while preserving a smooth, mobile-first experience.

Requirements

PII Field Classification Engine
"As a firm admin, I want to classify sensitive fields once so that redaction and notifications stay safe automatically everywhere."
Description

Introduce a unified sensitivity classification layer that tags every data element across intake questionnaires, uploaded files, and document templates as PII, Sensitive PII, or Safe Metadata. Extend the field schema and template merge tags to carry classification, with default rules for common legal fields (e.g., SSN, DOB, account numbers) and an admin override for custom fields. Enforce classification at save time and during document assembly so that redaction and notification filters can act deterministically. Provide a migration utility to backfill classifications on existing matters and an SDK/API to programmatically set or query sensitivity. Include CI-style linting for templates and forms that blocks unclassified or misclassified fields. Expected outcome: all surfaces uniformly understand which content must be hidden pre-auth and how it should be masked.

Acceptance Criteria
Default Classification Rules for Common Legal Fields
Given a new form field labeled "Social Security Number" or matching an SSN pattern (###-##-#### or 9 digits), When the field is saved, Then its classification is set to "Sensitive PII". Given a field labeled "Date of Birth" or key "dob", When the field is saved, Then its classification is set to "Sensitive PII". Given a field labeled "Bank Account Number", "Routing Number", "Driver's License", or "Passport Number", When the field is saved, Then its classification is set to "Sensitive PII". Given a field labeled "Email", "Phone", or "Mailing Address", When the field is saved, Then its classification is set to "PII". Given a field that does not match any default rule or sensitive pattern, When the field is saved, Then its classification defaults to "Safe Metadata".
Admin Override of Classification on Custom Fields
Given an admin user with permission "Classification:Manage" sets an override classification on a field, When the field is saved, Then the override classification is stored and persists across sessions and environments. Given a default rule would classify the field differently, When both apply, Then the admin override takes precedence. Given an admin changes the override classification, When a subsequent save occurs, Then new records use the updated classification while existing stored records retain their previous classification metadata. Given an override value outside the allowed enum ["Sensitive PII","PII","Safe Metadata"], When saving, Then the operation fails with a validation error and no changes are persisted.
Save-Time Enforcement of Classification Completeness
Given a form submission or file upload introduces new fields, When saving the record, Then every field must have a valid classification in the allowed enum or the save is rejected with field-level error messages. Given classification is correctly resolved via defaults or overrides, When the record is saved, Then the classification value is written to the data store and is retrievable via the SDK/API. Given a field already has a classification, When re-saving the record without changes to that field, Then the existing classification is preserved.
Document Assembly Honors Classification Masking
Given a document template includes merge tags tied to fields classified as "Sensitive PII" or "PII", When a not-yet-passkey-authenticated user previews a document in the portal, Then values for those tags are masked according to masking rules (e.g., SSN shows ***-**-1234; email shows j***@domain.com). Given the same user completes passkey authentication, When the preview is refreshed or regenerated, Then full unmasked values are rendered. Given any merge tag lacks a classification, When assembly is attempted, Then the build fails with a clear lint error listing the offending tags and no document is produced. Given merge tags tied to "Safe Metadata", When previewed pre-auth, Then those values render unmasked.
Migration Utility Backfills Classifications on Existing Matters
Given a tenant with existing matters created before classification existed, When the migration utility runs, Then 100% of fields, merge tags, and file metadata are assigned a classification using default rules. Given items that cannot be confidently auto-classified, When migration completes, Then they are reported in a machine-readable report (e.g., CSV/JSON) flagged for admin review and are conservatively assigned "PII". Given the migration utility is executed multiple times, When run again, Then it is idempotent and does not duplicate work or change previously reviewed overrides.
SDK/API Supports Querying and Setting Classification
Given a client with scope "classification:read", When calling the API/SDK to read a field's classification, Then the service returns the current classification and HTTP 200 or equivalent success status. Given a client with scope "classification:write", When updating a field's classification to a valid enum value, Then the update persists, returns success, and an audit log entry records actor, timestamp, old value, and new value. Given a request with an invalid enum value or insufficient scope, When processed, Then the service responds with HTTP 400 for invalid input or 403 for insufficient permissions and no changes are persisted.
CI Linting Blocks Unclassified or Misclassified Templates and Forms
Given a template or form definition is submitted for validation, When the linter runs in CI mode, Then any field or merge tag without an explicit classification is reported as an error and the process exits non-zero. Given a field name or pattern matches a sensitive type (e.g., SSN, DOB, account number) but is marked "Safe Metadata", When linting runs, Then a misclassification error is reported with file and line number. Given all fields and tags are properly classified, When linting runs, Then it exits with status zero and reports a summary of counts by classification.
Passkey-Gated PII Reveal (WebAuthn)
"As a client, I want to use a quick passkey to view my documents so that my sensitive info stays protected if a link is forwarded."
Description

Require successful WebAuthn/FIDO2 passkey authentication with user verification before any PII-classified content is rendered in the portal. Support platform authenticators on iOS/Android and desktop with discoverable credentials and a streamlined enrollment flow during first secure access. Implement step-up re-authentication when a session is older than a configurable threshold or risk signals are detected. Allow email/SMS magic links to open only a redacted context; full reveal always requires a passkey. Handle error states, device changes, and accessibility, preserving a fast, mobile-first experience.

Acceptance Criteria
PII remains redacted until successful passkey verification
Given an unauthenticated or magic-link-only session When the portal loads any view or API endpoint containing PII-classified fields or files Then all PII values are masked in the UI, file previews are redacted, and API responses exclude PII payloads or return 403 until WebAuthn user verification succeeds And download/export actions are disabled pre-auth And upon successful WebAuthn/FIDO2 assertion with userVerification=required, the page re-renders to display full PII and enables downloads for the current session context
First-time passkey enrollment with platform authenticators
Given a verified account accessing secure content for the first time on a device with a platform authenticator When the user opts to enroll a passkey Then the browser performs navigator.credentials.create with discoverable credentials and userVerification=required, supported on iOS Safari, Android Chrome, macOS Safari/Chrome, and Windows Edge/Chrome And the server stores and binds the public key credential to the account and subsequent navigator.credentials.get succeeds on the same device And if the user cancels or an error occurs, PII remains redacted and the user is returned to a safe state with a retry path And enrollment completes within 5 seconds at p90 on reference mobile devices
Step-up re-authentication on session age or risk signals
Given an authenticated session When the session age exceeds the configured threshold (pii_reveal_max_session_age) or risk signals are detected (e.g., new device fingerprint, IP geolocation change >300km, elevated-sensitivity PII request) Then any attempt to view or download PII triggers navigator.credentials.get with userVerification=required And until a successful assertion is validated, PII stays redacted and downloads remain blocked And upon success, reveal proceeds and last_verified_at is updated for the session
Magic link opens redacted context only
Given a user opens the portal via email or SMS magic link without a recent passkey assertion Then all PII fields are masked, document thumbnails use redacted placeholders, and notification content shows minimal non-PII context And page source and network payloads contain no PII data pre-auth When the user selects Reveal with passkey Then the WebAuthn prompt is shown and only upon successful assertion is PII unmasked and file access enabled
Error states and device change handling without weakening assurance
Given a passkey assertion or enrollment is initiated When no compatible platform authenticator is available, the credential is not found, the user cancels, or the device has changed since enrollment Then the UI presents clear, accessible error messaging and options to retry, select another enrolled passkey, or use supported cross-device passkey flows (where available) And no non-passkey fallback can reveal PII And PII remains redacted after any failure and all events are logged with non-PII metadata
Accessibility and mobile-first performance for PII reveal
Given a user using assistive technologies on a mobile device When interacting with redacted views, passkey prompts, and reveal confirmations Then all controls have accessible names, focus order is logical, roles/states are announced, color contrast meets WCAG 2.1 AA, and the flow is fully keyboard/switch accessible And from tapping Reveal to PII visible is ≤1.5s at p50 and ≤2.5s at p90 on 4G reference devices; server verification latency ≤500ms at p90
Audit logging and privacy-by-design for reveal events
Given any PII reveal, step-up challenge, enrollment, failure, or download attempt occurs When the event is processed Then an immutable audit log entry is recorded with timestamp, user/account ID, device/OS/UA, IP (truncated as per policy), event type, and risk reason with no PII values captured And authorized admins can query these events by user and time window And logs are retained and protected per configured retention policy
Adaptive Redaction UI
"As a client, I want to see just enough context without revealing sensitive details so that I can confirm I’m in the right place before signing in."
Description

Render a mobile-first portal experience that masks PII until passkey completion, showing only safe context such as initials, last-4 digits, or generalized labels. Apply server-side redaction for previews and inline document views, with masked layers that remain non-selectable and non-copyable prior to auth. Present clear calls to action to complete passkey, maintain functional non-PII interactions, and ensure accessibility and localization. Persist redaction state on the server to prevent client-side bypass and guarantee consistent masking across devices and sessions.

Acceptance Criteria
Pre‑Auth Portal PII Masking
Given a session without completed passkey verification When any portal page renders PII fields (name, address, SSN, DOB, email, phone, account numbers, docket) Then each PII value is replaced with safe tokens (initials, last‑4, generalized labels) and no full value is visible And masked values are visually distinct from real values And the page contains no network responses or DOM nodes with unmasked PII
Passkey Completion Unmasks PII
Given a redacted view When the user completes passkey authentication successfully Then masked values are replaced with full PII within 1000 ms without a full page reload And subsequent navigation within the session keeps PII unmasked And on sign‑out or session expiry PII returns to masked state on next view
Server‑Side Redaction for Previews and Inline Documents
Given a session without passkey verification When requesting a document preview (PDF/HTML) or inline document view Then the server returns a rendition with all PII redacted and rendered non‑extractable (e.g., rasterized/overlay) so text selection/copy yields only masked tokens And print/download controls are hidden or disabled pre‑auth And direct URL requests cannot return unredacted originals unless the session is passkey‑verified
Clear CTA and Preserved Non‑PII Interactions
Given a redacted portal state When the page loads Then a persistent, accessible CTA to "Complete passkey to view details" is visible above the fold and invokes WebAuthn on tap/click And non‑PII interactions (e.g., scheduling, FAQs, non‑sensitive questionnaire steps) remain fully usable without blockers And on CTA success the user returns to the originating context with state preserved
Non‑Selectable, Non‑Copyable Masked Layers
Given masked content is displayed When the user attempts to select, copy, long‑press, or use context menu on masked elements Then selection handles do not expose underlying PII and clipboard receives only masked tokens And accessibility tree does not include unmasked PII in labels or descriptions
Accessibility and Localization Compliance
Given assistive technologies and multiple locales are used When rendering masked values and CTAs Then masked elements announce "redacted" plus safe token via ARIA without exposing PII And focus order, hit targets, and contrast meet WCAG 2.2 AA And EN/ES/FR and RTL locales display localized strings and formats without truncation or overlap
Redaction State Persistence Across Devices and Deep Links
Given a deep link is opened on any device When the session is not passkey‑verified Then the linked resource loads with PII masked and prompts for passkey And passkey verification on device A does not unmask PII on device B until device B completes its own passkey And server‑persisted redaction state governs all responses regardless of client cache or script execution
Safe Notifications Templates
"As an attorney, I want notifications that never include PII so that clients are informed without risk if messages are exposed."
Description

Provide email and SMS templates that strictly exclude PII and expose only minimal, non-sensitive context (e.g., matter nickname, generic document type). Implement a template linter that blocks insertion of PII-classified fields and automatically sanitizes dynamic content. Offer an admin template editor with real-time safety warnings, default compliant templates, and brandable but safe variables. Ensure links contain no PII, use short, opaque tokens, and present a clear “Open Securely” call to action. Disable attachments pre-auth and enforce DMARC/SPF-aligned sending with consistent, non-sensitive subjects and previews.

Acceptance Criteria
PII‑Free Email and SMS Rendering
Given a notification uses a safe template and is rendered with records containing PII‑classified fields (e.g., SSN, DOB, address, phone, email, account numbers, client name), When the subject, body, and preview are generated, Then they contain no PII tokens or values and only the allowed variables {matter_nickname}, {generic_document_type}, {brand_name}, {cta_text}, {cta_url}. Given a rendered notification, When scanned by the PII detector, Then zero PII rule hits are found across subject, body, preview, headers, and tracking parameters. Given a template references any PII‑classified field via direct, nested, or aliased syntax, When rendering is attempted, Then rendering is aborted, the event is logged with the offending token(s), and the message is not queued for delivery.
Template Linter Blocks PII Fields in Editor
Given an admin is editing a template, When they insert a PII‑classified merge field (e.g., {{client.first_name}}, {{ssn}}, {{email}}, {{phone}}), Then an inline blocking error appears within 100 ms, the field is highlighted, and Save/Publish controls are disabled. Given disallowed fields exist in the template, When Save or Publish is attempted, Then the action is blocked and guidance suggests safe alternatives (e.g., {matter_nickname}, {generic_document_type}). Given a repository or environment build, When the linter runs in CI/CD, Then it exits non‑zero if any template contains disallowed fields or unsafe expressions, preventing deployment.
Automatic Sanitization of Dynamic Content
Given allowed variables contain unexpected PII patterns (e.g., matter_nickname="Smith SSN 123‑45‑6789"), When rendering, Then PII patterns are redacted (e.g., SSN -> ***‑**‑****) and the message renders without error. Given user‑supplied input includes HTML/JS, When rendering email/SMS, Then HTML is escaped, scripts/styles are stripped, and no remote resources are auto‑loaded from untrusted domains. Given the final SMS content is produced, When measured, Then it contains only GSM‑safe characters or is normalized, and no embedded PII remains after sanitization.
Secure, Opaque, PII‑Free Links and CTA
Given a notification includes a portal link, When inspecting all URLs, Then no path, subdomain, fragment, or query parameter contains PII or user identifiers; only a single opaque token parameter is present. Given the login link is generated, When validated, Then the token is URL‑safe, opaque, and 20–32 characters of base62/base64url with at least 80 bits of entropy, and the URL is HTTPS on an approved domain. Given the message is rendered, When viewing the primary action, Then the CTA text reads exactly "Open Securely" and appears once per message (email and SMS).
Pre‑Auth Attachments Disabled
Given a notification template includes attachments, When the recipient has not completed passkey login for the current session, Then all attachments are omitted from the MIME/SMS payload and replaced with the secure portal link. Given an email client or SMS forward occurs, When the forwarded message is viewed by a third party, Then no attachment bytes or inline PII are present in the message content. Given an attempt is made to add an attachment via the editor or API, When the notification is marked as pre‑auth, Then the system blocks the addition and surfaces a warning explaining that attachments are disabled until secure login.
Deliverability and Non‑Sensitive Subject/Preview
Given an email is sent, When evaluated by receiving servers, Then SPF=pass and DKIM=pass with alignment to the From domain, and DMARC=pass is recorded in aggregate logs. Given the subject and preview text are generated, When scanned by the PII detector, Then zero PII rule hits are found; the subject uses a consistent non‑sensitive pattern like "[Briefly] {matter_nickname}: New document available" and is ≤ 60 characters; the preview is a generic phrase (e.g., "Open securely to view."). Given a template is updated, When the change is published, Then a canary send verifies deliverability and absence of PII before enabling full rollout.
Admin Editor Safety UX and Defaults
Given an admin opens the template editor, When selecting from variables, Then only a curated list of safe variables is available ({matter_nickname}, {generic_document_type}, {brand_name}, {cta_text}, {cta_url}), and PII‑classified variables are hidden. Given the admin types freeform content, When a potential PII pattern is detected, Then a real‑time warning banner appears with the specific pattern found and a link to guidance; the preview pane shows the redacted output. Given a new workspace is created, When the editor loads, Then default compliant templates are available out‑of‑the‑box with safe branding options (logo, colors) and pass the linter with zero warnings.
Pre-Auth Download Guard & Watermarking
"As a client, I want downloads limited until I authenticate so that my documents can’t be easily leaked if a link is forwarded."
Description

Block downloads, exports, and printing for any assets containing PII until a passkey-verified session is established. Serve only redacted, low-resolution, inline previews pre-auth with a persistent, dynamic watermark (viewer ID, timestamp, matter ID) to deter sharing and enable attribution. For PDFs, rasterize and mask server-side to prevent layer stripping; set headers to inline and disable content-disposition downloads. Detect and log attempted print and screenshot events where supported, showing user-facing warnings. After passkey, allow downloads according to policy with optional post-auth watermarking.

Acceptance Criteria
Pre-auth redacted low-resolution inline preview with watermark
Given a user without a current passkey-verified session requests to view an asset flagged containsPII=true When the portal renders the asset Then the server delivers an inline preview only (Content-Disposition: inline) at ≤150 DPI or ≤1600px longest edge with all text layers removed And all defined PII fields (SSN, DOB, address, account numbers, emails, phone, full names where configured) are masked via burned-in redaction And a dynamic, persistent watermark overlays the preview showing anonSessionId or viewerFingerprint, UTC timestamp (ISO-8601), and matterId on each page And no direct URL to the original file is exposed in the DOM, network responses, or prefetch links
Pre-auth downloads and exports blocked with user guidance and audit
Given a user without a passkey-verified session attempts to download, export, or Save As an asset flagged containsPII=true When any download/export endpoint is invoked or a related UI control is used Then the action is blocked: HTTP 403 with errorCode PREAUTH_BLOCKED and the UI shows "Sign in with passkey to download" And all download/export/print UI controls are hidden or disabled until passkey verification completes And an audit event download_blocked_pre_auth is recorded with sessionId, assetId, userId (if known), IP, userAgent, and timestamp
Pre-auth PDF rasterization and mask integrity
Given a PII PDF is requested in a non-passkey-verified session When the preview is served Then the returned content is image-based (no selectable text, no extractable layers), with redactions irreversibly burned in server-side And attempts to open the preview in a PDF editor show zero text objects and no removable annotation/redaction layers And response headers include Content-Disposition: inline, X-Content-Type-Options: nosniff, Cache-Control: no-store, and no Content-Disposition: attachment
Pre-auth print attempt interception and logging
Given a user without a passkey-verified session triggers a print action (Ctrl/Cmd+P, browser menu, print button) on a PII preview When the print flow starts Then the application prevents printing of unredacted content by rendering either a blocked page or the same redacted, watermarked preview only And a warning modal is shown directing the user to complete passkey verification And an audit event print_blocked_pre_auth is recorded with sessionId, assetId, and timestamp
Pre-auth screenshot deterrence and warning (platform-aware)
Given an Android device and a user without a passkey-verified session views a PII preview When the user attempts a screenshot or screen recording Then FLAG_SECURE is active and the capture is prevented and an audit event screenshot_prevented_pre_auth is recorded Given an iOS device and a user without a passkey-verified session views a PII preview When the system reports a screen capture event Then the app displays a warning banner, dims sensitive content during capture, and records audit event screenshot_detected_pre_auth with device info and timestamp
Post-auth download enablement with optional watermarking and policy enforcement
Given a user completes passkey authentication and has policy permission download=true for the asset When the user requests a download Then the server returns the original file with Content-Disposition: attachment; filename set per policy, and applies a post-auth watermark if policy watermarking=true including viewerId, UTC timestamp, and matterId on each page And an audit event download_allowed is recorded with userId, assetId, and timestamp Given a user completes passkey authentication but policy denies downloads (download=false) When the user attempts to download Then the server returns HTTP 403 with errorCode POLICY_DENIED and the UI displays "Downloads disabled for this matter"
Ephemeral, Recipient-Bound Links
"As a firm admin, I want links that are safe if forwarded so that only the intended user can reveal PII after verifying."
Description

Issue single-use, short-lived magic links that open only a redacted view and bind to the first verified device/session. Apply contextual risk checks (geo/IP anomalies, device change) to force immediate passkey before any additional actions. Support rapid expiry after first open, easy revocation by staff, key rotation for signing, and minimal state exposure. If a link is forwarded, the recipient sees only the redacted context and a passkey prompt. Log reason codes and outcomes for each link interaction to feed audit and alerting.

Acceptance Criteria
Single-Use, Short‑Lived Link Lifecycle
Given a staff member issues a magic link with initial_ttl <= 24 hours, When the link is created, Then the link includes an absolute expiration timestamp and is invalid after that time. Given a magic link has not been opened, When it is opened the first time, Then a post_open_ttl <= 10 minutes is set and the link expires at now + post_open_ttl. Given a magic link has been opened once, When the same URL is opened again from any device or session, Then access is denied with HTTP 410 and a "Link already used" message. Given a magic link is expired by time or post_open_ttl, When it is accessed, Then access is denied with HTTP 410 and no sensitive state is returned in the response body.
Recipient‑Bound Device/Session Binding
Given a magic link is opened for the first time, When device fingerprint and session ID are established, Then the link binds to that device/session and the binding is persisted. Given a magic link is bound to device/session A, When the same link is opened on device/session B before passkey authentication, Then only the redacted context and a passkey prompt are shown and no unredacted data is revealed. Given a bound device/session A changes critical fingerprint attributes during the pre-auth session, When any action is requested, Then a passkey prompt is required before proceeding. Given passkey authentication is completed on the bound device/session, When unredacted content is requested, Then unredacted access is granted only on the bound session and remains denied on all other devices.
Pre‑Auth Redacted View and Download/Screenshot Limits
Given a magic link is opened and passkey authentication has not occurred, When the redacted view is displayed, Then PII fields (SSN, DOB, addresses, phone numbers, emails, account numbers) are masked or omitted. Given the user is pre-auth, When they attempt to download, export, print, or copy content, Then download/export/print controls are hidden or disabled and file responses are blocked with HTTP 401 and a passkey prompt is shown. Given the user is pre-auth on mobile or desktop, When they attempt to access sensitive assets via direct URL or long-press actions, Then those asset requests are denied server-side until passkey authentication succeeds. Given the user is pre-auth, When the UI renders, Then a dynamic watermark (timestamp, link_id) overlays the content to discourage screenshots and indicates "Redacted" state.
Contextual Risk Checks and Forced Passkey Gate
Given a magic link open event, When the IP ASN differs from the last known ASN for the contact or the geolocation distance exceeds 500 km from last known city, Then immediate passkey authentication is required before any content beyond the landing banner is shown. Given the link is opened from a new device fingerprint or from an IP flagged as VPN/Tor, When the request is processed, Then the passkey gate is enforced and all downloads are blocked until passkey success. Given a risk check is evaluated, When a decision is made, Then standardized reason code(s) (e.g., GEO_DISTANCE, NEW_DEVICE, VPN_ASN) are recorded with the interaction event. Given passkey authentication fails or is canceled under a risk gate, When subsequent attempts are made, Then the session is rate-limited after 5 failed attempts within 15 minutes and no additional context is revealed.
Staff Revocation with Near‑Real‑Time Invalidation
Given a staff user selects Revoke on an issued link, When the action is confirmed, Then the link is invalidated across cache and origin within 60 seconds. Given a link is revoked, When an already-open pre-auth session attempts any action, Then the session is terminated and redirected to a Link Revoked screen with support contact. Given a link is revoked, When a fully passkey-authenticated session exists that relies on the link, Then continued access is denied and re-authentication via passkey is required. Given a revoked link is requested, When the URL is accessed, Then the system returns HTTP 410 and logs a REVOCATION reason code.
Key Rotation for Link Signing and Validation
Given link signing keys follow a rotation policy, When a new key is promoted to active, Then newly issued links are signed with the new key within 5 minutes. Given existing links were signed with prior keys, When those links are presented within their valid TTL, Then they validate against inactive-but-valid keys until the configured grace period ends. Given a key passes beyond the grace window, When a link signed by that key is presented, Then validation fails and the response indicates invalid signature without exposing sensitive state. Given a key is marked as revoked due to compromise, When any link signed by that key is presented, Then validation fails immediately and the attempt is logged with KEY_REVOKED.
Audit Logging with Reason Codes for Link Interactions
Given any magic link interaction (create, open, bind, risk_evaluated, passkey_prompted, passkey_success, passkey_failure, revoke, expire), When the event occurs, Then an immutable audit record is written with link_id, contact_id, event_type, UTC timestamp, IP, geo (city, country), device fingerprint hash, user agent, decision/outcome, and reason_codes[]. Given audit records exist, When queried by link_id or contact_id for the last 30 days, Then results return within 2 seconds at the 95th percentile. Given audit logging stores context, When records are persisted, Then no raw sensitive PII (e.g., SSN, DOB, full address) is stored and retention is at least 1 year with tamper-evident integrity. Given an alert rule for suspicious activity (e.g., 3 failed passkey attempts from distinct IPs in 15 minutes) is configured, When conditions are met, Then an alert is emitted within 60 seconds with a link to the audit trail.
Admin Policy Controls & Audit Trails
"As a managing attorney, I want configurable policies and detailed logs so that we meet compliance and can investigate incidents."
Description

Deliver an admin console to define PII Shield policies per matter type and role: redaction strictness, PII reveal session timeout, allowed post-auth download actions, watermark text, and approved notification templates. Record immutable audit logs for redacted view access, passkey enrollments and verifications, download/print attempts, and risk-triggered events. Provide exportable reports, webhook integrations for SIEM, configurable retention, and threshold-based alerts for suspicious activity. Enforce role-based access controls to limit who can change policies and view sensitive logs.

Acceptance Criteria
RBAC: Restrict Policy Editing and Sensitive Log Visibility by Role
Given a signed-in user with role Policy Admin, when they open the Admin Console, then they can create, edit, and publish PII Shield policies and cannot view sensitive audit logs unless they also have role Security Auditor. Given a signed-in user with role Security Auditor, when they open the Audit Logs, then they can view sensitive audit log details and cannot modify PII Shield policies. Given a signed-in user without Policy Admin or Security Auditor roles, when they attempt to access policy editing or sensitive logs via UI or API, then the UI hides controls and the API returns HTTP 403 with an RBAC error code, and the attempt is logged as a denied action. Given any policy change is submitted, when the user has Policy Admin role, then the change requires passkey re-verification within the last 5 minutes or prompts for re-verification before applying. Given a published policy, when accessed by any user, then the effective policy version is displayed, and all access to policy and logs is recorded with user id, role, timestamp, and request origin.
Per-Matter-Type Policy Configuration Applies at Runtime
Given a policy for matter type Debt Collection setting redaction strictness=High, PII reveal session timeout=10 minutes, allowed downloads=PDF only, watermark text=CONFIDENTIAL – CLIENT COPY, and approved notification templates=DC_v3, when a Client views their portal pre-passkey, then all configured PII fields render as redacted and download/print controls are disabled. Given the same policy, when the Client completes passkey verification, then PII fields are revealed and remain visible until 10 minutes of inactivity, after which they re-redact and downloads/print are disabled until re-verified. Given the same policy, when the Client downloads a document post-auth, then only a PDF is available, the file contains the exact watermark text with timestamp, user id, and matter id, and the event is logged. Given notifications are sent for this matter type, then only templates from DC_v3 are selectable/used and the template id is recorded in the audit log. Given a different matter type Small Claims with stricter settings, when a user accesses it, then those settings override global defaults and behave as configured.
Immutable Audit Logging of Sensitive Events
Given audit logging is enabled, when any of the following occur—redacted view access, passkey enrollment, passkey verification, download attempt, print attempt, or risk-triggered event—then an audit record is appended with event_type, actor_id, actor_role, matter_id, policy_version, outcome, UTC ISO8601 timestamp, IP, user_agent, and request_id. Given the audit store, when records are written, then each record includes a cryptographic hash and a hash chain reference to the previous record, and direct update/delete operations are disallowed (HTTP 405) and logged as tamper attempts. Given a read request for logs, when a record’s hash chain is validated, then the API returns integrity_status=valid; if broken, integrity_status=failed and an alert is generated. Given system time skew, when logs are ingested, then timestamps are normalized to UTC and include source clock offset metadata. Given an audit viewer with Security Auditor role, when filtering by event_type and time range, then results return within 2 seconds for 10k matching records.
Exportable Reports with RBAC, Filtering, and Data Minimization
Given a Security Auditor filters logs by time range, user, event_type, and matter_type, when they export, then a downloadable CSV and NDJSON stream is provided with column headers/keys and a SHA-256 checksum manifest. Given an export is requested, when the dataset exceeds 100k records, then the system performs a streamed export with pagination cursors and completes without exceeding memory limits, and progress is visible in the UI. Given RBAC rules, when a non-authorized user requests an export, then the request is rejected with HTTP 403 and the attempt is logged. Given data minimization, when exporting, then PII values are redacted unless the requester has explicit permission to view PII, and the export metadata records which fields were redacted. Given an export completes, when downloaded, then the file name includes a timestamp, filter summary, and policy_version, and the export event is logged.
Webhook Delivery to SIEM with Signed, Reliable Events
Given a configured webhook endpoint with URL, HMAC secret, version=v1, and enabled event types, when a matching audit event is created, then the system POSTs JSON within 15 seconds including id, type, created_at (UTC), payload, and an X-Signature header (HMAC-SHA256) and X-Event-Id idempotency key. Given the SIEM responds with 2xx, then the delivery is marked succeeded; given 5xx or network failure, then the system retries with exponential backoff for up to 24 hours and at most 10 attempts; given 4xx (other than 429), then retries stop and the delivery is marked failed. Given repeated failures, when the retry budget is exhausted, then the event is placed in a dead-letter queue and an alert is created for admins. Given the endpoint returns 429 with Retry-After, then the next retry respects the header value. Given a webhook is disabled or returns 410, then further deliveries for that destination stop and an admin is notified.
Configurable Retention, Purge, and Legal Hold
Given retention policies per event_type are configured (e.g., 365 days for standard, 1825 days for security events), when the daily purge job runs, then audit records older than their TTL are permanently deleted and a purge summary log is created. Given a matter or record is placed on legal hold by a Security Auditor, when the purge job runs, then held records are excluded from deletion until the hold is removed, and holds are auditable. Given RBAC, when a non-authorized user attempts to change retention settings, then the request is rejected with HTTP 403 and logged. Given an export request spans data outside the retention window, then the export excludes purged records and the export metadata indicates the retention limits applied. Given clock changes and time zones, when purging, then the cutoff is computed in UTC and logged with the applied policy version.
Threshold-Based Anomaly Detection and Alerts
Given an admin defines a rule ">=5 failed passkey verifications from same IP within 10 minutes", when the threshold is met, then an alert is generated within 60 seconds containing rule_id, count, sample events, IP, geo, and affected user ids, and is sent to configured channels (email, webhook). Given an admin defines a rule ">20 redacted views by one user in 1 hour" and a rule ">3 downloads per matter in 24 hours", when either is triggered, then a single alert per rule is emitted per subject within a 30-minute cooldown to prevent duplicate noise. Given an alert is sent via email, then subject and body include severity, rule name, time window, and a deep link to filtered audit logs; given webhook, then the payload is signed as per webhook policy. Given a rule is disabled or its threshold updated, when changes are published, then they take effect for new windows and the change is logged with the editor’s user id. Given an alert is acknowledged by a Security Auditor, then its status changes to acknowledged and acknowledgments are auditable.

Trust Split Guard

Enforces compliant trust vs. operating routing at checkout. Automatically classifies amounts, blocks prohibited commingling or fee withdrawals from trust, writes IOLTA‑ready ledger entries per matter, and captures required consents. Built‑in state‑aware rules and one‑click reconciliation exports reduce ethics risk and monthly bookkeeping time.

Requirements

Automated Trust/Operating Split at Checkout
"As a consumer-law attorney, I want payments automatically split and routed to trust or operating based on line-item classification so that I avoid ethical violations and eliminate manual bookkeeping at checkout."
Description

Implements real-time classification and routing of payment amounts during checkout based on line-item type, matter context, and payment method. The system separates retainers and settlement proceeds (trust) from earned fees, costs, taxes, and surcharges (operating), then routes each portion to the appropriate merchant account without commingling. It enforces state-specific restrictions (e.g., no fee withdrawals from trust, card fee handling), blocks prohibited mixes, and provides actionable error messages. Supports partial payments, multiple processors/accounts, idempotent retries, refunds and chargebacks with mirrored adjustments, and a mobile-first UI embedded in Briefly’s e-sign and intake flow.

Acceptance Criteria
Real-Time Split Routing of Mixed Line Items
Given a checkout containing line items labeled Retainer, Settlement Proceeds, Earned Fees, Costs, Taxes, and Card Surcharge linked to Matter M and Firm F with configured trust and operating merchant accounts When the client authorizes payment of a single total amount via card or ACH Then the system classifies each line item by type and routes trust-designated amounts (Retainer, Settlement Proceeds) to F's trust merchant account for M and operating-designated amounts (Earned Fees, Costs, Taxes, Card Surcharge) to F's operating merchant account without commingling And the processor returns distinct transaction IDs per destination account and the UI and API expose both IDs And the split decision and fund routing completes within 1.0s at p95 and 2.0s at p99 And the matter ledger records separate entries per line item with account type (Trust/Operating), amount, timestamp, and transaction ID And no netting or internal transfer occurs between trust and operating within the transaction
State-Aware Restrictions and Card Fee Compliance
Given Firm F has its jurisdiction set to State S with rule set RS and a checkout includes a card surcharge and mixed line items When the checkout is evaluated against RS Then if RS prohibits passing card fees on trust deposits, the checkout is blocked when surcharge would affect trust funds and an actionable error is shown including State S, rule citation, and remediation (“remove surcharge or absorb fee”) And if RS prohibits fee withdrawals from trust, any earned-fee line items are routed exclusively to operating and attempts to fund fees from trust are blocked with an actionable error And if RS allows surcharging on operating only, the surcharge is routed to operating while the trust amount remains unaffected And all applied rules and decisions are recorded in an audit log with rule IDs and timestamps
Partial Payments Allocation Without Commingling
Given an invoice with multiple line items across trust and operating totaling T and a client enters a partial payment amount P<T When the client confirms payment Then the system allocates P to line items in invoice order while preserving account separation, funding each line item up to its remaining balance and routing each funded portion to its respective account And no portion of P intended for operating items is applied to trust items or vice versa And the UI shows a pre-authorization allocation preview with amounts per account and requires client confirmation And the API response returns the allocation map and remaining balances per line item and per account
Idempotent Retries and Double-Submit Protection
Given a checkout request with idempotency key K and payload P is submitted When a retry with the same K and identical P occurs within 24 hours Then no additional charges are created and the original split transaction IDs and ledger entries are returned And when a retry with the same K but different P occurs Then the request is rejected with HTTP 409 Conflict and details of mismatched fields And client-side double-clicks or back/forward resubmits do not create duplicate charges And deduplication also checks processor transaction reference to prevent duplicates if K is absent
Refunds and Chargebacks with Mirrored Ledger Adjustments
Given a historical split transaction with trust portion T_trust and operating portion T_operating When a full or partial refund R is initiated Then refunds are issued from the same destination accounts as the original portions, never drawing operating refunds from trust or trust refunds from operating And the matter ledger writes negative entries per line item and account type with links to original transaction IDs and refund references And when a chargeback occurs on any portion Then a hold entry is posted on the corresponding account and matter ledger with reason codes, and reconciliation export reflects the adjustment And pro-rated refunds respect original line-item mappings and the API returns a per-line-item refund breakdown
Mobile-First Embedded Checkout and Consent Capture
Given the client is completing checkout inside Briefly’s e-sign flow on a mobile device (viewport 360–414px) over 4G When the payment review screen loads Then the itemized split (trust vs operating) and totals per account are displayed and the screen renders within 2.0s p95 and 3.5s p99 And when the client proceeds to pay Then required consents are presented (trust deposit authorization, card surcharge consent if applicable, and state-specific disclosures), the client must explicitly agree via checkbox and e-sign, and consent artifacts are stored with timestamp, IP, and document hash And checkout cannot complete without required consents and the receipt/export includes consent summaries and split details And the UI is accessible with labeled fields, logical focus order, and minimum contrast ratio 4.5:1
Multi-Processor Account Selection and Failover
Given Firm F has multiple merchant accounts for trust and operating across processors with routing rules by state, currency, and practice area When a checkout is submitted Then the system selects the correct trust and operating accounts per rules and logs the selection rationale with rule IDs And when the primary processor for either account is unavailable Then the system fails over to the configured secondary account of the same account type without changing split amounts; if no secondary exists, the checkout is blocked with an actionable error And at no point are trust-designated amounts routed to an operating account or vice versa during failover And the API response includes the processor and account IDs actually used
State-Aware Compliance Rules Engine
"As a firm owner, I want the system to automatically apply my state’s trust accounting rules during payments and disbursements so that prohibited actions are blocked and required steps are enforced without manual research."
Description

Provides a maintainable, versioned rules engine that evaluates jurisdiction-specific trust accounting requirements at payment, transfer, and refund time. Detects governing state from firm, matter, or court venue, applies prohibitions and thresholds, determines required disclosures/consents, and blocks or requires approvals when needed. Includes a rule library with effective dates, change logs, test fixtures, and safe rollout. Allows firm-level configuration within compliant bounds with admin-justified overrides, and delivers machine-readable outcomes to the checkout and ledger subsystems.

Acceptance Criteria
Auto-Detect Governing Jurisdiction on Payment
Given a payment request with firm.default_state=FL, matter.state=GA, and court.venue_state=AL When the rules engine resolves jurisdiction Then jurisdiction_code=GA and jurisdiction_source="matter" are returned and persisted with evaluation_id and ruleset_version And an audit event "jurisdiction_resolved" is emitted containing evaluation_id, jurisdiction_code, jurisdiction_source, ruleset_version, matter_id, firm_id, timestamp And the resolution completes within 150ms p95 across 1,000 evaluations Given no jurisdictional hints are available (no firm default, no matter state, no court venue) When the rules engine resolves jurisdiction Then the decision is blocked with error_code="JURISDICTION_UNDETERMINED" and message including remediation steps to set one of the sources
Enforce State-Specific Trust Prohibitions and Thresholds
Given jurisdiction_code is resolved and the rule library marks specific transaction components as prohibited from trust (e.g., processing_fee, surcharge, earned_fee) When a checkout split proposes any prohibited component to be routed from trust Then the engine returns decision.status="blocked" for those components with reason_code="PROHIBITED_FROM_TRUST", rule_id, and an alternative routing suggestion if permitted And the engine guarantees no commingling by returning a normalized split where client_funds -> trust and earned_fees -> operating when compliant Given a rule defines a numeric threshold (e.g., max_unearned_transfer=0) When a transfer or refund exceeds the allowed threshold Then the engine returns decision.status="blocked" with reason_code="THRESHOLD_EXCEEDED", threshold_value, actual_value, and required next_action (e.g., requires_approval) And all returned decisions include deterministic IDs and are reproducible with the same inputs
Required Disclosures and Consents Collection at Checkout
Given the resolved jurisdiction and payment context require disclosures/consents When the rules engine is called by checkout Then it returns required_disclosures[] with fields {id, rule_id, text, language_code, display_at, requires_consent:boolean} And checkout must record consents[] with fields {id, rule_id, text_hash, accepted_at, actor_id, ip, user_agent} Given any disclosure marked requires_consent is not accepted When the user attempts to proceed Then the engine response enforces decision.status="blocked" with error_code="MISSING_REQUIRED_CONSENT" and lists missing ids And all collected consents are persisted to the matter/transaction record and are retrievable by evaluation_id
Block or Require Approval with Complete Audit Trail
Given a transaction triggers a rule that requires elevated approval (e.g., transferring unearned funds from trust to operating) When the engine evaluates the action Then it returns decision.status="requires_approval" with fields {required_role, reason_code, rule_id, approver_count=1} And the action cannot proceed until an approval record exists referencing evaluation_id When an approver with the required_role approves Then the engine reevaluates and either returns decision.status="allowed" or "blocked" with updated audit trail And the audit trail stores {approval_id, approver_user_id, approver_role, justification(optional), timestamp, ruleset_version, rule_id} and is immutable
Versioned Rule Library with Effective Dates and Safe Rollout
Given the rule library contains versions with {rule_id, version, effective_start, effective_end, change_log_id} When evaluation occurs at time T Then only versions where effective_start <= T < effective_end are applied and the response includes ruleset_version Given safe_rollout.mode="dry_run" When evaluations run Then enforcement uses current version while diagnostics include {candidate_version_result, diff_summary} and no user-facing blocks arise from candidate Given safe_rollout.mode="canary" and canary_percentage=20 When evaluations run across firms Then candidate version is enforced for a stable, randomly selected 20% of firm_ids and current version for others, recorded in diagnostics And loading or updating rules completes within 500ms and publishes a change_log entry; associated test_fixtures all pass before activation
Firm-Level Configuration Within Compliant Bounds and Admin Overrides
Given a firm submits configuration values When the engine validates them against rule-defined bounds and allowed options Then out-of-bounds values are rejected with error_code="CONFIG_OUT_OF_BOUNDS" and pointers to the invalid fields Given a configuration is overrideable When an admin attempts an override Then the system requires {justification_text>=20 chars, expires_at<=90 days, approver_role="Compliance Admin"} And on approval the override is stored with {override_id, rule_id, baseline_value, override_value, justification_text, expires_at, approver_id} When an override expires Then enforcement reverts to baseline automatically and subsequent noncompliant actions are blocked; notifications are emitted
Machine-Readable Outcomes to Checkout and Ledger
Given an evaluation completes When the engine returns its outcome Then the payload conforms to schema v1 with fields {evaluation_id, jurisdiction_code, jurisdiction_source, ruleset_version, decisions[], required_disclosures[], diagnostics} And each decisions[] item includes {type: route|block|requires_approval, amount, currency, source_account: trust|operating, destination_account, reason_code, rule_id, next_action(optional)} When ledger ingests the outcome Then it creates IOLTA-ready entries per matter with fields {matter_id, entry_id, account: trust|operating, amount, currency, memo, compliance_tag} And the reconciliation export reflects these entries and balances match decisions[] totals; schema validation passes and end-to-end p95 latency <=200ms
Required Consents & Disclosures Capture
"As a client-facing attorney, I want required disclosures shown and consents captured and stored with the payment and retainer so that I can evidence compliance and resolve disputes quickly."
Description

Dynamically presents state-appropriate disclosures and obtains required client consents and payment authorizations at checkout and within the retainer e-sign flow. Merges consent text into the engagement agreement, binds it to the specific matter and transaction, and stores tamper-evident records with timestamps, signer identity, and device metadata. Supports multi-language templates, ADA-compliant mobile UX, offline-safe receipt generation, and retrieval via the matter file and payment receipt. Provides versioned consent templates linked to the rules engine and surfaces proof during audits or disputes.

Acceptance Criteria
State-Aware Disclosures and Consent at Checkout
Given a client in state S with matter type Y is at checkout When the rules engine evaluates required disclosures and authorizations Then the UI displays only the state-appropriate disclosures and payment authorizations for S and Y in the client's selected language And each consent is presented with an unchecked-by-default checkbox and a required e-sign field And the Pay button remains disabled until all required consents are affirmatively checked and the e-sign is completed And attempting to continue without required consents shows inline errors and prevents submission And the captured consent event includes rule_version, template_version, locale, timestamp (ISO 8601), signer identity (name, email, phone), and device metadata (IP, user agent, timezone)
Template Versioning and Rules Engine Linkage
Given consent templates with versions linked to rule sets with effective dates When the system date/time is on or after a rule change effective date Then new checkouts and e-sign flows automatically use the new template_version associated with the active rule_version And records created before the effective date continue to reference and render the prior template_version without mutation And an admin can preview which template will apply for a given state, matter type, and date And unit tests pass for at least three effective-date boundary cases (T-1 minute, T, T+1 minute)
Retainer E-Sign Consent Merge and Binding
Given a client signs the retainer for Matter M and Transaction T When the signed agreement is generated Then the full consent and disclosure text is merged into the agreement as a signed annex with the exact language presented to the client And the PDF footer displays Matter ID M and Transaction ID T on every page And the signature envelope stores timestamp, signer identity, and device metadata and is cross-referenced in the matter file And the agreement metadata includes template_version and rule_version used
Tamper-Evident Consent Record Storage and Verification
Given a consent record is stored When its integrity is validated Then the stored SHA-256 hash of the PDF and JSON audit bundle matches a freshly computed hash And any mismatch marks the record as compromised, emits an alert, and blocks export and download And updates create a new immutable version linked to the prior record; the original remains readable but not editable And the audit log captures who performed the validation with timestamp
Accessible Multi-Language Mobile Consent UX
Given a mobile user with preferred language L and accessibility settings (screen reader, large text) When the consent UI is rendered Then content fully renders in language L with no mixed-language fragments and all placeholders resolved And the UI meets WCAG 2.1 AA: labels on all inputs, focus order logical, minimum contrast 4.5:1, hit targets >= 44x44dp, and error messages announced to screen readers And automated axe-core scan reports zero critical/serious issues and Lighthouse accessibility score >= 90 And the consent screen becomes interactive within 3 seconds at 3G Fast network emulation on a mid-range device
Offline-Safe Receipt Generation and Sync
Given a checkout where connectivity is lost after the user completes consents When the user taps Save & Generate Receipt Then a device-stored receipt is generated with QR code, matter ID, provisional transaction reference, timestamp, signer identity, and consent hash And the app clearly indicates offline mode and prevents payment submission until connectivity is restored and server confirms consent receipt And upon reconnection within 24 hours the receipt and consent bundle auto-sync, receive a server transaction ID, and reconcile without duplicate records And if sync does not complete within 24 hours the record is flagged for review and export is disabled
Consent Retrieval and Audit Package Exposure
Given a user opens Matter M or views Payment Receipt for Transaction T When they select View Consents Then the system returns the signed consent bundle (PDF and JSON audit) within 2 seconds at p95 and displays template_version and rule_version And a Download Audit Package is available containing PDF, JSON audit trail, hashes, timestamps, signer identity, device metadata, and reconciliation export And a read-only, expiring share link (default 72 hours) can be generated for auditors with access logs recorded And search by Matter ID, Transaction ID, or signer email returns the consent record within 1 second at p95
Per-Matter IOLTA Ledger Automation
"As a bookkeeper, I want per-matter trust ledgers to update automatically with every transaction so that monthly three-way reconciliation is accurate and audit-ready with minimal manual work."
Description

Automatically creates immutable, per-matter trust sub-ledger entries for all inflows, outflows, holds, fees, refunds, and chargebacks, maintaining running balances and preventing negative or commingled positions. Supports three-way reconciliation by tracking bank balance, client sub-ledger totals, and general ledger, and by tagging each transaction with matter, client, and processor IDs. Provides correction via reversing entries, NSF handling, interest treatment per IOLTA rules, monthly statements, and audit-ready views. Integrates with Briefly’s matter model to surface available trust balances during drafting, billing, and disbursement decisions.

Acceptance Criteria
Immutable Per‑Matter Ledger Entry Creation and Tagging
Given a successful trust transaction event (deposit|outflow|hold|fee|refund|chargeback), When the processor webhook is received and verified, Then an immutable ledger entry is created within 2 seconds, tagged with matter_id, client_id, trust_account_id, processor_txn_id, actor_id, and ISO8601 timestamp. Then the entry amount is recorded in cents with currency code, and entry_type is one of [deposit,outflow,hold,fee,refund,chargeback,interest,nsf,reversal]. Then the matter sub-ledger running balance equals previous_balance + signed_amount, accurate to the cent. Then direct edits to any persisted field are blocked (HTTP 403), and the attempt is audit-logged with user_id and reason.
Negative Balance and Commingling Prevention Rules
Given a matter with balance B and holds H, When a user attempts a trust disbursement for amount D, Then the system blocks if D > (B - H) and returns error TRUST_INSUFFICIENT_FUNDS including B, H, and available = B - H. Given a fee intended for operating, When no valid written client consent exists for fee withdrawal from trust for this jurisdiction, Then the system blocks with error TRUST_FEE_CONSENT_REQUIRED and provides a one-click consent capture flow. Given a payment instruction sourcing funds from Matter A to pay for Matter B, When A != B, Then the system blocks with error TRUST_COMMINGLING_BLOCKED and logs an incident record. Given drafting, billing, or disbursement screens, When a matter is selected, Then the UI displays current trust balance, holds, and available amount and disables actions that would violate rules.
Three-Way Reconciliation Support and Export
Given a reconciliation period P and bank statement balance S, When bank transactions for P are imported/matched, Then cleared trust bank balance equals sum of cleared client sub-ledger balances within $0.01 or a discrepancy is flagged with variance. Then general ledger trust liability equals total client sub-ledger balance; if not, discrepancies list affected matters and amounts. Then one-click export produces PDF and CSV with beginning/ending balances, outstanding deposits/checks, matched/unmatched items, and preparer signature lines.
Reversing Entries for Corrections
Given an original entry E, When a Trust_Admin initiates a reversal with reason_code, Then a reversing entry R is created with amount = -E.amount, same matter_id/client_id/tags, link_id = E.id, and created_at >= E.created_at. Then the net effect on the matter balance of E and R is zero. Then E remains immutable; attempts to delete E or R are blocked and logged. Then the UI shows E and R with a clear reversal badge and link.
NSF and Chargeback Handling
Given a deposited item is returned NSF or a card chargeback occurs, When the return event is received, Then an NSF/chargeback entry posts to the same matter within 2 seconds, reducing balance and setting a hold for any pending disbursement. Then any bank-assessed return fees are posted to operating/expense, not deducted from client trust, unless jurisdiction rules and stored consent explicitly permit; such deductions are blocked otherwise. Then assigned attorney and accounting receive in-app and email alerts within 5 minutes containing matter, client, amount, and next steps.
IOLTA Interest Treatment per Jurisdiction
Given a trust account configured as IOLTA for state X, When monthly interest is credited, Then the system records an interest_credit entry and an automated remittance entry to the IOLTA payee for the same amount, leaving all client matter available balances unchanged. Then remittance frequency, payee, and reporting format follow state X rules; if configuration is missing or invalid, posting is blocked and an admin alert is raised. Then interest is excluded from client sub-ledgers and appears only in trust account-level reporting with remittance details.
Monthly Statements and Audit-Ready Views
Given the end of a calendar month, When statements are generated, Then each matter with any trust activity receives a statement including opening balance, itemized entries with IDs/type/date/amount/tags, holds, reversals, interest summary, and ending balance. Then statements are immutable, versioned, and available as PDF/CSV in the portal within 24 hours of month-end. Then an audit view for any matter renders the complete immutable ledger history with filters (date range, type, user), shows running balances, and exports include a checksum/hash for integrity verification.
Protected Disbursement Workflow
"As a managing attorney, I want guarded, policy-driven transfers from trust to operating so that unearned funds cannot be withdrawn and my firm can demonstrate compliance during audits."
Description

Enforces safeguarded transfers from trust to operating by validating that funds are earned, available, and properly authorized. Triggers sweeps on invoice finalization or scheduled cycles, requires configurable approvals (e.g., two-person), and generates compliant transfer instructions and processor payouts. Applies jurisdiction rules for settlement distributions and third-party payees, manages hold periods, prevents overdrafts, and logs a complete audit trail of requests, approvals, and outcomes. Notifies attorneys and bookkeepers of pending actions and blocks noncompliant withdrawals.

Acceptance Criteria
Auto-Sweep on Finalized Invoice from Trust to Operating
Given a matter has a trust balance and a finalized invoice with line items marked as earned and trust-billable And any deposits subject to hold are identified with clearing dates When the invoice is finalized or a finalization webhook is received Then the system computes the eligible sweep amount = min(earned trust-billable total, available trust balance excluding held funds) And generates a transfer instruction with unique ID, matter ID, invoice ID, source/destination accounts, currency, total amount, and per-line-item breakdown And creates IOLTA-ready ledger entries (debit trust, credit operating) per matter and per line item And blocks the sweep if no earned items or eligible amount = 0 with a reason code and no ledger impact And requires policy-defined approvals before submitting to the payment processor And upon approval, submits the payout and updates status to Paid within 5 minutes of processor confirmation
Two-Person Approval Requirement for Trust Disbursement
Given firm policy requires two-person approval for trust-to-operating transfers And the initiator is recorded as Requester When a disbursement request is created Then the workflow requires approvals from two distinct users permitted by policy and disallows the Requester as the sole approver And enforces an approval expiry window (e.g., 72 hours) after which the request auto-cancels And records each approver’s user ID, role, timestamp, decision, and authentication method And blocks execution until all required approvals are captured And if any approver rejects, the request is marked Rejected, no submission occurs, and the Requester is notified
State Rule Compliance for Settlement Distribution and Lien Payees
Given a settlement disbursement for a matter with jurisdiction J and configured rule set RJ And third-party payees/liens exist with claimed amounts and priorities When the distribution worksheet is generated Then the system applies RJ to compute allowable attorney fee, costs, lien paydowns, client net, and required escrow holds And prevents distributions that violate rule caps or ordering or yield negative client net, returning rule ID and reason And creates distinct ledger lines and payout instructions per third-party payee from trust and per operating receipt for fees/costs And requires client consent (e-sign) of the distribution statement before executing payouts And stores jurisdiction, rule version, and calculation snapshot in the audit record
Hold Period and Available Balance Validation
Given the trust account includes deposits with configured hold periods and clearing dates When a disbursement amount is calculated Then available amount = cleared deposits − pending disbursements − escrow/retainer holds And funds with future clearing dates are excluded from available amount And if requested amount > available amount, execution is blocked with error INSUFFICIENT_FUNDS and no ledger impact And if partial disbursement is permitted by policy, the system offers the maximum allowable partial amount and records the decision
Scheduled Cycle Sweeps and Payout Batching
Given a firm-defined sweep schedule (e.g., daily at 17:00 local time) When the schedule triggers Then the system batches all eligible finalized invoices across matters that pass availability and policy checks And applies the same approval rules; items needing additional approvals remain queued and are not executed And generates a batch summary with totals, item counts, success/failure counts, and reconciliation export files And sends notifications to designated attorneys and bookkeepers for pending approvals and post-run results And retries transient processor failures up to N attempts with exponential backoff and records outcomes per item
Complete Audit Trail and Reconciliation Export
Given any disbursement lifecycle event occurs (create, approve, reject, submit, succeed, fail, cancel) When the event is processed Then an immutable audit log entry is written with event type, UTC timestamp, actor, matter ID, invoice ID, amounts, rule checks passed/failed, approval data, processor IDs, and before/after balances And audit entries are searchable by matter, date range, status, amount, and actor, returning results within 2 seconds for up to 10,000 records And one-click reconciliation export produces CSV and GL-friendly files with ledger lines, transfer IDs, payee info, and processor settlement references And audit records and exports are retained per firm policy and are downloadable with role-based access controls
One-Click Reconciliation Exports
"As a firm bookkeeper, I want one-click exports of trust and operating transactions with accurate mappings so that I can reconcile quickly in my accounting system and close the month on time."
Description

Produces reconciliation-ready exports for trust and operating activity with matter and client tags, including CSV, QBO, and OFX formats. Supports mapping to a firm’s chart of accounts, delta exports by date or statement cycle, encryption at rest/in transit, and delivery via download, email, or webhook to accounting systems. Includes export logs, success/failure alerts, and simple remap tools when accounts change. Ensures totals align with bank and sub-ledger balances to accelerate month-end close.

Acceptance Criteria
Monthly Trust Reconciliation — CSV Export with Matter/Client Tags
Given a firm selects the Trust account and a statement cycle date range And all transactions in the period have associated matter and client tags When the user exports format = CSV Then the CSV file is generated within 5 seconds and downloads successfully And the filename matches pattern trust_YYYYMMDD_YYYYMMDD.csv And each row includes: date, txn_id, debit, credit, amount, balance_after, bank_ref, matter_id, matter_name, client_id, client_name, account_code, ledger_entry_id, memo, trust_or_operating And trust_or_operating = "trust" for all rows And period totals equal the bank statement totals to the cent And the sum by matter_id equals the trust sub-ledger totals for the period And the record count equals the number of approved transactions in the range And the CSV is UTF-8 (no BOM), comma-delimited, with RFC4180 quoting And a SHA-256 checksum is produced and logged with the export
QuickBooks Online Mapping — QBO Web Connect Export
Given the firm has completed chart-of-accounts mapping and selected a Trust or Operating bank account And QBO format is selected for the chosen date range When the user clicks Export Then a .qbo file is produced with valid OFX headers and a unique FITID per transaction And BANKID, ACCTID, and CURDEF match the mapped bank account And payee/memo fields include matter_id and client_id tags to support QBO bank rules And debits/credits are correctly signed for bank-feed import And importing the file into QBO yields the same record count with no duplicates on re-import (FITID idempotency) And the export is logged with format = QBO and the mapped account identifiers
OFX Export — Operating Account Delta by Statement Cycle
Given the Operating account is selected and "Delta since last export" is enabled And the last successful export end timestamp is known When the user exports OFX for a statement cycle with range [start, end] Then only transactions with posted_at > last_end and posted_at <= end are included And each transaction contains a stable, unique FITID across re-exports And BANKID, ACCTID, and CURDEF match the mapped operating bank And the record count equals the number of new approved transactions in the delta And re-exporting the same range produces zero additional records (idempotent) And the OFX validates against schema with no errors
Secure Delivery — Download, Email, and Webhook
Given the user has export permissions When the user chooses Download delivery Then the file is served over TLS 1.2+ via an authenticated session and a pre-signed URL that expires within 15 minutes When the user chooses Email delivery Then the recipient receives a time-limited link (expires within 72 hours) requiring a one-time code; no raw file is attached When a Webhook delivery is configured Then the system POSTs a JSON payload with export metadata and a signed URL; the request includes an HMAC-SHA256 signature header; retries use exponential backoff for up to 24 hours on 5xx And all export files are encrypted at rest with AES-256 and stored with server-side encryption enabled
Export Logs and Alerts — Auditability
Given an export is initiated by a user or automation When the export completes successfully Then a log entry records export_id, initiator_user_id, role, timestamp UTC, format, account type, filters (date range or statement cycle), record_count, checksum, delivery channels, and destinations (redacted where applicable) And a success alert is sent to the initiator via in-app and email within 60 seconds including export_id and link When the export fails Then a log entry records error_code, error_message, and trace reference, and a failure alert is sent within 60 seconds And logs are retrievable in the UI with filters by date range, status, format, and account type and are downloadable as CSV
Account Remap and Backfill — Seamless Continuity
Given the firm updates its chart-of-accounts mapping When a new export is generated after the change Then the export reflects the new mapping for all transactions in the selected period without modifying prior exports And the system provides a remap tool to regenerate prior periods using the new mapping and marks originals as superseded with a superseded_by reference And the remap preview shows old→new account mappings, record counts, and confirms net-zero impact on balances before execution And re-generated exports preserve original transaction IDs/FITIDs to maintain downstream idempotency
Balance Validation Gate — Prevent Mismatched Totals
Given a date range or statement cycle is selected for export When the user initiates the export Then the system verifies that beginning balance + net activity = ending balance for the bank and for the ledger And the sum of trust sub-ledgers by matter equals the trust control account balance for the same period And if any variance exceeds $0.01 the export is blocked, a discrepancy report is displayed (variance by matter and bank vs ledger), and no file is produced And after discrepancies are resolved, re-validation passes and the export proceeds; the validation outcome is recorded in the export log

Tap Terminal

Turn any modern phone into a tap‑to‑pay point of sale inside intake—no extra hardware. Collect retainers via Apple/Google Pay contactless in court hallways, clinics, or curbside, auto‑attach payments to the matter, issue branded receipts, and trigger the retainer e‑sign flow on the spot to close faster.

Requirements

Tap-to-Pay SoftPOS Enablement
"As a solo attorney, I want to accept contactless payments on my phone without extra hardware so that I can collect retainers anywhere immediately."
Description

Implements contactless in-person payments on modern iOS and Android devices using Apple Tap to Pay on iPhone and Android SoftPOS partners, requiring no external hardware. Supports NFC wallets (Apple Pay, Google Pay) and contactless cards, with on-device PIN entry where cardholder verification is required. Performs device capability checks, region and currency eligibility validation, and real-time authorization via supported payment processors. Ensures minimal setup for attorneys, secure tokenization, and immediate confirmation within the intake experience, enabling hallway, clinic, or curbside collections.

Acceptance Criteria
Device Capability & Eligibility Gate
Given an authenticated attorney is on the Intake Payment step on a mobile device, When runtime checks evaluate NFC presence, OS version, and provider support (Apple Tap to Pay on iPhone or Android SoftPOS), Then the Tap-to-Pay action is enabled only if all are supported. Given firm merchant configuration is loaded, When region and currency are validated against the payment processor and platform eligibility, Then ineligible combinations disable Tap-to-Pay and display an actionable message with a help link. Given all checks pass, When the screen is displayed, Then a readiness state is shown and an analytics event TapReady is logged with device model, platform, region, and currency (no PII).
Contactless Tap Flow – Wallets & Cards
Given Tap-to-Pay is enabled and the attorney starts a payment, When a customer presents a supported NFC wallet (Apple Pay/Google Pay) or contactless EMV card within 3 cm, Then the device detects the tap within 1 second and advances to processing. Given an unsupported instrument (non-NFC or damaged card), When presented, Then the app displays Tap not detected with guidance and allows up to 2 retries before cancelling. Given a supported scheme (Visa, Mastercard, Amex, Discover) and amount within configured limits, When tapped, Then a tokenized payment method is created without exposing PAN to the app.
On-Device PIN Entry (CVM)
Given the tapped card requires cardholder verification, When CVM=PIN is requested by the network, Then the OS-native secure PIN entry is presented and Briefly never receives PIN keystrokes or values. Given PIN entry is active, When the user enters an incorrect PIN 3 times or cancels, Then the transaction is declined with an appropriate CVM/DECLINE reason code and the flow returns to retry/cancel. Given CVM succeeds, When PIN is verified, Then authorization proceeds without additional input and an event CVM_Success is logged (no PIN or PAN).
Real-Time Authorization & Confirmation
Given a tokenized payment method is available, When the app submits authorization to the configured processor, Then the p95 end-to-end response time is ≤ 5 seconds and p99 is ≤ 10 seconds under nominal network conditions (≥ 3G). Given authorization succeeds, When the response returns, Then the intake view shows Success with amount, brand, last4, auth code, and timestamp, and the Continue button is enabled. Given authorization fails, When a decline or error is returned, Then the app shows the decline reason/code, logs PaymentDeclined, and offers a single retry; subsequent failures require starting a new attempt.
Auto-Attach Payment to Matter & Receipt
Given a successful authorization, When the result is received, Then a Payment record is created and linked to the active matter/intake ID with fields: amount, currency, processor charge ID, auth code, brand, last4, CVM result, wallet type, merchant account ID, and createdAt. Given the Payment record is persisted, When confirmation is shown, Then a branded receipt is issued via the client’s selected channel (email/SMS) within 10 seconds and a copy is accessible from the matter timeline. Given receipt delivery is queued, When confirmation is acknowledged, Then the retainer e-sign flow launches automatically within 2 seconds, pre-filled with payer details and payment reference.
Attorney Provisioning & Minimal Setup
Given a firm admin opens Settings > Tap Terminal for the first time, When enabling Tap-to-Pay, Then the guided provisioning collects required business and processor details and completes in ≤ 3 minutes without external hardware steps. Given provisioning completes, When any attorney in the firm signs in on a compatible device, Then Tap-to-Pay is available without additional device pairing and shows the readiness state. Given a non-admin user opens Settings, When attempting to modify Tap Terminal configuration, Then access is blocked and an Admin required notice is shown with no configuration changes applied.
Security, Tokenization, and Audit
Given any tap transaction, When data is handled by the app, Then PAN, PIN, and CVV are never stored, logged, or transmitted by Briefly; only network tokens and the last4/brand are retained from the processor response. Given a transaction completes (success or decline), When events are logged, Then audit logs include actor, device ID, platform, eligibility outcome, amount, currency, processor IDs, auth/decline code, and timestamps, excluding sensitive cardholder data. Given periodic compliance review, When running the security test suite, Then transport is TLS 1.2+ and device attestation/provider SDK integrity checks pass; any failure blocks Tap-to-Pay and raises a security alert.
Intake-Embedded Checkout
"As an intake paralegal, I want a checkout step embedded in the questionnaire so that payment happens naturally during intake with minimal context switching."
Description

Adds a guided checkout step directly inside the mobile intake flow that pre-fills the retainer amount from fee schedules, allows adjustments (if permitted), and clearly displays line items, fees, and terms. Presents a single-tap confirmation optimized for small screens, captures client consent, and returns the user seamlessly to the next intake step after authorization. Supports matter selection or creation in-context, and records payment context (who, when, device) for downstream automation.

Acceptance Criteria
Prefilled Retainer From Fee Schedule
Given a matter type with a configured fee schedule and an active mobile intake session When the checkout step loads Then the retainer amount auto-populates from the schedule for the selected matter type and jurisdiction And the amount input is read-only if adjustments are not permitted by role/permissions And if adjustments are permitted, edits are constrained to the configured min/max bounds; out-of-bounds values show inline validation and disable confirmation And totals recalculate in real time to reflect line items, taxes, discounts, and processing fees And each line item displays description, quantity, unit price, and extended amount And currency formatting matches the matter currency with two-decimal rounding
Single-Tap Mobile Confirmation
Given a mobile device with viewport width ≤ 414 px and a valid payment summary When the user has satisfied all required inputs Then a single primary CTA labeled "Pay and Continue" is visible without scrolling, enabled, and has a minimum hit area of 44×44 px And the CTA meets WCAG 2.2 AA focus visibility and is reachable via keyboard/accessibility focus When the CTA is tapped Then the native Apple Pay or Google Pay sheet opens within 2 seconds And no secondary confirmation is required beyond the wallet sheet
Explicit Consent Capture and Audit
Given the checkout step is displayed Then a mandatory consent control referencing the current Terms and Fee Disclosure is visible and unchecked by default And the "Pay and Continue" CTA remains disabled until the consent control is checked When the user checks the consent control and proceeds Then the system records a consent event with: client (or intake link) id, user id (if applicable), matter id (if available), timestamp (ISO 8601 UTC), IP address, device platform, app version/build, locale, and terms version And the consent event is attached to the matter timeline and retrievable via API within 5 seconds
Seamless Return to Next Intake Step
Given payment authorization succeeds in the wallet sheet When the authorization callback is received Then the user is advanced to the next intake step in the same session within 1 second And the checkout step is marked complete on the intake progress indicator And the authorized payment id is stored on the intake session Given authorization is declined or cancelled Then the user returns to the checkout step with a user-friendly error message, preserved inputs, and options to retry or choose a different method And no duplicate charges are created; exactly one authorization attempt is recorded per try And each failure is logged with a trace id available to support
In-Context Matter Selection or Creation
Given the client has no open matters for the current intake When the checkout step loads Then a create-matter prompt appears prefilled with intake data (client, matter type, jurisdiction) And upon confirmation a new matter id is created and set as the selected matter Given the client has existing open matters Then a selector lists them (type, status, last updated) with the intake-associated matter preselected When the user changes the selection Then the subsequent payment attaches to the selected matter And duplicate creation is prevented for identical client + matter type + intake id combinations
Payment Context Recording and Exposure
Given a payment is authorized When the authorization response is received Then the system stores payment context: payer name, payer contact (email/phone), client id, matter id, initiating user id (if any), timestamp (ISO 8601 UTC), wallet type (Apple Pay/Google Pay), card/network brand, country, device platform and model (if available), masked last4 (PAN or token), authorization id, and fee/tax breakdown And the context is visible in the matter ledger and retrievable via API endpoint /payments/{id} And a webhook event payment.authorized is emitted within 5 seconds including the same context payload And stored data excludes full PAN, CVV, and unmasked tokens to maintain compliance
Matter Linking & Trust Accounting
"As a firm owner, I want payments auto-linked to the matter and deposited correctly into trust and operating accounts so that I stay compliant and save reconciliation time."
Description

Automatically associates each payment with the correct matter and client, creates immutable ledger entries, and supports legal trust accounting. Enables split settlement so retainer funds settle to IOLTA/trust while processing fees debit the operating account, never the trust. Handles partial payments, payment plans, and refunds with compliant reversals. Provides exports and webhooks for accounting systems and a reconciliation view filtered by matter, attorney, and account.

Acceptance Criteria
Auto-Link Payment to Matter During Tap Collection
- Given a tap-to-pay is initiated from a specific matter context, when the transaction is approved, then the payment is automatically linked to the correct Matter ID and Client ID and visible in the matter timeline within 5 seconds. - Given a tap-to-pay is initiated without an active matter context, when the user attempts to charge, then the UI requires matter selection and prevents processing until selected. - Given a duplicate submit within 2 minutes with the same device_id, idempotency_key, matter_id, and amount, when the processor returns the same authorization, then only one ledgered payment is created and linked. - Then the issued receipt displays Matter ID, Client name, payment amount, and a link to the retainer e-sign flow.
Immutable Ledger Entries and Audit Trail
- Given any financial event (authorize, capture, settlement, fee, refund, reversal, chargeback, adjustment), when it occurs, then an append-only ledger entry is created with fields: entry_id (UUID), matter_id, client_id, account_type, amount, currency, direction, event_type, processor_txn_id, device_id, created_at (UTC ISO8601), created_by, hash. - Given a user attempts to edit or delete a ledger entry, when the action is submitted, then the system rejects it and logs an audit event requiring a reversal entry to correct errors. - Then summing all ledger entries by account_type produces a non-negative trust balance and matches processor settlement totals for the selected period within ±$0.01.
Trust-Compliant Split Settlement (IOLTA vs Operating Fees)
- Given a $100 retainer payment with a $3.20 fee, when the transaction settles, then $100 posts to the trust account and $3.20 is debited from the operating account; trust balance remains +$100. - Given processor default is fee-netting, when fee funding is configured, then fees are charged to operating and not netted from trust; otherwise the payment is blocked and the user is shown a configuration error. - Given 50 successive payments of varying amounts, when settlements complete, then no trust ledger entry reflects fee debits and operating shows all fee debits with matching processor reports. - Given a payment is declined or reversed before settlement, then no trust or operating entries are posted.
Partial Retainer Payments and Outstanding Balance Tracking
- Given a matter with a $1,500 retainer target, when a $500 tap payment posts, then the matter shows outstanding balance $1,000 and the receipt states "Partial payment" with remaining balance. - Given multiple partial payments, when the sum reaches the target, then the matter status updates to "Retained" and the retainer e-sign flow is triggered if not yet completed. - Given an overpayment attempt that exceeds the remaining balance by more than configured tolerance ($0.01 default), when the user submits, then the system blocks the charge or caps it to the remaining balance based on admin setting. - Then each partial payment creates separate ledger entries to trust and never applies fees to trust.
Payment Plans with Automated Collection and Controls
- Given a plan is created with 6 installments of $250 starting next month, when the start date arrives, then the system auto-charges the saved payment token, posts $250 to trust, debits the fee from operating, and sends a receipt within 1 minute. - Given an installment fails, when retries occur, then the system retries up to 3 times with exponential backoff (1h, 24h, 72h), notifies client and attorney, and marks the installment "Failed" after retries exhaust. - Given a plan is paused by the attorney, when paused, then no charges are attempted and the schedule resumes from the next unpaid installment on resume. - Then plan creation, pause/resume, and cancellation actions are logged in the audit trail, and all successful installments reduce outstanding balance accordingly.
Refunds and Chargebacks with Trust-Safe Reversals
- Given a client refund of $200 on a trust-funded payment, when processed, then $200 is withdrawn from trust to the client, fees are not debited from trust, and any processor fee refund is credited to operating. - Given a partial refund, when submitted, then remaining trust balance and outstanding amounts update correctly, and receipts show the refunded amount and remaining paid total. - Given a refund would cause a negative trust balance, when attempted, then the system blocks it and displays "Insufficient trust balance." - Given a chargeback is received, when webhook is delivered, then a reversal ledger entry removes principal from trust, fee impact is recorded in operating, and the matter is flagged for review.
Accounting Exports, Webhooks, and Reconciliation Filters
- Given a date range and filters (matter, attorney, account_type), when export is requested, then a CSV is generated within 30 seconds containing columns: entry_id, date, matter_id, client_id, attorney_id, account_type, event_type, amount, currency, direction, running_balance, processor_txn_id, note, and a SHA-256 file checksum. - Given webhook destinations are configured, when events occur (payment_authorized, captured, settled, fee_debited, refund_issued, chargeback_received, plan_failed), then signed (HMAC-SHA256) webhooks are delivered with idempotency keys and retried up to 10 times with exponential backoff on 5xx/timeout. - Given the reconciliation view is loaded with filters and a 50k-entry dataset, when the user paginates or adjusts filters, then results render in under 2 seconds and totals match the export for the same filters. - Then all payloads contain matter_id and account_type, exclude full PAN/PII, and include last4 and network token reference only.
Branded Digital Receipts
"As a client, I want an instant, branded receipt sent to my phone so that I have proof of payment and my records are clear."
Description

Generates and sends firm-branded receipts instantly via SMS and email, including payer name, last-4, wallet indicator, amount, matter ID, trust/operating allocation, fees, and timestamp. Stores a PDF copy in the matter’s document set and allows staff to resend or download. Supports localized formatting, tax/fee disclosures by jurisdiction, and a scannable receipt code for quick verification in court or clinics.

Acceptance Criteria
Instant Receipt Issuance After Tap-to-Pay
Given a payment is successfully captured via Tap Terminal for an existing matter When the gateway returns a capture confirmation Then a firm-branded digital receipt is generated within 5 seconds and assigned a unique receipt ID And the receipt includes: firm logo and legal name, payer full name, masked PAN (last-4 only), wallet indicator (Apple Pay or Google Pay), total amount and currency, matter ID, trust and operating allocations (amounts and percentages if applicable), itemized taxes/fees, and an ISO 8601 timestamp with timezone And the subtotal + taxes/fees equals the total amount, with currency rounded to the smallest unit And no PAN beyond last-4, CVV, or full email/phone is displayed on the receipt body or PDF
Dual-Channel Delivery via SMS and Email
Given the payer’s mobile number and email address are on file When the receipt is generated Then an SMS containing a secure receipt link is queued within 5 seconds And an email containing the secure link and a PDF attachment is queued within 10 seconds And delivery events (queued, sent, delivered, failed/bounced) for both channels are recorded on the matter timeline And the SMS contains no PII beyond firm name, amount, and last-4; the email subject includes firm name and receipt ID And if one channel fails, the other still sends and the failure is logged with a retry recommendation
Matter Storage and Resend/Download Controls
Given a receipt has been generated for a matter When the PDF is created Then it is saved to the matter’s document set within 10 seconds using the filename pattern Receipt_<receiptID>_<matterID>.pdf And the stored PDF is read-only and immutable (content checksum recorded) And authorized staff can resend the receipt via SMS and/or email from the matter with selectable channels And authorized staff can download the exact stored PDF; unauthorized users are denied access And all resend/download actions are audit-logged with user, timestamp, channels, and receipt ID
Localization and Jurisdictional Disclosures
Given the matter’s jurisdiction and the payer’s locale are set When generating the receipt Then currency symbol, decimal/thousand separators, and date/time format match the payer locale And jurisdiction-specific tax/fee disclosures (e.g., trust accounting notices, surcharge disclosures, local tax labels) are included per configuration for that jurisdiction And the receipt uses the correct currency for the jurisdiction (e.g., USD, CAD) with accurate tax calculations and labels And if a required disclosure template is missing for the jurisdiction, generation is halted and a clear error is shown to staff; no receipt is sent until resolved
Trust vs Operating Allocation Accuracy
Given a payment includes allocations to trust and operating accounts When the receipt is generated Then both allocations are displayed with amounts and percentages And the sum of trust and operating allocations equals the gross payment amount And rounding uses the largest remainder method to the smallest currency unit, assigning any remainder to the larger allocation to maintain total integrity And if no allocation is provided, the receipt explicitly indicates the default allocation state per firm settings
Scannable Receipt Code Verification in Court
Given a receipt displays a scannable QR code When the code is scanned on a standard mobile device Then a public verification page opens and loads in under 2 seconds on a 4G connection And the page shows status (Valid, Refunded, or Voided), firm name, amount and currency, last-4, wallet indicator, receipt ID, matter ID, and timestamp And the code is backed by a signed, tamper-evident token; altered tokens render an Invalid status and reveal no PII beyond last-4 And the verification event is logged to the matter with timestamp and device IP/country; the page is mobile-friendly and readable from both on-screen and 200 DPI printed codes
Instant Retainer E-Sign Trigger
"As an attorney, I want payment to automatically trigger the retainer for e-sign on the spot so that I can close the engagement before the client walks away."
Description

On successful authorization, auto-assembles the retainer using Briefly’s document automation, pre-fills verified intake data, and launches the e-sign ceremony on the same device. Supports single or multi-signer flows, attorney countersignature rules, and fallback to send-by-link if the client cannot sign immediately. Records signatures to the matter, timestamps the engagement, and updates status to "Retained" to accelerate time-to-engagement.

Acceptance Criteria
Immediate e-sign after contactless retainer authorization (single signer)
- Given a Tap Terminal payment authorization returns Approved for a new matter with verified intake data - When the authorization callback is received with a unique idempotency key and payer metadata - Then Briefly assembles the correct retainer template for the matter type and merges all required intake fields with 0 missing required fields - And the assembly completes within 5 seconds and produces a single PDF with signature anchors - And the e-sign ceremony opens automatically on the same device within 2 seconds, addressed to the client’s legal name - And the client can review and complete all required fields and signatures without manual data re-entry - And only one e-sign ceremony is launched per unique authorization id; duplicates are ignored
Multi-signer retainer flow with remote co-signer routing
- Given the selected retainer template requires multiple client-side signers - When the first signer completes their portion on-device - Then the system prompts for additional signer contact info (name + SMS or email) and required relationship - And sends secure signing links to remaining signers immediately - And preserves signing order and required fields per template configuration - And the matter remains in “Pending Client Signatures” until all client-side signatures are complete - And progress is visible in the matter timeline with per-signer status and timestamps
Attorney countersignature rules enforcement and sequencing
- Given the retainer template requires an attorney countersignature - When all required client-side signatures are completed - Then the countersign task is created and assigned per configured routing rules (e.g., assigned attorney or on-duty pool) - And if the assigned attorney is authenticated on the same device, the countersign ceremony can be completed immediately; otherwise it appears in their signature queue within 5 seconds - And the matter status shows “Pending Countersignature” until the attorney signs - And upon countersign, the engagement timestamp is set to the countersign time and status updates to “Retained”
Fallback to send-by-link when client cannot sign immediately
- Given the client declines, times out (no interaction for 120 seconds), or the device/browser cannot render the e-sign ceremony - When the user selects “Send Signing Link” - Then Briefly sends a secure, expiring link (valid 7 days) via the chosen channel (SMS or email) to the client - And the link requires sender-verified contact and a one-time code to open - And the partially assembled retainer is preserved; the client resumes at the start of signing - And the matter status updates to “Signature Out for Client” and is removed from in-person signing mode - And when the client completes signing via the link, the workflow continues as if signed in-person
Signature recording, audit trail, and matter status update
- Given all required signatures (client-side and countersignature if applicable) are completed - When the final document is sealed - Then Briefly stores the signed PDF, certificate of completion, signer IP/device metadata, and hash checksum in the matter documents - And writes an immutable audit log entries for each signature with UTC timestamps - And sets the engagement timestamp to the time the last required signature was applied - And updates the matter status to “Retained” - And links the payment authorization/transaction ID to the signed retainer record
Resilience, idempotency, and retry on assembly/e-sign failures
- Given payment authorization succeeds but document assembly or e-sign service temporarily fails - When an error is returned or a 60-second timeout elapses - Then the system surfaces a clear, actionable message and records the failure in the matter timeline - And automatically retries up to 3 times with exponential backoff without re-charging the card - And uses the authorization idempotency key to prevent duplicate retainers or duplicate ceremonies - And provides a manual “Retry Now” and “Send Signing Link” option - And if unrecoverable, the matter status sets to “E-Sign Setup Failed” and alerts the user
E‑consent capture and identity binding for mobile e‑sign
- Given a signer initiates the e-sign ceremony on a mobile device - When the ceremony begins - Then the signer is presented with and must accept e-consent (ESIGN/UETA) before accessing the document - And the consent record (text version, acceptance, timestamp, IP/device) is stored with the matter - And the signer’s displayed legal name and contact channel match the verified intake profile or payer metadata - And each signature record binds to the signer’s verified contact via a one-time code challenge when sent-by-link flows are used
Resilient Fallbacks & Connectivity
"As a field intake staffer, I want reliable fallbacks when NFC or connectivity fails so that I can still collect payment and complete intake."
Description

Detects device or NFC ineligibility and dynamically offers a QR code or link to a secure hosted checkout supporting Apple/Google Pay and card entry. Monitors connectivity strength and provides clear guidance; never stores PAN data locally and does not attempt offline card capture. Queues non-sensitive downstream actions (receipt delivery, document generation) for retry if the network drops after authorization. Includes a visible payment status tracker and admin overrides with audit notes.

Acceptance Criteria
NFC Ineligible Device Fallback to Hosted Checkout
Given the device lacks NFC support, incompatible OS, or NFC permission is denied When the user taps “Collect Payment” in intake Then the app detects ineligibility within 500 ms And shows a QR code and shareable link to a PCI-hosted checkout And the hosted checkout supports Apple Pay, Google Pay (when available), and manual card entry And no card entry fields render inside the app And the fallback UI remains available until eligibility changes or checkout completes
Connectivity Monitoring and User Guidance
Given the app is open on the payment screen When network connectivity changes Then a connectivity indicator updates to Good/Weak/Offline within 1 second And when Weak, the app displays guidance to move for better signal and recommends QR/link fallback And when Offline, the app disables tap-to-pay and in-app capture initiation and displays guidance to regain connectivity; no card data entry is allowed And the user can retry a connectivity check on demand
Post-Authorization Network Drop and Retry Queue
Given a payment authorization succeeds When the device loses connectivity before sending downstream actions Then the app enqueues non-sensitive tasks (receipt dispatch, document generation, matter attachment) with unique IDs And stores no PAN, CVV, or track data in the queue And retries automatically with exponential backoff until success or a 24-hour timeout And upon reconnect, successful tasks update the payment record and UI status And if retries exhaust, the user sees a clear alert and can trigger manual retry
Visible Payment Status Tracker
Given a payment attempt exists for a matter When the user views the payment screen Then a tracker displays steps: Initiated, Authorized, Captured, Receipted, Documents Generated, Attached to Matter And each step shows a timestamp on completion or “Pending” otherwise And the tracker updates within 2 seconds of receiving a webhook or successful retry And users can expand a step to see event details and error messages And hosted checkout and tap-to-pay events are both reflected consistently
Admin Override with Audit Notes
Given a user with Admin role is viewing a payment with pending/failed downstream tasks When the admin applies an override (e.g., mark Receipted done, cancel a task, reattach payment) Then a required audit note (minimum 15 characters) must be entered And the system records user ID, timestamp, original and new state, and reason And the audit note is immutable after save and visible in the audit log And non-admin users cannot access override actions
Payment Association and Reconciliation from Hosted Checkout
Given a payer completes payment via hosted checkout (QR/link) When the payment provider sends a confirmation webhook Then the payment auto-attaches to the originating matter using the checkout session ID And if the initiating device was offline, the attachment syncs on next reconnect And idempotency keys prevent duplicate attachments and duplicate receipts And receipts are delivered to the client and firm per notification settings And failures follow the retry policy until success or timeout
No Local PAN Storage and No Offline Card Capture
Given any payment flow is initiated from the app When collecting payment Then the app renders no local fields for PAN, CVV, or expiry and never stores or logs PAN, track data, or CVV And all card entry occurs only in PSP-hosted forms or wallets (Apple/Google Pay) And if the device is Offline, the app refuses tap or in-app capture initiation and instructs the user to regain connectivity And security tests verify zero PAN in device storage, logs, and analytics payloads
Compliance, Security & Audit Trail
"As a compliance officer, I want the tap-to-pay flow to meet PCI/EMV and IOLTA rules with full audit trails so that we minimize risk and pass audits."
Description

Meets PCI DSS scope via approved SoftPOS/payment partners, avoids PAN storage, and uses end-to-end encryption for contactless transactions. Ensures EMV contactless compliance, Apple/Google program adherence, and on-device PIN security. Enforces jurisdictional rules for surcharging/convenience fees and ensures IOLTA compliance (fees never deducted from trust). Captures complete audit logs (user, device ID, location/time, matter, amount, outcome) with tamper-evident storage and data retention controls.

Acceptance Criteria
PCI Scope via Approved SoftPOS with No PAN Storage and E2EE
Given Briefly Tap Terminal is configured with an approved SoftPOS/payment partner And the production build has debug logging disabled When a contactless transaction is initiated and completed Then all cardholder data capture and encryption occur within the partner SDK using end-to-end encryption And the Briefly app process memory, logs, and persistent storage contain no PAN, track data, or CVV at any time And a forensic scan of device storage and network captures confirms no plaintext PAN data And a current partner attestation/certification (e.g., PCI MPoC/CPoC/SPoC) is on file and linked in the compliance record
EMV Contactless Transaction Compliance
Given a test suite of EMV contactless cards/brands (Visa, Mastercard, Amex, Discover) and simulated fallback scenarios When transactions are attempted with and without network connectivity Then EMV L3-validated kernels from the partner are used for processing And offline approvals are not permitted; if connectivity is unavailable, the transaction is declined with a clear message And the app never offers manual PAN entry as a fallback And EMV outcome codes and transaction references are returned and stored (excluding PAN/track/CVV)
Apple/Google Program Adherence and Device Integrity
Given supported iOS and Android devices When initiating Tap to Pay Then on iOS, Apple Tap to Pay on iPhone APIs are used exclusively and device attestation passes And on Android, Play Integrity/SafetyNet attestation passes and Google Tap to Pay program rules are enforced And if the device is jailbroken/rooted, lacks secure NFC, or fails attestation, the payment flow is blocked and the event is logged And screen recording and screenshots are disabled during sensitive payment steps
On-Device PIN Entry Security
Given a transaction above the CVM limit or with issuer-mandated PIN When the payer is prompted to enter a PIN Then a secure PIN-on-glass component from the payment partner is displayed And the Briefly app never receives or stores the PIN value And after three failed PIN attempts the transaction is terminated and the failure is logged And screenshots/screen recording are blocked during PIN entry
Jurisdictional Surcharging and Convenience Fee Enforcement
Given the merchant’s jurisdiction, card type (credit vs debit/prepaid), and card brand rules When the merchant configures or applies a surcharge or convenience fee Then surcharges are automatically blocked where prohibited and for debit/prepaid cards in all jurisdictions And where allowed, caps and disclosure rules are enforced (e.g., max 3% or actual cost, whichever is lower) And the exact fee amount is displayed to the payer with explicit consent captured before tap And the applied fee, rule basis, and consent are recorded in the audit log And a configuration check verifies fee tables are current to the latest brand/state rules
IOLTA Trust Accounting Compliance
Given a retainer payment designated to a trust account When the transaction settles Then processor settings ensure all processing fees are deducted from the operating account and the trust deposit equals the gross amount And settlement reports reconcile net-to-trust = gross and fees = operating for the batch And if split settlement for trust compliance is unavailable, the system blocks trust designation and informs the user And refunds/chargebacks do not cause fees to be taken from trust; any exceptions are blocked and logged
Tamper-Evident Audit Trail and Retention Controls
Given any payment event (initiation, approval, decline, cancel, refund) When the event is recorded Then the audit log captures: user ID, device ID, device attestation result, OS/app version, geolocation (if consented), UTC timestamp, matter ID, amount, surcharge/fee details, payment method token descriptor, processor reference IDs, and outcome And each entry is immutably stored using a hash chain or WORM mechanism with a per-entry HMAC/signature And any modification attempt fails integrity verification and raises an alert And retention is configurable with a default of 7 years; purge actions create a signed tombstone record; export is available in CSV/JSON with integrity proof

Installment AutoPay

Offer compliant payment plans at intake without extra tools. Set installments or trust top‑ups with dates and caps, capture a single authorization, and let Briefly auto‑collect via card or bank. Smart reminders, automatic retries, and a live plan dashboard cut staff follow‑up while keeping matters funded.

Requirements

Unified Plan Builder
"As a solo attorney, I want to configure a compliant payment plan during intake so that I can enroll clients without switching tools or re-entering data."
Description

Provide an intake-embedded plan configuration experience that lets attorneys define fixed installments or trust top-ups with start date, frequency, number of payments, and end conditions. Support caps, minimum trust balance triggers, and per-matter or template-based defaults by practice area. Validate amounts, dates, and jurisdictional constraints (e.g., no surcharges on trust in certain states), with timezone and banking holiday awareness. Present a clear client-facing summary of total obligation, schedule, and maximum authorization cap before e-sign. Store reusable plan templates and expose equivalent APIs so plans can be created programmatically from intake responses. Ensure mobile-first UI, accessibility, and guardrails to prevent over-authorization beyond configured caps.

Acceptance Criteria
Fixed Installment Plan Configuration and Calculation
Given an attorney selects Fixed Installments during intake, When they enter total amount, start date (>= today), frequency (weekly/biweekly/monthly), and number of payments OR end date, Then the system validates inputs, requires exactly one of number of payments or end date, computes installment amounts, adjusts the final installment for rounding to the nearest cent, and displays a schedule preview. Given the schedule is computed, When the user saves the plan, Then the sum of all installments equals the total amount and the plan is stored with the selected timezone.
Trust Top-Up Plan with Threshold Trigger and Caps
Given an attorney selects Trust Top-Up, When they set minimum trust balance trigger, top-up amount, evaluation frequency, start date, end condition (date or matter closed), and per-charge and monthly caps, Then the system validates all values are positive, start date >= today, caps are present, and enables Save. Given a top-up plan with a balance trigger, When the trust balance drops below the threshold, Then the next evaluation initiates a charge for the lesser of the top-up amount and the remaining authorization under the configured caps and the maximum authorization cap, and no single charge or aggregate monthly charges exceed any cap.
Jurisdictional Compliance: Trust Surcharge Prohibition
Given the matter jurisdiction prohibits surcharges on trust accounts, When configuring any plan that charges a trust account, Then the system disallows adding processing fees/surcharges and sets surcharge = $0 with an explanatory message. Given the jurisdiction allows surcharges only on operating account payments, When the plan charges an operating account, Then surcharges may be applied; When the same plan charges a trust account, Then surcharges are not applied.
Timezone and Banking Holiday Scheduling Adjustments
Given the firm timezone and payment method are selected, When a scheduled charge date falls on a weekend or banking holiday in that timezone for ACH payments, Then the system moves the charge to the next business day and updates the schedule preview accordingly. Given daylight saving time transitions, When a charge is scheduled on the transition date, Then the stored execution timestamp is in UTC and maps to the intended local date without skipping or duplicating occurrences. Given a client with a different timezone views the schedule, When the summary is rendered, Then dates/times display in the client’s local timezone with the timezone label.
Client-Facing Summary and Authorization Prior to E‑Sign
Given a plan is configured, When the client reaches e-sign, Then the summary displays total obligation, schedule (dates and amounts), payment method, and the maximum authorization cap in a single view. Given the summary is displayed, When the client attempts to sign without affirming the authorization, Then the system blocks signing and requires explicit consent via checkbox or equivalent. Given the configured cap, When any computed installment or potential top-up would exceed the cap, Then the system requires the attorney to lower amounts or raise the cap before the plan can be finalized; the signed authorization cap stored must be greater than or equal to the maximum possible single charge.
Plan Templates, Practice-Area Defaults, and API Parity
Given an attorney saves the current configuration as a template with a name and associated practice area(s), When saved, Then the template appears in the template library with a unique ID and version and can be set as the default for those practice areas. Given a new matter created for a practice area with a default template, When the plan builder opens, Then fields are prepopulated from the default template and can be overridden before save; changing a template does not retroactively modify existing matter plans. Given an external system calls the Plans API with intake responses and an optional template ID, When the payload passes validation, Then the API creates the plan with the same validation rules and schedule calculation as the UI and returns 201 with the plan ID and schedule; invalid payloads return 422 with field-specific errors.
Mobile-First UI and Accessibility Compliance
Given a mobile device with viewport width 320–375px, When using the plan builder, Then all inputs, summaries, and controls render without horizontal scrolling, tap targets are at least 44x44px, and form completion is possible end-to-end. Given keyboard-only navigation, When tabbing through the plan builder, Then focus order is logical, visible, and all actions are operable without a mouse. Given a screen reader user, When interacting with the plan builder, Then all labels, help text, errors, and summary content are announced correctly with appropriate roles and associations, and color contrast meets WCAG 2.1 AA.
Single Authorization & Payment Method Vaulting
"As a client, I want to authorize my full payment plan once during intake so that future charges happen automatically without repeated signatures."
Description

Capture a single digital authorization at intake that binds the full schedule, maximum cap, change terms, and cancellation policy, and attach it to the signed retainer. Render dynamic, jurisdiction-aware authorization language compliant with card network rules, Reg E, NACHA, and the E‑Sign Act. Tokenize card and bank details via the processor to maintain PCI DSS SAQ A scope and store mandate/reference IDs for ACH. Support instant bank verification where available and fall back to micro-deposit verification when required. Persist the authorization artifact and method token for future charges, with secure rotation and card-expiry handling reminders.

Acceptance Criteria
Single Signature Binds Full Installment Schedule and Cap
Given a client completes intake with a configured installment plan, schedule dates, a maximum cap, and any trust top-up rules When the client signs the authorization once at checkout Then the authorization is recorded as binding for all scheduled installments and eligible top-ups up to the cap without requiring additional signatures And the authorization captures signer name, UTC timestamp, IP address, device/browser fingerprint, and affirmative consent And the authorization ID is linked to the matter and associated with each subsequent charge event
Jurisdiction-Aware Authorization Language and Retainer Attachment
Given the client jurisdiction and selected payment method (card or bank) When the authorization language is rendered Then the text dynamically includes schedule, amount or calculation method, maximum cap, change terms, and cancellation policy And the variant is selected per jurisdiction and method mapping and includes required card network recurring disclosures and Reg E/NACHA elements And upon signature, the authorization is attached to the executed retainer as an appendix with a language version ID and a copy is delivered to the client by email
Processor Tokenization and SAQ A Scope
Given the client enters card or bank details When payment data is collected Then collection fields are hosted by the payment processor so raw PAN or full account/routing numbers never transit or persist on Briefly servers, logs, or telemetry And the processor returns a customer identifier and payment method token And Briefly stores only token, last4, brand/type, expiration (for cards), and non-sensitive fingerprint metadata
ACH Mandate Capture and Reference IDs
Given the client selects bank debit (ACH) When the authorization is completed Then the system records the SEC code (WEB/PPD/CCD), company ID, authorization text, revocation instructions, and the mandate/reference IDs returned by the processor And an email receipt containing the authorization terms and reference ID is sent to the client immediately And mandate data is viewable in the dashboard and exportable for dispute response
Bank Verification with Instant and Micro-Deposit Fallback
Given instant bank verification is available When the client connects their bank Then the account is verified immediately and marked active for the authorization Given instant verification is unavailable or declined When micro-deposit verification is initiated Then two micro-deposits are sent within 1–2 business days and the client must confirm exact amounts within 10 days And until verification completes, scheduled charges are queued as Pending Verification and do not attempt And if not verified by the deadline, the authorization is paused and both client and firm receive notifications
Authorization Artifact Persistence and Audit Trail
Given an authorization is signed When it is stored Then an immutable artifact (PDF or HTML) with cryptographic hash, language version ID, and signer metadata is persisted And any subsequent charge references the authorization ID and artifact hash in the event log And if schedule, cap, change terms, or cancellation policy are modified beyond allowed change terms Then a new authorization is required before further charges can process
Payment Method Updates, Rotation, and Card Expiry Handling
Given the stored card will expire before the next scheduled charge When the expiry date is within 30 days Then the client receives automated reminders at T-30, T-7, and T-1 to update the payment method via a secure link And when the client updates the method through the processor Then the token is rotated and linked to the existing authorization without requiring re-signature, provided schedule/cap/terms have not changed And if a charge fails due to expired or invalid method Then retries follow the configured retry policy and the plan status reflects Dunning with notifications sent to client and firm
IOLTA-Safe Funds Routing & Trust Top-Ups
"As a practitioner handling client funds, I want payments to flow to the appropriate trust or operating account so that I remain compliant with IOLTA and avoid commingling."
Description

Route payments to the correct trust or operating account based on fee type and jurisdictional rules to prevent commingling. Support advance fee deposits to trust with automatic transfers to operating only upon earn events, and maintain minimum balance triggers that initiate trust top-ups up to a configurable cap. Generate compliant trust ledger entries per matter and reconcile disbursements with plan schedules. Block convenience fees on trust where prohibited and honor processor account-mapping constraints. Provide configuration per firm and per matter to reflect differing engagement terms.

Acceptance Criteria
Jurisdiction-Driven Funds Routing
Given a matter in a jurisdiction that requires advance fees to be deposited in trust When the client pays a $1,500 retainer Then funds are deposited to the mapped trust account for that jurisdiction and the matter ID is recorded on the transaction Given a matter in a jurisdiction that allows flat fees earned on receipt When the client pays a $750 flat fee Then funds are deposited to the operating account and the ledger notes "Earned on receipt" Given no processor account mapping exists for the required destination account When routing a payment Then the transaction is blocked before authorization with error "Account mapping missing" and no funds are captured
Earn Event Transfer From Trust to Operating
Given an advance fee balance of $1,500 in trust When an earn event of $300 is recorded on the matter Then $300 is transferred from trust to operating within 5 minutes and the trust ledger entry is marked "Earned" Given an earn event amount exceeds available trust balance When an earn event of $400 is recorded and the trust balance is $250 Then $250 is transferred, $150 is flagged as pending transfer, and a notification is sent to the matter owner Given a transfer occurs When the ledger is updated Then entries include timestamp, user/action, matter ID, amounts, and before/after balances and are immutable
Minimum Balance Triggered Trust Top-Ups
Given a matter minimum trust balance of $500 and a per-attempt top-up cap of $200 When a disbursement reduces trust balance to $420 Then an automatic top-up of $80 is initiated within 10 minutes and does not exceed the cap Given a top-up attempt fails due to payment method decline When retry policy is configured for 3 attempts over 72 hours Then the system retries per policy, logs each attempt and outcome, and marks the top-up "Failed" after the final attempt Given the calculated top-up amount exceeds the per-attempt cap When initiating a top-up Then the system charges only up to the cap and records the remaining shortfall as outstanding
Block Convenience Fees on Trust Where Prohibited
Given a jurisdiction that prohibits surcharges on trust deposits When configuring a payment plan that funds trust Then the surcharge option is disabled and the checkout displays $0 surcharge Given an API request attempts to apply a convenience fee to a trust deposit When the request is processed Then the API returns 422 CF_PROHIBITED_ON_TRUST and no transaction is created Given surcharges are permitted on operating charges but not trust deposits When an earned fee is collected to operating Then the configured surcharge is applied and itemized on the receipt while trust deposits remain fee-free
Per-Firm and Per-Matter Configuration
Given firm-level defaults for routing, minimum balance, and top-up cap exist When a new matter is created Then the matter inherits those defaults Given matter-specific overrides are entered When a user sets minimum balance to $750 and a cap of $250 Then the matter uses those values and an audit log records the change with user ID and timestamp Given role-based permissions are enforced When a user without Manage Trust Settings attempts to modify matter trust settings Then the change is rejected with a permission error and logged
Trust Ledger and Plan Reconciliation
Given a payment plan with scheduled deposits, earn events, and disbursements exists When related transactions occur Then the matter trust ledger records each event with a unique sequence ID, linked schedule item ID, and running balance Given a monthly reconciliation run When ledger entries are matched to processor settlement reports and plan schedules Then any variance greater than $0.01 is flagged with a reason code and included in an exception report Given a scheduled disbursement date is changed in the plan When the plan is updated Then pending ledger entries are adjusted by reversal and repost with cross-references, preserving an immutable audit trail
Smart Reminders & Dunning Rules
"As an office manager, I want automated reminders and failure notices sent to clients so that my team spends less time chasing payments."
Description

Send pre-charge, charge confirmation, and failure notifications with configurable cadence and channels (email/SMS) branded to the firm. Include a secure, one-time link for clients to update their payment method without re-authorizing the plan when terms are unchanged. Support quiet hours, throttle limits, and content templates with jurisdictional disclosures. Track delivery, opens, and link clicks to surface at-risk plans, and escalate to staff tasks after defined thresholds. Respect client communication preferences and opt-outs while ensuring required notices are delivered.

Acceptance Criteria
Pre-Charge Reminder Cadence, Channels, and Quiet Hours
Given a scheduled installment at a specific date/time and a reminder cadence of T-3 and T-1 days with Email and SMS channels configured When each trigger time occurs Then a reminder is sent via the configured channels, branded to the firm, including amount, due date/time, last4, and a manage-payment link Given a reminder trigger falls within configured quiet hours (e.g., 21:00–08:00 client local time) When the trigger occurs Then the reminder is queued and delivered at the next allowed window before the charge time and within daily throttle limits Given throttling is set to a maximum of 2 notifications per client per 24 hours When additional reminders would exceed the limit Then the system consolidates into a single reminder per channel and defers extras to the next window Given a reminder is dispatched When delivery is attempted Then channel, timestamp, template version, and messageId are recorded in the audit log
Charge Confirmation Delivery and Tracking
Given a successful charge for a plan When the payment processor returns a success event Then a confirmation is sent within 5 minutes via the configured channels and includes amount, date/time, transaction ID, and receipt link, branded to the firm Given a confirmation is sent When recipients interact Then delivery status, opens, and receipt link clicks are tracked per channel and associated to the plan and client record
Failure Notice with Retry Schedule and One-Time Update Link
Given a charge attempt fails When a failure webhook/event is received Then a failure notice is sent within 5 minutes including failure reason (if available), next retry time, and a single-use HTTPS link to update payment method that expires in 24 hours Given the client opens the link and updates the payment method without changing plan terms When the update is saved Then the plan continues without requiring re-authorization and the next retry uses the new method Given the client attempts to use an expired or already-used link When the link is opened Then access is denied and the client is prompted to request a new link via the authenticated portal Given plan terms are changed during the update flow When the change is submitted Then a fresh authorization is required before resuming charges and dunning pauses until authorization is completed
Communication Preferences, Opt-Outs, and Required Notices
Given a client's communication preferences are stored with explicit channel consents When sending non-required reminders Then only channels with consent are used and non-consented channels are not used Given a notice is marked as required When the client has opted out of marketing or specific channels (e.g., SMS) Then the system sends via an allowed channel (e.g., Email if email consent exists) and records the legal basis for delivery Given no consented channel exists for the client When a required notice must be sent Then the system does not send via prohibited channels, creates a staff task to contact the client, and marks the notice as undeliverable Given quiet hours are configured When required notices are queued Then they are scheduled for the next allowed window before the charge; if the next allowed window would be after the scheduled charge time, send at the last window before charge
Notification Throttling, De-duplication, and Consolidation
Given a maximum of N notifications per client per rolling 24 hours is configured When multiple events would exceed the limit Then the system consolidates into a single message per channel summarizing the events and defers additional messages to the next window Given duplicate events (e.g., repeated processor webhooks) occur within 5 minutes When notifications are generated Then only one notification per event type is sent and duplicates are ignored but logged with a deduplication reason Given consolidation is applied to SMS When the message is constructed Then the first SMS segment is <=160 GSM-7 characters (or <=70 UCS-2), includes key facts, and provides a link for full details
Jurisdictional Templates and Disclosures
Given a plan is associated to a client's jurisdiction When generating a reminder or notice Then the correct template for that jurisdiction is used and all required jurisdictional disclosures are included in the content Given a template is edited or created When attempting to publish Then validation blocks publishing if required tokens (e.g., {{amount}}, {{due_date}}, {{manage_link}}) or mandated disclosures for the jurisdiction are missing and lists the missing items Given firm branding settings (logo, colors, sender name) are configured When emails and SMS are generated Then branding is applied to email headers/footers and supported SMS sender ID/label per carrier and jurisdictional rules
At-Risk Plan Detection, Dashboard Indicators, and Staff Escalation
Given delivery, open, and click events are tracked per notice When a plan meets any of the following: two consecutive payment failures; three consecutive unopened reminders; or no click on the update link within 24 hours after a failure Then the plan is marked At Risk and the status is visible on the plan dashboard with a filterable badge Given escalation thresholds are configured (e.g., max 2 retries without recovery) When a threshold is reached Then a staff task is created with priority, client details, and recommended next action, and subsequent reminders follow the escalation cadence Given an At Risk plan recovers (successful payment or client updates method and next retry succeeds) When recovery occurs Then the At Risk status is cleared, the staff task is updated to Done, and normal cadence resumes
Automatic Retries & Schedule Recovery
"As a billing coordinator, I want failed payments to retry intelligently and schedules to self-correct so that collections continue with minimal staff intervention."
Description

Implement reason-aware retry logic with bank-day scheduling and exponential backoff for soft declines and NSF events, with configurable max attempts. Automatically reschedule missed installments and keep the plan aligned to its end state without exceeding the authorized cap. Allow partial payments to be applied and adjust remaining balances accordingly while maintaining a clear audit trail. Pause, resume, or cancel plans based on client requests or repeated failure criteria, and propagate state via webhooks to connected systems. Ensure idempotency for all collection attempts to avoid duplicate charges.

Acceptance Criteria
Soft-Decline Retry with Bank-Day Backoff
Given an installment auto-collection fails with a soft decline code When the retry policy is enabled and the attempt is within the configured max retries (default 3) Then the next attempt is scheduled using the default backoff sequence [1, 3, 7] bank days unless overridden by plan settings And the computed date falls on a bank day in the plan timezone (skipping weekends and plan holiday calendar) And the retry schedule, reason code, backoff step, and next_run_at are recorded in the audit log And a reminder notification is sent 24 hours before the retry when reminders are enabled And hard declines (e.g., lost/stolen, invalid account) do not trigger retries and the installment is marked failed
NSF Retry for ACH with Exponential Backoff and Max Attempts
Given an ACH debit returns NSF When retries are configured (default max 3) Then the system schedules retries at [2, 5, 10] bank days by default unless overridden in plan settings And no retry is scheduled beyond the plan's end date And each retry respects bank-day rules and processor cut-off times in the plan timezone And after max attempts, the installment is marked failed and plan-level failure handling is invoked
Missed Installment Auto‑Rescheduling Within Authorized Cap
Given one or more installments are missed due to pause or reaching max retries When the plan is active or resumed Then missed amounts are redistributed across remaining installments to preserve the original end date when feasible And if preserving the end date would exceed per‑installment limits or the authorized total cap, the schedule is extended to the minimum additional installments needed without exceeding caps And all new due dates fall on bank days per the plan calendar And the sum of collected plus scheduled amounts never exceeds the plan's authorized cap And all rescheduling actions are appended to the audit log with before/after schedules and actor/source
Partial Payment Application and Balance Recalculation
Given a partial payment settles for less than the installment amount When the settlement posts Then the paid amount is applied to the targeted installment and its remaining_due is reduced accordingly And the remainder is scheduled as a new attempt on the next bank day using the current backoff policy And the plan balance and future installment amounts are recalculated and visible in the dashboard/API within 5 seconds And the audit log records payment_id, applied installment_id(s), remaining_due, and recalculation summary
Plan Pause, Resume, and Cancel with Failure Criteria
Given a client or staff requests pause/resume/cancel, or auto‑pause criteria are met (two consecutive installments reach max retries) When the action is confirmed by an authenticated actor Then the plan status updates to Paused/Active/Cancelled accordingly And all pending attempts are unscheduled on Pause or Cancel and no new attempts are created while Paused And on Resume, the schedule is recomputed using bank‑day rules and recovery logic without exceeding the authorized cap And the action rationale and actor are captured in the audit log And customer notifications and webhooks are dispatched for each state change
Webhook State Propagation and Delivery Guarantees
Given a state change occurs (attempt_scheduled, attempt_succeeded, attempt_failed, installment_rescheduled, plan_paused, plan_resumed, plan_cancelled) When webhooks are configured Then an event with a globally unique event_id, a monotonically increasing sequence per plan, and ISO‑8601 timestamps is enqueued within 2 seconds And deliveries use at‑least‑once semantics with exponential retry for up to 24 hours on 5xx or timeout responses And each delivery includes an Idempotency‑Key header equal to event_id to enable consumer de‑duplication And delivery outcomes (success/failure/retry count) are visible in the dashboard and audit log
Idempotent Collection Attempts to Prevent Duplicate Charges
Given a collection attempt request includes an idempotency_key When the same key is submitted again within 24 hours with identical parameters Then no duplicate processor charge is created and the original result is returned And if parameters differ, the request is rejected with 409 Conflict and no charge is created And idempotency_key, parameter hash, and processor transaction_id are recorded in the audit log And idempotency is enforced across dashboard, API, and automated retry pathways
Live Plan Dashboard, Ledger & Alerts
"As a firm owner, I want a live view of all payment plans and trust balances so that I can intervene early and keep matters funded."
Description

Provide a real-time dashboard listing all plans with status, next charge, collected-to-date, outstanding balance, trust balance, and risk indicators. Enable filters, search, and exports, along with inline actions to pause, cancel, record external payments, trigger a reminder, or refresh a card on file. Display a per-matter ledger that reconciles plan events to trust and operating accounts and shows links to the signed authorization. Offer role-based access controls and configurable alerts for at-risk plans or low trust balances. Support streaming updates and audit-safe snapshots for monthly reconciliation.

Acceptance Criteria
Real-Time Dashboard Overview and Risk Indicators
Given an authenticated user with dashboard access, When the Live Plan Dashboard loads, Then each plan row displays Status, Next Charge (date and amount), Collected-to-Date, Outstanding Balance, Trust Balance, and Risk Indicator. Given a plan event occurs (charge success/failure, pause, cancel, card refresh, external payment recorded), When the event is processed, Then the corresponding dashboard row reflects the change within 3 seconds without page refresh. Given a plan meets any risk rule (>=2 consecutive failures, payment method expiring within 30 days, or upcoming charge within 3 days with trust balance below charge amount), Then the Risk Indicator shows the specific reason label and severity color.
Filter, Search, and Export Plans
Given filter controls are visible, When a user applies filters (Status, Risk Indicator, Next Charge date range, Trust Balance threshold) and/or enters a search term (client or matter), Then the results update within 1 second on datasets up to 5,000 plans and show a count of matches. Given results are filtered, When the user exports, Then the exported CSV contains only the visible result set with the columns displayed and is generated within 10 seconds for up to 10,000 plans. Given an export completes, Then a success confirmation with a download link is shown and the export action is audit logged with filter parameters.
Inline Plan Actions from Dashboard Row
Given a user with manage permissions clicks Pause on a plan row, When the user confirms, Then the plan status becomes Paused, the next scheduled charge is suspended, and the row updates within 3 seconds. Given Cancel is triggered and confirmed, Then all future auto-collections are disabled, the status becomes Cancelled, and the outstanding balance remains visible on the row. Given Record External Payment is submitted with amount, method, and date, When saved, Then the ledger records the entry, Collected-to-Date and Outstanding Balance update accordingly, and Trust/Operating balances adjust per allocation rules. Given Trigger Reminder is clicked, Then a payment reminder is sent to the client using the default template and the action time-stamped. Given Refresh Card on File is initiated, When the client completes the secure update, Then the plan’s payment method is updated and the next retry uses the new method.
Per-Matter Ledger Reconciliation and Authorization Links
Given a user opens a matter’s ledger, Then all plan-related financial events are listed in chronological order with date/time, description, amount, debit/credit, allocation (Trust or Operating), running Trust balance, running Operating balance, and a link to the signed authorization. Given totals are computed, Then (charges + external payments − refunds/chargebacks) equals Collected-to-Date shown on the dashboard and remaining scheduled payments equals Outstanding Balance. Given the user exports the ledger, Then a CSV is produced with identical line items and running balances. Given a ledger entry is viewed, Then the processor transaction ID and action source (system, user, or client) are displayed.
Role-Based Access Controls for Plans and Ledger
Given permissions are configured, Then only users with Billing:View can access the dashboard, Billing:Manage can execute inline actions, Billing:Export can export data, and Billing:Trust can view Trust balances and ledger allocations. Given a user lacks a permission, Then corresponding UI controls are hidden and direct API attempts return 403 Forbidden with no data leakage. Given access is revoked while a session is active, When the user attempts a protected action, Then the action is blocked and the UI reflects updated permissions within 60 seconds.
Configurable Alerts for At-Risk Plans and Low Trust Balances
Given an admin sets alert thresholds (e.g., consecutive failures count and low Trust balance amount), When saved, Then the configuration persists organization-wide and survives user logout/login. Given a plan meets an at-risk condition, Then an in-app alert appears in the dashboard Alerts panel and an email notification is sent to configured recipients within 5 minutes including plan, client, matter, reason, and next charge details. Given an alert is acknowledged by a user, Then it is marked read for that user but remains active until the underlying condition is resolved. Given a matter’s Trust balance falls below the configured threshold, Then a Low Trust alert is generated and visible on both the matter and the dashboard.
Streaming Updates and Monthly Audit-Safe Snapshots
Given the dashboard is open, When new plan events occur, Then the UI updates via streaming within 3 seconds and indicates Live status without requiring a page refresh. Given month-end reconciliation, When a user generates a snapshot for a selected month, Then the system produces an immutable, timestamped snapshot as of 23:59:59 in the organization’s timezone with plan list, balances, and full ledgers, stores a cryptographic hash, and makes CSV and PDF downloads available. Given a snapshot exists, Then subsequent changes are not retroactively applied to that snapshot and are only reflected in later reporting periods. Given a snapshot is retrieved, Then its integrity hash validates and its contents match the state captured at generation time.
Audit Trail & Compliance Reporting
"As a compliance officer, I want a complete audit trail and standardized reports so that I can demonstrate adherence to trust accounting and payment regulations."
Description

Record an immutable, time-stamped event log for each plan covering authorization capture, schedule changes, charge attempts, notices sent, and user actions. Store signed artifacts and mandate IDs with cryptographic integrity checks and redact sensitive PAN/ABA data from views and exports. Provide monthly trust reconciliation reports, plan performance summaries, and downloadable evidence packs suitable for bar audits. Map controls to SOC 2 and maintain encryption at rest and in transit with strict retention policies. Offer export and API access for compliance teams and external accountants.

Acceptance Criteria
Immutable, Comprehensive Event Logging
- Given a payment plan exists, When the system captures an authorization, modifies a schedule (date, amount, cap), attempts a charge (success, retry, fail), sends a notice (reminder, dunning), or a user performs an action (create/update/pause/cancel), Then an append-only event is recorded with: ISO 8601 UTC timestamp, event type, actor (user ID/service), plan ID, prior/new values (for changes), source IP/UA, and result code. - Given a lifecycle test executes all supported actions, Then the event log contains at least one event for each category: authorization capture, schedule change, charge attempt (incl. retries), notices sent, and user actions. - Given any attempt to alter or delete an existing event via UI or API, When the request is submitted, Then the platform rejects it with HTTP 403 and logs the attempt. - Given the daily tamper-check job runs, When it recomputes a chained SHA-256 hash over the log, Then any modification triggers an alert and the plan is flagged "audit attention". - Given a plan has up to 10,000 events, When events are queried by date range, type, or actor, Then results return in ≤ 2 seconds with correct chronological order and pagination.
Cryptographic Integrity & Signed Artifacts
- Given an authorization is e-signed, When the artifact is stored, Then a SHA-256 checksum, e-sign envelope ID, signer identity, timestamp, and mandate ID/token reference are recorded and linked to the plan. - Given a stored artifact is downloaded, When its checksum is recomputed, Then it matches the recorded SHA-256 value. - Given an update to any artifact is required, When a new version is saved, Then it is stored as a new immutable version with version number and reason; prior versions remain read-only; in-place edits are blocked. - Given storage configuration, Then artifacts are encrypted at rest and stored on WORM-capable buckets or equivalent immutability controls.
Sensitive Data Redaction in UI & Exports
- Given a user views plan details or event logs, Then card numbers are masked to last 4 (no full PAN), bank account numbers masked to last 4 (no full ABA/account), and CVV/CVC is never stored or displayed. - Given an export (CSV/PDF/JSON via UI or API) is generated, Then sensitive fields are excluded or masked consistently with UI masking; no full PAN/ABA/account numbers appear. - Given a system scan for numeric patterns ≥ 12 digits on exported and logged content in a test environment, Then no matches to full PAN/ABA/account numbers are found. - Given API responses that include payment method references, Then only tokens, mandate IDs, and last4 are returned; attempts to request full numbers return HTTP 403 and are logged.
Monthly Trust Reconciliation Reports
- Given it is the first business day at 08:00 firm local time, When the scheduler runs, Then a reconciliation report is generated for the prior month per trust account. - Given the report is opened, Then opening balance equals the prior month’s ending balance; deposits (by plan/mandate), disbursements, top-ups, fees, uncleared items, and ending balance are listed; variance is 0.00 or flagged if non-zero. - Given an Accountant or Admin downloads CSV/PDF, Then totals and transaction counts match the ledger export/API within $0.01; generation time is ≤ 30 seconds; downloads are access-controlled and audit-logged. - Given filters (account, matter, plan status) are applied, Then the report recalculates totals accurately and the filter set is stored in the export metadata.
Evidence Pack Download for Bar Audits
- Given a plan is selected, When "Download Evidence Pack" is requested, Then a ZIP is produced within 60 seconds containing: complete event log (JSON + human-readable PDF), signed authorization/retainer artifacts, notices sent, plan schedule and change history, charge results, mandate IDs, and a manifest with per-file SHA-256 hashes. - Given the evidence pack is downloaded, When the manifest is validated, Then all file hashes match; the pack is signed or sealed with a top-level manifest hash. - Given access control policies, Then only Attorney, Admin, or Accountant roles can generate packs; links expire within 24 hours; each access is audit-logged with user, IP, and timestamp. - Given a plan has >500 events and artifacts totaling up to 50 MB, Then the pack still generates successfully and remains under 50 MB via compression or pagination of logs.
SOC 2 Control Mapping, Encryption, and Retention Policies
- Given the SOC 2 mapping view is opened, Then each applicable control (e.g., CC, A1) maps to specific product controls with linked evidence (policy doc, config, test result) and last-reviewed dates; exportable as CSV/PDF. - Given transport security tests, Then all endpoints enforce TLS 1.2+ with modern ciphers; HSTS enabled; weak ciphers and TLS <1.2 are rejected. - Given data-at-rest validation, Then customer data, artifacts, and logs are encrypted with AES-256 or equivalent; keys are managed in a KMS with rotation at least annually; KMS access is audit-logged. - Given retention settings, Then audit logs and artifacts have a default retention of 7 years; legal holds can be applied per matter/plan; upon expiry, data is purged within 30 days and purge events are audit-logged; backups honor the same retention or document exceptions with restore testing evidence.
Compliance Exports and API Access
- Given an Admin generates a compliance export via UI, Then the user can select date range, entity (firm/account/plan), and format (CSV/JSON); the job completes within 15 minutes for up to 1,000,000 rows and is downloadable with integrity metadata (row count, checksum). - Given an API client with scope compliance.read calls GET /api/v1/compliance/events with date filters, Then results are paginated, PII is masked, rate-limited to 60 req/min, and responses include a next cursor; all accesses are audit-logged with client ID and IP. - Given a non-privileged user attempts to export or call compliance APIs, Then the request is denied with HTTP 403; no data is leaked; the attempt is logged with reason code. - Given an export is re-run with the same parameters, Then the content hash is identical unless underlying data changed; differences are reported with a delta manifest.

Surcharge Compliance

Reduce processing costs without risking violations. Briefly applies or suppresses surcharges based on card type and jurisdiction, shows clear client disclosures, routes convenience fees to operating (never trust), and offers no‑fee ACH alternatives—maximizing savings while staying compliant and transparent.

Requirements

Card & Jurisdiction Detection
"As a solo attorney, I want Briefly to automatically recognize when a client's payment is a credit card and what jurisdiction applies so that surcharges are only considered when allowed."
Description

Detect payment method characteristics (credit vs debit/prepaid), card brand, and the applicable jurisdiction using BIN lookup and available client/firm location data. Normalize inputs, handle cross-border scenarios, and output a standardized decision context consumed by the surcharge rules engine. Operate across web, mobile, and payment-link flows. Degrade safely when card type is indeterminate by treating the transaction as non-surchargable until confirmed. Cache BIN metadata, honor PCI constraints by using tokenized data from the processor (no PAN storage), and allow BIN range updates via configuration without code deployments.

Acceptance Criteria
Tokenized BIN Lookup for Card Type & Brand Detection
Given a tokenized card from an integrated processor that includes BIN (first 6–8) and last4 When the detection service receives the token Then it performs a BIN lookup via the configured provider using only token/BIN (no PAN) and returns card.type ∈ {credit, debit, prepaid, unknown} and card.brand ∈ {Visa, Mastercard, Amex, Discover, Other} And Then the service sets card.issuingCountry to an ISO 3166-1 alpha-2 code and bin.length to 6–8 as provided And Then P95 lookup latency ≤ 300 ms and lookup success ratio (non-5xx from provider) ≥ 99.5% over a rolling 24h window And Then an audit event is recorded without PAN, including masked BIN (first 8 shown), provider, requestId, and result codes
Jurisdiction Resolution from Firm and Client Data
Given firm location (country, state/region) and optional client location When building the decision context Then jurisdiction.country = normalized(firm.country, ISO 3166-1 alpha-2) and jurisdiction.region = normalized(firm.state/region, ISO 3166-2) And Then client.regionNormalized is included if client state/region is present; values normalized to ISO 3166-2 or USPS for US And Then crossBorder = (card.issuingCountry ≠ jurisdiction.country) And Then all address inputs are normalized (case-insensitive, punctuation-tolerant) and invalid/missing pieces default to null without failing the flow
Cross-Border Indicators and Edge Cases
Given issuingCountry differs from firm country (e.g., CA vs US) When the decision context is built Then crossBorder=true and jurisdiction.scope="cross-border" And Given issuingCountry equals firm country but client region differs from firm region When the decision context is built Then crossBorder=false and jurisdiction.scope="domestic-interstate" And Then the context includes fields: {issuingCountry, merchantCountry, clientCountry?, crossBorder, jurisdiction.scope} with non-null merchant/issuing values
Safe Degradation on Indeterminate Card Type
Given the BIN provider returns no match, error, or ambiguous type When detection completes Then card.type="unknown" and decision.assumeNonSurchargable=true with reason="indeterminate-card-type" And Then surcharge flag is not set to true in the decision context, and a retry policy is attached (retryEligible=true, retryAfterSeconds ≤ 300) And Then the UI/API response exposes a no‑fee ACH alternative flag (offerAch=true) for downstream surfaces
BIN Metadata Caching and Hot Config Updates
Given the same BIN is looked up multiple times within the configured TTL When requests are processed Then only the first triggers an external provider call and subsequent lookups are served from cache with cache.hit=true And Then the default TTL is configurable (e.g., 24h) via admin configuration without code deployment; updating the configuration invalidates affected cache entries within 60 seconds And Then configuration changes include a configVersion in the decision context and are audit-logged
PCI-Conformant Token-Only Processing
Given a payment is initiated When detection runs Then no primary account number (PAN) is accepted, stored, or logged; only processor tokens, masked BIN (first 6–8), and last4 are permitted And Then log scrubbing redacts any PAN-like patterns and structured logs pass a compliance check with zero violations in automated tests And Then database and telemetry contain no PAN values in schema or sample records in integration tests
Channel Parity Across Web, Mobile, and Payment-Link Flows
Given identical tokenized card and subject data are submitted via web, mobile, and payment-link flows When detection runs Then the produced decision context schema and values are identical across channels (excluding channel metadata), and schemaVersion matches expected And Then channel-specific latency P95 ≤ 300 ms for web and mobile SDK, and ≤ 500 ms for payment-link (cold start), measured in staging And Then if a channel omits client location, detection still returns a valid context with null client fields and no errors
Surcharge Rules Engine & Rate Caps
"As a compliance-conscious firm owner, I want a rules engine that applies or suppresses surcharges based on card networks and local rules so that I save fees without risking violations."
Description

Provide a centralized, data-driven policy engine that determines whether a surcharge or convenience fee may be applied, the permissible maximum rate/amount, and suppression cases (e.g., prohibited payment types, regions, or channels). Accept merchant-configured target rates and clamp them to allowed caps. Return a decision payload with allowed status, reason codes, disclosure requirements, capped rate, and computed amounts. Support versioned, admin-editable rules with change history and effective dates, plus simulation mode for QA. Default to suppression where uncertainty exists. Offer unit-testable rule packs and telemetry for decision transparency.

Acceptance Criteria
Clamp Target Rate to Jurisdictional Cap and Compute Amounts
Given a card-not-present Visa credit transaction in jurisdiction US with purchaseAmount = 1000.00 USD and merchant targetRate = 3.5% And the jurisdictional cap for Visa credit surcharges is 3.0% When the rules engine evaluates the surcharge decision Then allowed = true And cappedRate = 3.0% And surchargeAmount = 30.00 USD (rounded to 2 decimals, using banker’s rounding) And totalAmount = 1030.00 USD And reasonCodes includes ["CAP_APPLIED"] And disclosureRequirements includes ["SURCHARGE_ALLOWED","MAX_RATE_DISCLOSURE"] And if targetRate <= cap (e.g., 2.0%), cappedRate = targetRate and reasonCodes excludes "CAP_APPLIED"
Suppress Surcharge for Prohibited Payment Types or Regions
Given a US debit card transaction (any network) where debit surcharging is prohibited in the jurisdiction When the rules engine evaluates the surcharge decision Then allowed = false And cappedRate = 0% And surchargeAmount = 0.00 And totalAmount = purchaseAmount And reasonCodes includes ["PROHIBITED_PAYMENT_TYPE"] And disclosureRequirements includes ["NO_SURCHARGE_DISCLOSURE"] And decisionPayload.surchargeType = "none" Given any transaction in a jurisdiction that bans surcharges outright When evaluated Then allowed = false with reasonCodes including ["PROHIBITED_JURISDICTION"] and amounts as above
Default Suppression on Uncertainty (Missing or Ambiguous Data)
Given a transaction where BIN data or network cannot be determined or jurisdictional cap is not found When the rules engine evaluates the surcharge decision Then allowed = false And reasonCodes includes ["UNCERTAIN_DATA"] And cappedRate = 0% And surchargeAmount = 0.00 And disclosureRequirements includes ["NO_SURCHARGE_DISCLOSURE"] And decision includes diagnostics.missingFields enumerating which inputs were unavailable
Decision Payload Completeness and Field Semantics
Given any evaluated transaction When the rules engine returns a decision Then the payload includes fields with valid values: - allowed: boolean - reasonCodes: array<string> (non-empty when allowed = false) - targetRate: number (0.0000–1.0000) - cappedRate: number (0.0000–1.0000) and cappedRate <= applicableCap - surchargeType: enum("surcharge","convenience_fee","none") - surchargeAmount: monetary 2-decimal string in currency - totalAmount: monetary 2-decimal string in currency and equals purchaseAmount + surchargeAmount - currency: ISO 4217 code - disclosureRequirements: array<string> - rulePackVersion: string (semver) - effectiveRuleId: string (uuid) - evaluationTimestamp: ISO-8601 UTC And if allowed = false then surchargeAmount = 0.00 and surchargeType = "none" And numeric rates are rounded to 4 decimal places; monetary amounts to 2 decimal places
Versioned, Admin-Editable Rules with Effective Dates and History
Given rule pack v1.2.0 is active with effectiveFrom <= now < effectiveTo When a decision is evaluated Then rulePackVersion = "1.2.0" and effectiveRuleId references a rule whose effective window contains now Given an admin publishes v1.3.0 with effectiveFrom = tomorrow When evaluating today Then the engine still applies v1.2.0 Given v1.3.0 becomes active at effectiveFrom When evaluating after that timestamp Then the engine applies v1.3.0 Given an admin edits a rule When saved Then a new immutable version is created (version increments) and changeHistory records author, timestamp, summary, and diff
Simulation Mode Produces Non-Persistent, Traceable Decisions
Given any transaction input and simulation = true When the rules engine evaluates the decision Then the decision outcome (allowed, cappedRate, amounts, reasonCodes) matches what live evaluation would produce for the same inputs And decisionPayload.simulation = true And no persistent side effects occur (no audit entry of "applied", no counters incremented) And telemetry includes mode = "simulation" and a link to the evaluation trace
Telemetry and Decision Transparency
Given a decision request with requestId and optional traceId When the rules engine completes evaluation Then a telemetry event is emitted containing: requestId, traceId (generated if missing), rulePackVersion, effectiveRuleId, jurisdiction, paymentMethod details, allowed, reasonCodes, cappedRate, surchargeAmount, evaluationDurationMs And the event is queryable in the telemetry sink within 10 seconds And an evaluation trace is retained for at least 24 hours for debugging
Client Disclosures & Explicit Consent
"As a client paying online, I want to see exactly what fee I’m being charged and agree before I pay so that I’m not surprised and I can choose a no-fee option."
Description

Present clear, plain-language disclosures when a surcharge or convenience fee will be applied, including the calculation basis and resulting amount, before payment confirmation. Ensure accessibility (WCAG AA), mobile-first layouts, currency/format localization, and real-time updates as payment method changes. Require explicit acknowledgment captured with timestamp, IP, user agent, and a snapshot of the decision details. Hide fee elements when rules suppress surcharges. Allow limited, brand-safe text customization. Persist a renderable disclosure artifact for receipts and audit purposes.

Acceptance Criteria
Pre-Payment Disclosure Render and Fee Calculation
Given a payment subtotal and a card payment method subject to a surcharge or convenience fee, When the payment screen loads or the method is selected, Then a disclosure is shown before payment confirmation displaying the fee basis (rate/flat and cap), card type and jurisdiction, the calculation method, the exact fee amount, and the new total. Given fee suppression rules apply (e.g., debit card, prohibited jurisdiction, or cap exceeded), When the payment screen loads or method is selected, Then no fee amount or fee disclosure elements are shown and the total excludes any fee. Given the fee applies, When the subtotal or taxable basis changes prior to confirmation, Then the disclosure recomputes and displays the updated fee amount and total prior to consent.
Explicit Consent Capture and Enforcement
Given a surcharge or convenience fee will be applied, When the user proceeds to pay, Then the user must explicitly acknowledge the disclosure via a required control (e.g., checkbox or explicit “I agree” action) that references the specific fee amount and basis, and payment cannot continue until acknowledged. When the user provides consent, Then the system records timestamp (UTC), IP address, user agent, user/account ID (if available), jurisdiction, selected payment method, fee basis, fee amount, and total, and binds these to the transaction attempt. Given the user changes payment method or amount resulting in a different fee outcome, When attempting to pay, Then previously captured consent is invalidated and a fresh acknowledgment is required reflecting the new details.
WCAG AA Accessibility and Mobile Responsiveness
Given a user navigating with keyboard or screen reader, When interacting with the disclosure, Then all controls are reachable via keyboard, focus order is logical, focus is visibly indicated, and the disclosure is fully announced with accessible names/roles and readable amounts. Then text and interactive elements meet WCAG 2.1 AA color contrast (4.5:1 for body text, 3:1 for large text), error states are announced, and the modal (if used) traps focus until dismissed or acknowledged. Given mobile viewports from 320px to 414px width, When the disclosure renders, Then layout is mobile-first with no horizontal scroll, touch targets are at least 44x44px, and CTAs remain visible without overlap or truncation.
Localization of Currency, Number, and Language
Given a configured locale/currency from firm settings or client profile, When the disclosure renders, Then all monetary values (fee, subtotal, total) use locale-appropriate currency symbols/codes and number formatting (e.g., $1,234.56 for en-US, 1 234,56 € for fr-FR). When the user or system locale changes prior to consent, Then the disclosure re-renders in the new locale without altering the underlying amounts or rules. Given a missing translation, When the disclosure renders, Then it falls back to the default language without broken placeholders and preserves required legal statements.
Real-Time Disclosure Update on Payment Method Change
Given the user toggles between credit card, debit card, and ACH, When the selection changes, Then the disclosure updates within 1 second to reflect apply/suppress status and recalculates fee amount and total; ACH shows a no‑fee state with fee = 0. Given BIN lookup classifies the card as debit or other suppressed type, When the user enters sufficient card digits, Then fee elements hide and totals exclude the fee. Given the user switches back to a fee-applicable method, When the selection changes, Then the disclosure reappears with the correct, current fee amount and basis and any prior consent is cleared.
Disclosure Artifact Persistence and Receipt Embedding
When the user completes explicit consent (at payment confirmation) or the transaction is finalized, Then the system persists an immutable, renderable artifact (HTML/PDF) containing the disclosure text, template version, jurisdiction, payment method, fee basis, fee amount, total, and consent metadata (timestamp, IP, user agent) with a unique ID and content hash. When viewing the receipt or payment record, Then the artifact is retrievable via UI and API and renders identically to the consented view; it cannot be edited post‑creation, and superseding consents create new artifacts without altering prior ones. Given an audit request, When the artifact is retrieved, Then all required fields are present and match the transaction log values.
Brand-Safe Customization of Disclosure Text
Given an admin with permissions, When editing disclosure text, Then only allowed regions (e.g., header and footer) are editable with character limits and required placeholders/clauses enforced; unsafe HTML/CSS/JS is stripped on save. When saving customized text, Then validation blocks removal of mandatory statements/variables, flags missing placeholders, enforces length limits, and provides a preview that matches the runtime render. Given multiple locales, When customization is saved, Then localized variants can be provided per language; where absent, the system falls back to the default safely without breaking required content.
Operating-Only Fee Routing
"As a lawyer who handles client trust funds, I want surcharge proceeds to always go to operating and never touch trust so that I remain compliant with trust accounting rules."
Description

Automatically split surcharge/convenience fee proceeds to the firm’s operating account and ensure fee amounts never enter the trust/IOLTA account. Use gateway-native split settlement where available; otherwise, create post-settlement journal movements that preserve trust principal intact while allocating fees to operating with a dedicated GL code. Block transactions when routing cannot guarantee trust protection. Expose routing results in admin views and include in exports to accounting systems.

Acceptance Criteria
Gateway Split Settlement to Operating
Given a card payment includes a surcharge or convenience fee and deposits principal to trust And the gateway supports native split settlement and operating and trust accounts are configured When the charge is captured and settles Then 100% of the fee amount is settled to the operating account and 0% of the fee amount is settled to the trust account And 100% of the principal amount is settled to the trust account And the transaction record stores method="split_settlement", operating_account_id, trust_account_id, fee_amount, principal_amount, settlement_id, and settlement timestamps And the admin transaction detail view displays the trust/operating allocations and method And the accounting export contains a separate line for the fee to operating using the dedicated GL code
Fallback Journal Movement Preserves Trust Principal
Given a payment includes a surcharge or convenience fee and the gateway does not support split settlement And the firm has enabled journal-movement fallback with required permissions When the charge settles as a single deposit Then an automatic journal entry moves the fee amount from trust to operating within 60 minutes of receiving the settlement webhook And the trust principal ledger for the client/matter reflects only the principal amount (fee not counted as trust principal) And journal lines use the dedicated fee GL code and link to the original transaction and settlement id And the admin view and export show the journal movement id, timestamps, amounts, bank accounts, and GL codes And if the journal cannot be posted automatically, the transaction state becomes routing_error and an alert is sent to admins
Block When Trust Protection Cannot Be Guaranteed
Given a user attempts to take a payment that would deposit principal to trust And either no operating account is configured, or split settlement is unavailable and journal fallback is disabled or lacks required permissions When the user submits the payment form Then the transaction is blocked before authorization And an error message explains that fees cannot be routed safely and offers the no-fee ACH option And no authorization or capture is created with the gateway And an audit log records user id, timestamp, reason_code="routing_unavailable", and configuration gaps
Admin Visibility and Accounting Export of Routing Results
Given any settled transaction with a surcharge or convenience fee When an admin opens the transaction detail view Then the view shows: routing method (split_settlement or journal_movement), principal to trust, fee to operating, bank account identifiers, GL code, settlement id, and timestamps And when exporting to the accounting system Then the export contains distinct lines for principal-to-trust and fee-to-operating (with the dedicated GL code), plus any journal movement lines, each with stable external ids that map back to the transaction
Dedicated GL Code Enforcement for Fee Allocation
Given fee routing configuration requires a dedicated GL code When a transaction with a surcharge or convenience fee is processed Then the fee allocation posts using the configured GL code in all journals and exports And if the GL code is missing or invalid, the transaction is blocked before capture and a configuration error is presented to admins
Refunds, Voids, and Chargebacks Maintain Trust Integrity
Given a transaction where principal was allocated to trust and fees to operating When a full or partial refund, void, or chargeback occurs Then principal reversals affect only the trust principal ledger for the client/matter And any fee reversals due to the client post from the operating account, not from trust And all reversal journals and exports use the dedicated GL code and reference the original transaction id And net trust principal remains accurate before and after the reversal
ACH/No-Fee Alternative Leaves Trust Untouched by Fees
Given the payer selects ACH/no-fee payment for a trust deposit When the payment authorizes and settles Then no surcharge or convenience fee is applied And no fee ledger entries are created in trust or operating for the transaction And the admin view and export show zero fee and payment_method=ACH
No-Fee ACH Alternative
"As a cost-sensitive client, I want a no-fee bank transfer option so that I can avoid paying a card surcharge."
Description

Offer a prominently presented bank transfer option as a zero-fee alternative whenever a surcharge would otherwise apply. Display side-by-side payment choices with dynamic totals and clear explanations of timing and refund considerations. Support instant account verification where available with fallback micro-deposits, and perform basic account name validation to reduce returns. When the user selects ACH, remove any surcharge and recalculate the total. Provide webhooks/events for settlement status to update matter records and documents.

Acceptance Criteria
Side-by-Side Payment Options With Dynamic Totals
Given a payment request where a card surcharge would apply When the user opens the payment screen on desktop or mobile (viewport ≥ 375x667) Then display two payment choices side-by-side without scrolling: Card (showing surcharge) and ACH (labeled No Fee) And show base amount, surcharge amount, and total for Card; show base amount and total (no surcharge) for ACH And when the user toggles between Card and ACH, the displayed total updates within 500 ms And the ACH option is visually emphasized with a No Fee badge and is keyboard- and screen-reader accessible
Surcharge Removal on ACH Selection
Given a payment request that includes a card surcharge policy When the user selects ACH and proceeds to payment authorization Then exclude any surcharge line item from the charge authorization and internal ledger entries And ensure the amount authorized equals the base amount (plus applicable taxes/adjustments) with zero surcharge And ensure receipts, invoices, and matter records display no surcharge for the transaction And if the user switches back to Card before paying, reinstate the surcharge in UI and calculations
Clear ACH Timing and Refund Disclosures
Given ACH is available as a payment option When the payment screen is displayed Then show an inline disclosure that ACH settlement may take 3–5 business days and ACH refunds may take 5–10 business days to post And require the user to check an acknowledgement box before enabling the Pay with ACH button And include a learn more link to the payments policy And include the ACH timing/refund disclosure text on the receipt and in the signed engagement document
Instant Account Verification With Fallback Micro-Deposits
Given the user initiates bank account linking for ACH When the selected institution supports instant account verification (IAV) Then present a secure IAV flow and on success store only a tokenized account reference (no raw account/routing numbers) When IAV is unavailable or fails Then offer a micro-deposit verification flow that sends two deposits within 1–2 business days And require correct entry of the two amounts before enabling ACH payments for that account And allow the user to cancel ACH linking and choose Card at any time
Basic Account Name Validation to Reduce Returns
Given an ACH account has been linked or entered When the system obtains the account holder name Then compare it to the client/matter party legal name using case-insensitive, punctuation-insensitive comparison with a similarity threshold of ≥ 0.80 And if the similarity is < 0.80 or the entity types differ (e.g., business vs individual), require an authorization attestation checkbox to proceed And prevent ACH initiation if the account holder name is empty or clearly invalid (e.g., < 2 characters) And record the validation result and any attestation flag on the payment record for audit
Settlement Webhooks and Event Processing
Given an ACH payment is initiated When the payment status changes (initiated, submitted, settled, returned, reversed) Then emit signed, idempotent webhook events with unique IDs, timestamps, and payment/matter references And retry failed webhook deliveries using exponential backoff for at least 24 hours And upon receiving each event, update matter balances, payment status, and regenerate payment-related document sections as needed And expose a GET events API to retrieve event history for reconciliation
ACH Failure Handling and Fallback to Card
Given an ACH verification attempt fails or a posted ACH is returned (e.g., R01, R02, R03) When the user is notified or revisits the payment screen Then display a clear error with the return code/description and mark the payment as unpaid/returned in the matter And restore the Card option with the applicable surcharge and allow immediate completion via Card And prevent double charges by enforcing idempotency keys across retries and payment method switches And maintain the original invoice/reference number while creating a new payment attempt record
Itemized Receipts & Invoices
"As an attorney, I want itemized receipts that show any surcharge as a separate line so that clients and auditors can clearly see how the total was calculated."
Description

Generate receipts and invoices that list surcharge or convenience fees as separate line items from legal services. Show base amount, applied rate/fee, and total. Include a disclosure excerpt and link to the full consent artifact. Ensure documents are compatible with Briefly’s document automation and e-sign flows. Enable resend and client-portal download. Respect tax handling per configuration and provide API fields for downstream accounting synchronization.

Acceptance Criteria
Invoice Itemization with Applied Surcharge
Given a legal services charge exists and the payment method qualifies for a surcharge at a configured rate or flat fee When an invoice is generated Then the invoice displays separate line items for Legal Services (base amount) and Card Surcharge labeled with the applied rate/fee And the surcharge amount is calculated on the eligible base per configuration and rounded to two decimals And Subtotal, Tax (if any), and Total are shown and Total equals the sum of all line items And currency code matches the matter currency and amounts format as 0.00
Receipt Without Surcharge When Suppressed by Jurisdiction
Given a card payment from a jurisdiction or card type where surcharges are prohibited When a receipt is generated Then no surcharge or convenience-fee line item appears on the document And the receipt shows the base amount, tax (if configured), and total only And the document includes a note "Surcharge not applied due to jurisdiction/card rules" And Total equals base plus applicable taxes
Disclosure Excerpt and Consent Link on Documents
Given the payer accepted the surcharge/convenience-fee disclosure during checkout When an invoice or receipt is generated Then the document includes a disclosure excerpt of 140–300 characters, with an ellipsis if truncated And a visible hyperlink labeled "View full consent" points to the stored consent artifact URL And the URL resolves with HTTP 200 and references the correct payer, matter, and timestamp And the link is clickable in HTML view and embedded as a hyperlink in the PDF
Compatibility with Document Automation and E‑Sign Flow
Given an invoice or receipt is generated by the system When it is added to a Briefly document automation package Then the package validator reports no blocking errors and the document MIME type is PDF And the document can be included in an e‑sign envelope with zero required signature fields by default And the envelope can be sent successfully and recipients can view the document without signature prompts
Resend and Client‑Portal Download of Invoice/Receipt
Given an existing invoice or receipt is present in a matter When a user clicks "Resend" Then email and SMS notifications are sent with a unique, expiring access link valid for 30 days And an audit log entry records the resend action with user, timestamp, channels, and target contacts When the client opens the link and selects "Download PDF" Then the file downloads within 5 seconds and a download audit event is stored with client identity and timestamp
Tax Handling per Configuration on Fees and Services
Given tax configuration defines service_tax_rate and whether surcharge/convenience fees are taxable When an invoice is generated for a $100.00 service with a 3.00% card surcharge and service_tax_rate = 8.25% Then if surcharge_taxable = false, the document shows Tax (Services 8.25%) = 8.25, Card Surcharge (3.00%) = 3.00, no tax on surcharge, Total = 111.25 And if surcharge_taxable = true, the document shows Tax (Services 8.25%) = 8.25 and Tax (Surcharge 8.25%) = 0.25, Total = 111.50 And tax lines are labeled with the applied rate and jurisdiction label (if configured)
API Fields for Downstream Accounting Sync
Given an invoice or receipt is created with or without a surcharge/convenience fee When retrieving it via API or receiving the invoice.created or receipt.created webhook Then the payload includes: invoice_id/receipt_id, matter_id, currency (ISO‑4217), base_amount, surcharge_type (credit_card|convenience|none), surcharge_rate, surcharge_amount, tax_service_amount, tax_surcharge_amount, total_amount, disclosure_excerpt, consent_artifact_url, line_items[], and deposit_account for each fee line And all monetary fields are strings with two decimal places and reconcile so total_amount equals the sum of line items and taxes And deposit_account for any surcharge/convenience fee line equals "operating" and is never "trust"
Compliance Audit Trail & Reporting
"As a managing attorney, I want exportable compliance records of surcharge decisions and client consent so that I can prove adherence if audited."
Description

Persist an immutable audit trail for each payment decision, capturing detection inputs, rules version, decision result and reasons, displayed disclosures, client consent, routing outcomes, and document artifacts. Provide searchable reports and exports by date range, matter, or user, with role-based access controls. Trigger alerts for anomalies (e.g., surcharge applied where later rules indicate suppression) and offer remediation guidance. Enable sandbox replay of historical transactions against updated rules to evaluate impact before publishing changes.

Acceptance Criteria
Immutable Audit Trail Capture on Payment Decision
Given a payment attempt with detected card attributes and jurisdiction When a surcharge decision is computed Then an audit event is appended capturing: timestamp (UTC), payment/matter/user IDs, detection inputs (tokenized BIN, card brand, funding type, card-present flag, jurisdiction codes), ruleset ID and hash, decision (apply|suppress) and reasons, disclosure IDs and text hash, consent artifact ID and timestamp, routing target (operating|trust), document artifact IDs, and actor identity And any attempt to update a persisted audit event returns 409 Conflict; only append-only correction events are permitted and are linked by prior_event_id And the audit stream is tamper-evident: a verification endpoint validates a hash chain and returns valid for unaltered sequences and invalid if any event is removed or changed
Disclosure and Client Consent Recording
Given a decision requires disclosures When the payment UI is presented Then the exact disclosure text and version ID shown are snapshotted and stored with locale and timestamp And when the client proceeds Then e-sign consent metadata (IP, user agent, approximate geo, timestamp) and a signed consent artifact are stored and linked to the audit event And the audit view renders those artifacts and redacts sensitive fields according to the viewer’s role
RBAC Search and Export
Given a Compliance Admin is authenticated When they search audit events by date range, matter, or user Then results are filterable, sortable, and paginated (default 50, max 500) with a total count And when they export the current result set Then CSV and JSON exports are available, complete within 30 seconds for up to 10,000 events, include a header dictionary, and the export action is audited And when an Attorney without export permission attempts export Then 403 Forbidden is returned and they can only view audit events for matters they are assigned And unauthenticated requests receive 401 Unauthorized
Anomaly Detection and Remediation Alerts
Given a new ruleset is published When the anomaly job re-evaluates the last 90 days of applicable transactions Then any transaction where the new rules would suppress a previously applied surcharge is flagged with old vs new outcomes and rule references And an alert is sent to Compliance Admins via in-app and email within 5 minutes, containing counts and links to affected items And each anomaly provides remediation guidance (refund amount, client notice template, steps) and supports Mark Resolved and Dismiss as False Positive, requiring a reason; status changes are audited
Sandbox Replay Against Updated Rules
Given an Admin selects a date range, matter, or user filter and a candidate ruleset version When they run a sandbox replay Then simulated decisions are computed and no production records, payments, or client notifications are changed And the replay produces an impact report with counts by outcome change category (apply->suppress, suppress->apply, unchanged), projected fee deltas, and a list of affected transactions with IDs; the report completes within 2 minutes for 10,000 events And replay results are retained for 14 days, downloadable as CSV/JSON, and access is restricted to Admin/Compliance roles; others receive 403
Document Artifact Preservation and Retrieval
Given a payment decision completes When document artifacts are generated Then immutable snapshots are stored for the retainer draft, disclosure snapshot, consent artifact, and ruleset JSON; each stored object has a content hash and version And retrieval uses short-lived signed URLs (expiry <= 15 minutes) and is logged with requester identity and reason; artifacts are viewable per RBAC
Routing Outcome and Segregation Logging
Given a payment includes a convenience fee When the payment settles Then the audit records the routing destination for fee (operating) and principal (trust if applicable), and ledger events confirm no surcharge funds enter trust accounts And given the client selects ACH as an alternative When payment is processed Then the decision shows no surcharge applied, ACH method recorded, and routing reflects no fee And a routing summary report by date range shows totals by destination and matches processor settlement totals within 0.5% variance

Dispute Shield

Lower chargebacks and win more disputes. Adaptive risk prompts (e.g., 3‑D Secure/strong auth) kick in when needed; if a dispute occurs, Briefly auto‑bundles the signed retainer, payment authorization, intake audit trail, device/IP data, and receipts into a ready‑to‑submit evidence packet.

Requirements

Adaptive Risk Scoring & 3DS Orchestration
"As a solo attorney, I want Briefly to automatically step up authentication only for risky payments so that I reduce chargebacks without adding friction for trustworthy clients."
Description

Implement a real-time risk engine that evaluates each client payment and engagement event using signals such as device fingerprint, IP reputation/geolocation, BIN/country mismatch, past dispute history, form completion patterns, order amount, and time-of-day. When the risk score exceeds configurable thresholds, automatically trigger strong customer authentication (e.g., 3-D Secure 2.x challenge) via supported processors (e.g., Stripe, LawPay/Authorize.Net) while allowing frictionless approval for low-risk flows. Support configurable firm-level policies, exemptions, and fallback paths if a processor or 3DS directory server is unavailable. Log all decisions and outcomes for auditability, minimize user friction on mobile, and ensure compliance with relevant network and regional requirements.

Acceptance Criteria
Real-Time Risk Scoring and Decision Outcome
Given a client initiates a payment or engagement event And firm-level risk thresholds and signal weights are configured When the risk engine evaluates device fingerprint, IP reputation/geolocation, BIN–country match, past dispute history, form completion patterns, order amount, and time-of-day Then it produces a risk score (0–100) and decision (approve | require_sca | block) within 300 ms at p95 and 1000 ms at p99 And persists the score, top 5 contributing signals with weights, and decision reason codes with the event And ensures idempotent, consistent decisions across retries within the same idempotency key
Threshold-Based 3DS 2.x Orchestration Across Processors
Given the computed risk score meets or exceeds the firm’s SCA threshold And the payment will be processed via Stripe or LawPay/Authorize.Net When authorization is attempted Then a 3DS 2.x authentication flow is initiated with the selected processor/DS And the client is presented a challenge only if the issuer requires it And on 3DS success the authorization is submitted and receives an approval or decline from the issuer And on 3DS failure or abandonment the transaction is declined with an actionable error And the 3DS result (frictionless/challenged), ECI, liability shift indicator, DS/ACS transaction IDs, and ARes/CRes status codes are captured on the record
Frictionless Approval for Low-Risk Flows
Given the risk score is below the SCA threshold and no blocking policy applies When the client completes checkout on a mobile device over 4G or better Then no 3DS prompt or additional authentication step is shown And at least 95% of such authorizations complete without additional clicks/taps in the payment step And the payment step loads and submits in under 2 seconds p95 and completes end-to-end in under 10 seconds p95
Configurable Policies and Exemptions
Given a firm admin configures risk policies (SCA threshold, block threshold, exemptions by amount/region/customer type/repeat client) via settings or API When the configuration is saved Then it is validated (ranges, conflicts, required fields) and rejected with specific messages if invalid And a new version with actor, timestamp, and diff is created on success And the new policies take effect for subsequent transactions within 60 seconds And exemptions permitted by region/network (e.g., low value, TRA, MIT) are requested when configured and applicable And per-processor overrides can be set and are honored at run time
Resilient Fallback for 3DS/Processor Outage
Given the selected processor or 3DS Directory Server is unavailable, returns error, or exceeds a 5-second timeout When a transaction requiring SCA is processed Then the system automatically retries once and, if configured, fails over to an alternate processor And if no alternate is available, falls back to authorize without SCA only when allowed by firm policy and regional rules, otherwise fails fast And the client is shown a clear, localized message with a retry option And all retries/failovers are correlated under one ID and complete within 30 seconds p95
Complete Decision Logging and Auditability
Given any risk evaluation or 3DS flow is executed When the transaction completes or definitively fails Then an immutable audit record is written including timestamps, event type, risk score, signal values (PII-minimized), thresholds, policy version, processor, 3DS step-up status, challenge outcome, ECI/liability shift, errors, and final decision And firm admins can query these records by client, case, transaction, or date with results under 5 seconds And the records are retained for at least 18 months and included in evidence bundle exports
Regional and Network Compliance
Given a cardholder’s issuer and merchant location determine regional scope When authorizing EEA in-scope transactions Then SCA is performed or a compliant exemption is applied and documented, with exemption type and rationale recorded And out-of-scope transactions follow card network rules with correct ECI and liability shift indicators And quarterly internal compliance review shows 0 critical findings and any medium findings remediated within 30 days
One‑Click Dispute Evidence Packet
"As a case manager, I want Briefly to auto-generate a complete evidence packet when a dispute occurs so that I can submit high-quality proof in minutes instead of hours."
Description

Automatically assemble a dispute-ready evidence bundle that includes the signed retainer (with e-sign certificate), payment authorization, itemized receipt(s), intake responses with timestamps, immutable audit trail, device fingerprint and IP data, and correspondence history. Generate a standardized PDF and a structured evidence manifest (JSON) suitable for direct API submission to supported processors and for manual upload elsewhere. Include automated redaction of sensitive fields, page-numbered exhibits, and a cover letter summarizing the timeline and client consent. Store versioned packets with checksum for integrity and allow rapid regeneration if new artifacts are added.

Acceptance Criteria
One-Click Packet Assembly from Dispute Record
Given a payment dispute is linked to a client matter that contains the signed retainer with e-sign certificate, payment authorization, itemized receipt(s), intake responses with timestamps, immutable audit trail, device fingerprint, IP address, and correspondence history When the user clicks "Generate Evidence Packet" from the dispute or payment view Then the system assembles a packet that includes each required artifact as a distinct exhibit and returns a success confirmation with a packet ID And then any missing required artifact is identified in an error list with a specific reason and remediation hint And then generation completes within 60 seconds for matters with ≤ 200 total pages and ≤ 50 exhibits And then an activity log entry is recorded with user ID, matter ID, dispute ID, start/end timestamps, duration, and outcome
Standardized PDF with Cover Letter and Page-Numbered Exhibits
Given a packet has been generated When the system produces the standardized PDF Then the first page is a cover letter that includes matter ID, dispute ID, client name, payment reference, and a timeline (retainer signed date/time, payment authorization date/time, charge date/time, dispute notice date/time) And then the cover letter summarizes client consent (retainer acknowledgment and payment authorization) with references to exhibit IDs And then each exhibit is labeled "Exhibit <Letter/Number>: <Title>" on its first page and referenced consistently throughout And then every page has a footer with "Page X of Y" and the exhibit identifier And then the PDF is flattened and text-searchable, with embedded fonts, and opens without errors in Acrobat Reader and Apple Preview
Structured Evidence Manifest (JSON) Validation
Given a packet has been generated When the system emits the evidence manifest (JSON) Then the manifest conforms to schema version v1.0 and passes JSON Schema validation with zero errors And then the manifest includes: schema_version, packet_id, matter_id, dispute_id, client_id, generated_at (UTC ISO 8601), generator_version, pdf_sha256, exhibits[] (id, title, type, page_range, file_sha256 if separate), redactions[] (exhibit_id, coordinates/page or field path, reason), and source_artifacts[] (type, id, created_at) And then device_fingerprint and client_ip are present with collection timestamps And then a sandbox API adapter for each supported processor validates and accepts the manifest (HTTP 200/202) in a dry-run submission
Automated Redaction of Sensitive Data
Given artifacts contain sensitive fields (e.g., SSN, PAN, CVV, bank account/routing numbers, DOB, access tokens) When the packet is generated Then the PDF exhibits are irreversibly redacted so that full values are not recoverable from visual content, copy/paste, or text extraction And then SSN shows only last 4; PAN shows BIN + last 4; CVV is fully removed; bank account/routing show only last 4; DOB shows MM/YYYY at most And then redaction annotations do not obscure signatures, checkboxes, or consent text And then the manifest includes a redactions[] entry for each applied redaction with reason = "PII" or "PCI" And then a redaction QA check reports 0 unmasked occurrences of flagged patterns across all exhibits
Versioning and Integrity Checksum
Given a packet is stored When the packet is saved to the repository Then the system assigns a monotonically increasing version number starting at 1 and computes SHA-256 checksums for the PDF and JSON manifest And then the packet record stores packet_id, version, created_by, created_at, pdf_sha256, manifest_sha256, and a write-once integrity flag And then retrieving a stored packet verifies the checksums before download; on mismatch, access is blocked and an alert is logged And then any modification (e.g., regeneration) creates a new version; previous versions remain immutable and retrievable
Rapid Regeneration When New Artifacts Are Added
Given new artifacts (e.g., additional receipt or correspondence) are added to the matter after a packet exists When the user clicks "Regenerate Packet" Then a new packet version is created that includes the new artifacts and updates exhibit numbering sequentially without gaps And then the manifest updated_at and exhibits[] reflect the new ordering and checksums And then regeneration completes within 30 seconds for incremental changes affecting ≤ 10 exhibits And then an audit log records the prior and new packet version IDs, the artifacts added/removed, user, and timestamps
Submission-Ready Packaging and Access Controls
Given a packet is generated successfully When the user selects "Download Evidence" Then the system provides a ZIP containing the standardized PDF and the JSON manifest, named with packet_id and version And then the UI displays a copyable packet_id and a secure link that expires in ≤ 24 hours And then only users with firm role = Attorney or Admin can generate or download packets; actions by others are blocked and logged And then, for supported processors, clicking "Send via API" performs a sandbox submission using the manifest and returns success/failure with trace ID
Immutable Intake‑to‑Payment Audit Log
"As a firm owner, I want a provable audit trail of client intake and authorization so that I can substantiate client consent and services when a chargeback arises."
Description

Create an append-only, tamper-evident event timeline that captures key milestones from first questionnaire interaction to payment, including field edits, consent checkpoints, document views, signature events, IP/device metadata, and payment gateway responses. Chain events with cryptographic hashes, timestamp them using a trusted source, and store them in encrypted, write-once storage. Provide export to PDF/CSV with selective redaction, link events to evidence exhibits, and expose a read-only view in the Dispute Shield console and within the auto-bundled packet.

Acceptance Criteria
End-to-End Append-Only Event Capture
Given a client intake session from first questionnaire interaction through payment completion for a single matter When the client performs actions including questionnaire start, per-field edits, consent checkpoints, document views, e-signature, and payment Then the audit log records an event for each action with event_type, case_id, session_id, actor_id (nullable), role, ip_address, user_agent, device_fingerprint, and event_sequence And field_edited events include field_id, previous_value, new_value, editor, and validation_result And consent_captured events include consent_id, consent_text_version, method (checkbox, typed name, clickwrap), and outcome And document_viewed events include document_id and version And signature events include signer_id, signature_method, status, and signature_request_id And payment events include amount, currency, gateway, transaction_id, and outcome And querying the log by case_id returns a strictly ordered timeline by event_sequence with no gaps or duplicates And any attempt to update or delete a persisted event is rejected and logged
Cryptographic Hash Chain and Tamper Evidence Verification
Given an audit log timeline for a case When chain validation recomputes hashes over the ordered events Then each event contains its own hash and the previous_event_hash And event.hash equals SHA-256(canonical_event_payload || previous_event_hash) And the first event has previous_event_hash = null and a recorded genesis_hash And any modification to an event or order causes validation to fail and identifies the first invalid index
Trusted Timestamping with External Authority
Given creation of any audit event When the event is persisted Then the event includes a timestamp issued by a trusted source and the timestamp_source metadata (e.g., TSA, NTP) And when a RFC 3161 TSA is reachable, the event stores a valid time-stamp token (TST) and TSA certificate chain And when TSA is unavailable, the event stores an NTP-synchronized time and marks source=fallback, and the fallback usage is recorded in system logs
Encrypted Write-Once Storage (WORM) Enforcement
Given audit events persisted to storage When a privileged or non-privileged user attempts to update or delete an existing event via API, console, database, or storage layer Then the operation is blocked by write-once controls, returns an error (e.g., 403 or 409), and is itself audited And stored bytes are encrypted at rest and unreadable without authorized keys And successful writes are append-only and increase the event_sequence without altering prior bytes
Selective Redaction Export to PDF/CSV with Verifiable Signatures
Given an authorized user requests an audit export for a case with a selected date range and a redaction profile When the export is generated to PDF and CSV Then the export contains the ordered events, a hash-chain summary, and a validation report (chain_valid true/false and first_invalid_index if any) And fields flagged by the redaction profile are masked in CSV and visually redacted in PDF, with a redaction legend listing each rule applied And the PDF is digitally signed; the CSV is accompanied by a checksum manifest and detached signature And the export request, filters, redaction profile, and download action are logged and linked to the case
Read-Only Timeline in Dispute Shield with Exhibit Linking
Given an authorized user opens the Dispute Shield console for a case When viewing the audit log tab Then the timeline renders in read-only mode with filters (event_type, date range) and search, with no edit or delete affordances And selecting an event reveals its details and a link to its evidence exhibit ID(s) And generating a dispute evidence packet includes the same timeline snapshot and exhibits with identical hashes to the stored events
Payment Authentication and Gateway Response Capture
Given a payment attempt that may invoke strong customer authentication (e.g., 3-D Secure) When the payment gateway returns its response(s) Then the audit log stores AVS result, CVV result, response codes, and gateway transaction identifiers And for 3-D Secure flows, the log stores version, ECI, DS/ACS transaction IDs, challenge status, and liability_shift flag And the payment event is linked to the preceding intake and signature events via case_id and session_id, and includes the payer's ip_address and device_fingerprint at authorization
Processor Dispute Webhooks & Case Sync
"As an operations lead, I want disputes to auto-appear with deadlines and pre-attached evidence so that nothing is missed and responses go out on time."
Description

Integrate webhook listeners for supported processors to detect dispute lifecycle events (opened, needs response, evidence submitted, won/lost). On receipt, automatically create or update a Briefly Dispute case, attach the pre-built evidence packet, set response deadlines, and notify assigned staff. Support direct evidence submission via API where available, track submission receipts, and synchronize status and outcome details back to the case. Provide idempotent processing, retries, and secure signature verification for all incoming webhooks.

Acceptance Criteria
Secure Webhook Signature Verification and Replay Protection
Given a webhook from a supported processor with a valid signature and timestamp within a 5‑minute tolerance, When the listener receives the request, Then the signature is verified against the configured secret, the timestamp is validated to prevent replay, the event is accepted, HTTP 200 is returned within 2 seconds, and the event is queued for processing. Given a webhook with an invalid signature or stale timestamp, When the listener receives the request, Then the system rejects the event, returns HTTP 401/400, records a security audit entry with reason, and does not persist or enqueue the payload. Given a duplicate delivery with the same processor event_id within 24 hours, When the listener receives the request, Then the system returns HTTP 200 and performs no duplicate side effects (no new case, attachments, notifications, or submissions).
Idempotent Dispute Event Processing and Retry Policy
Given any dispute lifecycle event identified by processor + event_id, When the processor retries delivery or the worker reprocesses the event, Then side effects are at‑most‑once: no duplicate Briefly Dispute cases, attachments, status updates, notifications, or evidence submissions are created. Given a transient downstream failure (e.g., DB deadlock, processor 5xx), When processing an event, Then the system retries up to 5 times with exponential backoff (1s, 2s, 4s, 8s, 16s), preserves ordering per dispute_id, and marks the attempt history; after max retries the event is moved to a dead‑letter queue and an alert is raised to ops. Given a permanent validation error (e.g., missing required mapping), When processing an event, Then retries are not attempted, the event is marked Failed‑Validation with a human‑readable reason, and a task is created for remediation.
Create/Update Briefly Dispute Case on Processor Events
Given a "dispute_opened" event referencing a known payment and client, When the event is processed, Then a Briefly Dispute case is created if none exists, linked to the payment and client matter, and fields are populated (processor, dispute_id, amount, currency, reason_code, created_at). Given subsequent lifecycle events (e.g., needs_response, evidence_submitted, won, lost, closed) for the same dispute_id, When they are processed, Then the existing case is updated with status, timestamps, and timeline entries without creating a duplicate case. Given an unsupported or unknown event type, When it is received, Then the system logs the event, stores raw payload for audit, and ignores it without failing the webhook endpoint.
Auto-Bundle and Attach Evidence Packet
Given a dispute case is created or transitions to Needs Response, When background assembly runs, Then a versioned evidence packet (PDF/ZIP) is generated within 2 minutes containing: signed retainer, payment authorization, intake audit trail, device/IP metadata, and receipts, and it is attached to the case with a SHA‑256 checksum. Given any expected artifact is missing, When assembly runs, Then the packet index lists the missing item with reason, a remediation task is created for assigned staff, and assembly completes without failure. Given the packet is regenerated, When assembly runs again, Then a new version is created without overwriting prior versions, and the case history reflects the change.
Set Response Deadline and Reminders
Given an event contains a response_due_at or SLA window, When the case is created/updated, Then the system sets the response deadline in UTC and displays it in the firm’s default timezone, calculates remaining time, and records the source of the deadline. Given the deadline is within 72 hours, When the case is updated, Then the case priority is set to Urgent and escalation rules apply. Given T‑72h, T‑24h, and T‑2h before the deadline, When scheduled triggers fire, Then assigned staff receive in‑app and email notifications within 60 seconds; acknowledgments suppress subsequent reminders, non‑acknowledgment continues reminders.
Direct Evidence Submission and Receipt Synchronization
Given the processor supports evidence submission via API and a case is in Needs Response with a ready packet, When a user initiates Submit Evidence or auto‑submit is enabled for that processor, Then the system uploads the packet and required metadata, captures a processor submission_id/receipt, sets case status to Evidence Submitted, and stores request/response payloads. Given the processor returns validation errors (e.g., missing field, file too large), When submission is attempted, Then the user is shown the error details, the case remains in Needs Response, errors are logged, and a Retry Submission action is available. Given a webhook later indicates submission accepted or changes requested, When processed, Then the case reflects Submitted/Action Required with timestamps, and a task is created for any required updates.
Dispute Outcome Sync and Case Closure
Given a dispute_outcome event of won or lost is received, When processed, Then the case status updates to Closed with outcome = Won/Lost, final financial fields are recorded (recovered_amount/chargeback_amount/fees), a final activity entry is added, and assigned staff are notified. Given outcome = Won, When accounting sync runs, Then fee reversals and ledger adjustments are posted per mapping; Given outcome = Lost, outstanding balance adjustments and a follow‑up task (e.g., payment plan or write‑off review) are created. Given 30 days elapse after a Closed outcome with no new events, When the archival job runs, Then the case is archived per retention policy and remains searchable via audit logs.
Dispute Command Center
"As a paralegal, I want a single place to review, finalize, and submit dispute evidence so that I can manage multiple cases efficiently and meet response deadlines."
Description

Provide a consolidated UI for managing disputes: overview dashboard, SLA countdowns, status filters, outcome analytics, and per-case workspaces. Allow users to review/edit the evidence packet, add custom exhibits or attorney statements, apply redactions, and submit directly to processors when supported. Include role-based access controls, activity logs, email/SMS/Slack notifications, and templates for common responses. Optimize for mobile and ensure quick loading for large documents with streaming previews.

Acceptance Criteria
Dashboard Overview, Filters, and SLA Countdown
Given disputes exist across multiple statuses and SLA due dates When the user opens the Dispute Command Center dashboard on mobile (4G) or desktop (broadband) Then above-the-fold content renders within 2s on broadband and 5s on 4G, with full dashboard interactive within 3s and 7s respectively And status tiles display counts that match the backend within ±1 record And each dispute card shows an SLA countdown (d:hh:mm) accurate to ±1 minute vs server time And SLA badge colors follow rules: >48h green, 24–48h amber, <24h red Given the user applies Status=Needs Response and Processor filters When Apply is clicked Then the list updates within 300ms client-side and completes server filtering within 1s And the URL reflects the active filters for shareability and is restored on reload And Clear All removes filters and restores defaults within 300ms Given a 30/60/90 day range is selected in Analytics When metrics load Then Win Rate, Chargeback Rate, and Avg Response Time match backend aggregates within ±0.5% And Export CSV completes within 3s and the file rows and metrics match the on-screen dataset
Case Workspace: Evidence Packet Review, Edit, and Redaction
Given a dispute with an auto-bundled evidence packet (retainer, payment authorization, intake audit trail, device/IP data, receipts) When the user opens the case workspace Then all packet items are listed with type, size, and source and the order matches the default template And first-page preview of each document streams and renders within 1.5s on 4G; subsequent pages lazy-load in <800ms per page Given the user drags an exhibit to reorder When the drag is released Then the new order is persisted and reflected in the export and submission packet Given the user uploads a custom exhibit (PDF/JPG/PNG) up to 200MB When upload starts Then a progress bar, file hash, and virus scan status are shown; on scan pass the file is available and stored encrypted at rest; on fail the file is rejected with an error Given the user edits the Attorney Statement When Save is clicked or autosave triggers every 10s Then the statement (up to 10,000 chars, rich text limited to bold/italic/lists) is versioned with timestamp and author and can be restored from history Given PII must be removed When the user applies box or search-and-redact to a PDF Then redactions are visible in preview, logged with selector and author, and are irreversible in exported/submitted PDFs while the original is preserved securely Given an unsupported file type is added When preview is requested Then a download-only fallback is offered with a warning and the item is still included in the packet if allowed by policy
Direct Submission to Payment Processors with Fallback Download
Given a dispute linked to a processor that supports API submissions When the user clicks Submit Then required fields and packet size/format are validated against processor limits And the request is sent with an idempotency key and times out after 15s with up to 2 retries (exponential backoff) And on success a processor Submission ID is displayed and stored; the dispute status updates to Submitted and the SLA clock pauses Given the processor returns an error When retries are exhausted Then a descriptive error is shown, the event is logged, and the user is offered a Download Evidence Packet fallback Given a dispute with a non-supported processor When the workspace loads Then the Submit button is disabled with tooltip "Direct submit not supported" and a Download Evidence Packet (ZIP) is available containing the compiled PDF, exhibits, and a cover letter Given a submission completed When the processor posts a webhook/callback Then the case timeline updates within 10s with the new status (e.g., Under Review, Won, Lost) and any reference IDs; notifications are triggered per preferences
Role-Based Access Control and Activity Logging
Given organization roles (Owner, Attorney, Staff, Viewer) are assigned When a Viewer opens a dispute Then read-only access is enforced and Edit/Submit actions are hidden/disabled; direct URL access to restricted actions returns 403 Given a Staff member attempts to manage templates or change org settings When the action is invoked Then permission is denied with an explanatory message and is logged Given any user performs a sensitive action (edit packet, apply redaction, submit, download export, change status) When the action completes Then an audit log entry is written within 3s including actor, timestamp (UTC), IP/device, entity, before/after summary, and hash-chained sequence number; logs are append-only and exportable to CSV Given an Owner views the audit trail When filters by user, action, or date range are applied Then results load within 1s and the hash chain verifies without gaps
Multi-Channel Notifications (Email/SMS/Slack) and Preferences
Given a new dispute is created or an SLA threshold is crossed (24h and 4h remaining) When event processing runs Then opted-in users receive notifications within 60s for SMS, 120s for Email, and 15s for Slack in 95th percentile cases And content includes dispute ID, processor, amount, SLA time remaining, and a secure deep link (token TTL 15m) to the case workspace; expired links require re-auth Given a user updates notification preferences When toggles for channel/event are changed Then changes persist immediately and are honored on the next event; per-user throttling ensures no more than one reminder per threshold per dispute Given a submission succeeds or fails When the processor status changes Then a single outcome notification is sent per user per dispute and delivery status is logged; bounces/unsubscribes suppress future sends
Response Templates with Merge Fields and Versioning
Given an Attorney creates a response template with merge fields (e.g., {{client.name}}, {{matter.amount}}, conditional blocks) When Save is clicked Then validation flags unresolved fields and disallows save unless defaults are provided; version is stored with author, timestamp, and change notes Given a Staff user applies a template in a case workspace When Preview is clicked Then a populated draft renders within 1s with sample or case data; applying inserts the content into the Attorney Statement and attaches to the packet Given permissions: Owner/Attorney can create/edit org-shared templates; Staff can create personal templates; Viewer cannot use templates When actions are attempted Then permissions are enforced and audited Given many templates exist When the user searches or filters by tag Then results return within 500ms and cloning a template creates a new draft retaining tags Given the packet is exported or submitted When the template-generated document is included Then it is embedded as a PDF with correct pagination and fonts and appears in the evidence index
PII Minimization & Secure Evidence Storage
"As a compliance-conscious attorney, I want sensitive client and payment data secured and minimized so that dispute handling doesn’t increase my regulatory risk."
Description

Enforce privacy-by-design for all Dispute Shield artifacts. Avoid storing PAN or CVV; rely on processor tokens and masked card data. Encrypt evidence and audit logs at rest and in transit, enable field-level redaction for sensitive PII, and gate access behind role-based permissions with just-in-time access requests. Provide configurable retention policies (e.g., purge X days after dispute closure), immutable access logs, and quarterly data hygiene jobs. Align with PCI DSS responsibilities and SOC 2 controls applicable to stored artifacts.

Acceptance Criteria
No PAN/CVV Storage and Tokenization Enforcement
- Given any payment input is received from the UI or API, When the data is persisted, Then only the processor token, card brand, expiry month/year (if required), and last4 are stored; PAN and CVV are never written to databases, logs, caches, analytics, or error traces. - Given scheduled DLP scans on databases, logs, and object stores, When PAN/CVV regex patterns are evaluated nightly, Then zero matches are found; if matches > 0, the job fails, emits a Sev-1 alert, and blocks the next deployment. - Given a payment processor response, When tokenization fails, Then the transaction is aborted, no PAN/CVV is stored anywhere, and the error message contains no sensitive substrings. - Given an evidence packet export, When generated, Then payment details are masked (e.g., **** **** **** 1234) and include only the processor token reference; raw PAN/CVV are absent in file content and metadata.
Encryption of Evidence and Audit Logs at Rest and In Transit
- Given evidence and audit records are stored, When written to persistence, Then encryption at rest uses AES-256-GCM (or stronger) with KMS-managed keys, key rotation ≤ 365 days, and per-tenant data keys; direct plaintext reads are technically impossible. - Given any network transfer of evidence or audit logs, When initiated, Then TLS 1.2+ with modern cipher suites and PFS is enforced; sub-TLS1.2 connections are rejected and logged. - Given a key compromise drill, When an encryption key is disabled/rotated, Then new writes use the new key immediately and attempts to decrypt with disabled keys fail with 403; key events are auditable. - Given independent security testing, When the latest pen test and config validation complete, Then there are zero critical/high findings related to at-rest or in-transit encryption.
Field-Level Redaction Controls in Evidence Packets
- Given redaction settings for sensitive fields (e.g., SSN, DOB, address, email, phone), When an evidence packet (PDF/JSON) is generated, Then configured fields are replaced with [REDACTED] or masked per policy and appear consistently across all formats and previews. - Given a user with RedactionAdmin role, When they change a redaction policy, Then the change is versioned, recorded immutably, and takes effect for new packet generations within 5 minutes. - Given an approved one-time override with purpose and ticket ID, When an unredacted packet is requested, Then access requires time-bound approval (≤ 60 minutes), the packet is watermarked "Sensitive - Not for Client", and all access is logged. - Given document metadata inspection, When the exported files are analyzed, Then no raw sensitive values appear in embedded metadata, annotations, or revision history.
RBAC with Just-in-Time Access for Dispute Artifacts
- Given defined roles (Attorney, Paralegal, Support, Admin), When listing, viewing, or downloading dispute artifacts, Then only principals with DisputeEvidenceViewer/Downloader permissions can perform the action; others receive 403. - Given a user without standing access, When submitting a JIT request specifying scope and duration, Then approval by Admin or Attorney is required; upon approval, access is granted for ≤ 60 minutes and auto-revoked on expiry. - Given elevated access is active, When the session is idle for 10 minutes, Then re-authentication with MFA is required before further actions. - Given any access attempt, When evaluated, Then decision logs capture user, role, scopes, timestamp, IP/device fingerprint, action, and outcome and are appended immutably.
Configurable Retention and Automated Purge Post-Dispute
- Given a global or matter-level retention period (e.g., 30/60/90 days), When a dispute is marked Closed, Then all associated artifacts are scheduled for purge at the period end. - Given legal hold is applied, When the purge job runs, Then artifacts under hold are excluded until the hold is lifted; holds are auditable. - Given purge execution completes, When validated, Then primary stores and replicas contain zero artifact records; backups containing the artifacts are flagged for lifecycle purge within ≤ 30 days; a deletion certificate is generated and stored. - Given retention settings are edited, When a value < 7 days or > 7 years is entered, Then validation blocks the change and prompts for a compliant value.
Immutable Access Logs with Tamper Detection
- Given access logs are written, When persisted, Then they are stored append-only (WORM or hash-chained) with synchronized time (NTP) and cannot be edited or deleted prior to retention expiry. - Given hourly integrity verification, When hash chains are validated, Then any mismatch triggers a Sev-1 alert within 5 minutes and prevents further log writes until resolved. - Given an audit export request, When fulfilled, Then the export includes complete log records, hash chain proofs, and signatures, and is delivered read-only to auditors. - Given a log retention policy (e.g., 1 year), When the period elapses, Then logs expire per policy; premature deletion attempts are blocked and logged.
Quarterly Data Hygiene and Compliance Governance
- Given scheduled quarterly hygiene jobs, When they run, Then reports include counts of orphaned artifacts, expired tokens, stale audit entries, and policy drift; ≥ 95% of identified items are remediated within the same quarter. - Given a hygiene job failure, When detected, Then on-call is alerted within 5 minutes and the job retries up to 3 times with exponential backoff; unresolved failures create an incident ticket within 24 hours. - Given PCI DSS and SOC 2 applicability, When the control responsibility matrix is reviewed quarterly or upon scope change, Then all applicable controls for stored artifacts are mapped with owner, evidence, and status; zero unmapped applicable controls; updates are published within 10 business days of change. - Given an auditor evidence request, When generated from the compliance portal, Then artifacts (architecture/data flow, key management configs, DLP scans, access reviews, hygiene reports) are retrievable within 1 hour and dated within the last 12 months.
Reason‑Code Evidence Templates & Guidance
"As a practitioner new to disputes, I want reason-code–specific guidance and prefilled templates so that my submissions align with what reviewers expect and have a higher win rate."
Description

Map card network and processor reason codes to curated evidence checklists and narrative templates. Dynamically tailor the auto-bundled packet contents and cover letter to the detected reason code (e.g., services not provided, fraud—card absent, recurring billing). Provide inline guidance and examples, auto-populate fields from case data, and flag missing items. Maintain a centrally managed ruleset that can be updated without code deployments to reflect evolving network requirements.

Acceptance Criteria
Auto-tailored evidence packet by reason code
Given a dispute with reason code "Services Not Provided" (e.g., Visa 13.1) When the system generates the evidence packet Then it includes the mapped checklist items: signed retainer, payment authorization, intake audit trail, communications/proof of service, and receipts And the cover letter uses the "Services Not Provided" narrative template with auto-filled case data And items not in the mapped checklist are excluded from the packet And the cover letter and packet metadata reference the detected reason code Given a dispute with reason code "Fraud—Card Not Present" (e.g., Visa 10.4, Mastercard 4837) When the system generates the evidence packet Then it includes device fingerprint and IP, 3‑D Secure/strong auth data when available, signed retainer, payment authorization, intake audit trail, and receipts And it excludes proof-of-service artifacts not mapped for this reason code Given a dispute with reason code "Recurring Billing Canceled" When the system generates the evidence packet Then it includes cancellation confirmation, last-billing date, terms of cancellation, payment authorization, signed retainer, and receipts And the narrative template references the cancellation timeline and policy
Contextual guidance and missing-item flags
Given a reason-code-specific checklist is displayed When a required item has no matching case data or upload Then the item is flagged as Missing (Required) with inline guidance text and a link to an example Given a user attaches or maps the required evidence to the flagged item When the checklist refreshes Then the flag clears and the item status changes to Present with timestamp and user attribution Given one or more required items remain missing When the user attempts to submit the packet Then submission is blocked and a consolidated list of missing items is shown And if the ruleset allows justification in lieu of a document, providing a justification unblocks submission
Auto-population of narrative templates from case data
Given a case with client name, matter ID, signed retainer timestamp, payment authorization details, service dates, device/IP data When generating the cover letter and any narrative fields Then all corresponding placeholders are auto-populated with case data without manual entry And date/time fields render in the practice’s configured timezone and display format And fraud-related narratives include device/IP and authentication data only for applicable reason codes And recurring-billing narratives include cancellation date and policy terms when applicable And any unmapped placeholder is surfaced as [MISSING] and listed in a task panel
Centrally managed ruleset updates without deployment
Given an admin edits the reason-code mapping for "Visa 13.1" to add a new required item and updates narrative copy When the change is published Then a new ruleset version is created with version number, editor, timestamp, and change summary in an audit log And newly generated packets use the new version within 5 minutes without any code deployment And admins can rollback to a prior version, after which new generations use the rolled-back version And in-progress disputes retain their originally bound version unless the user opts to rebind to the latest
Network and processor-specific overrides with precedence
Given rules exist at default, network-level (e.g., Visa/Mastercard), and processor-level (e.g., Stripe, Adyen) When generating an evidence packet for a Visa dispute processed by Stripe Then the processor-level Visa/Stripe mapping is applied if present And if no processor-level rule exists, the Visa network-level rule is applied And if no network-level rule exists, the default rule is applied And the applied rule source and version are recorded in packet metadata
Performance, output integrity, and ordering
Given a case with up to 50 evidence items totaling up to 25 MB When generating the auto-bundled packet Then 95th percentile generation time is under 10 seconds and median under 3 seconds And the output is a single PDF (or ZIP if non-PDF artifacts exist) with deterministic ordering: cover letter, checklist, evidence items in ruleset-defined order And all referenced files are present without corruption; a checksum for the bundle is recorded And on transient failure the system retries up to 2 times and surfaces an actionable error if still unsuccessful

Bank Pay Saver

Prominently offer low‑fee bank transfers for larger retainers. Instant account verification, NSF/retry workflows, and clear settlement ETAs keep clients informed. Firms can optionally delay countersign or work start until funds clear, preventing unfunded engagements while cutting payment costs.

Requirements

Preferred Bank Transfer Checkout
"As a client paying a large retainer, I want a clearly presented low-fee bank transfer option so that I can minimize costs and complete payment quickly on my phone."
Description

Prominently present ACH/bank transfer as the recommended payment method for retainers above a configurable threshold, with clear fee comparisons versus card payments. Dynamically prioritize the bank option in mobile and desktop checkout, surface plain-language cost savings, and preselect it when the amount exceeds the firm-defined limit. Integrates with Briefly’s intake-to-e‑sign flow, preserving entered client data and retainer terms while transitioning seamlessly into payment. Ensures accessibility and WCAG-compliant UI, supports one-tap selection, and records the user’s payment method choice in the matter timeline for auditability. Outcome: higher adoption of low-fee payments, reduced payment costs, and faster completion on mobile.

Acceptance Criteria
Bank Transfer Preselected Above Threshold
Given a firm-defined bank transfer threshold is set and the retainer amount entered exceeds that threshold When the checkout page renders Then the bank transfer (ACH) method is preselected and placed first in the payment options list And the card method is still available but not selected And the preselection occurs without page reload and within 300ms of render And if the amount is later reduced below the threshold without any manual selection by the user Then the system de-selects the ACH preselection and applies the platform’s default selection behavior
Responsive Prioritization and One‑Tap Selection
Given the checkout is viewed on a mobile device or desktop When the payment options are displayed Then the bank transfer option is visually prioritized (first, larger tap target, recommended badge) when the amount exceeds the threshold And a single tap/click on a payment option selects it and updates fee/savings details within 200ms And the layout remains readable and functional at 320px–1440px widths without horizontal scroll
Fee Comparison and Cost‑Savings Messaging
Given card and bank transfer fee schedules are configured And a retainer amount is present When payment options are displayed Then the UI shows estimated fees and total cost for each method in the user’s currency with two‑decimal precision And when ACH is selected, a plain‑language message displays the exact amount saved versus card (e.g., “Save $X.YZ vs card”) if savings > $0.00 And the savings message hides when savings ≤ $0.00 And all values recalculate within 200ms after any amount change
Seamless Intake‑to‑Payment Transition with Data Preservation
Given the user has completed Briefly intake steps and retainer terms are set When the user proceeds to the payment step and selects a payment method Then all previously entered client data and retainer terms persist without re‑entry And payer name and email are prefilled from intake where available And if the user cancels or navigates back from payment, the intake and payment selection states are restored And no duplicate intake records are created during the transition
Accessibility and WCAG‑Compliant Payment Selection
Given a user navigating with keyboard or screen reader When the payment methods are presented Then the options are exposed as a single radiogroup with accessible names that include fee and savings information And focus order is logical, Enter/Space toggles selection, and focus is visible And status/error changes (e.g., invalid amount) are announced via aria‑live politely And text and controls meet WCAG 2.1 AA contrast and touch target size (≥44px) requirements
Payment Method Choice Logged to Matter Timeline
Given a user selects a payment method in checkout When the selection is confirmed (selection persisted or payment initiated) Then an immutable timeline entry is created for the matter recording: payment method, retainer amount, timestamp (UTC), user identity (or client ID), device type, and the threshold value in effect And any subsequent method change prior to payment creates an additional entry with the same fields And the entries are visible in the matter timeline within 5 seconds and cannot be edited
User Override and Selection Persistence
Given the amount exceeds the threshold and ACH is preselected When the user manually selects card instead Then card remains selected for the session despite subsequent amount edits, step changes, or soft reloads And the system does not auto‑switch back to ACH unless the user explicitly selects it And savings/fee summaries update to reflect the currently selected method
Instant Bank Verification
"As a client, I want to verify my bank account instantly so that I can complete intake and payment without delays or extra steps."
Description

Enable instant account verification via secure bank authentication with fallback to micro-deposit verification when instant auth is unavailable. Support personal and business checking/savings, detect account type, and store tokens/identifiers securely with encryption at rest and in transit. Provide real-time validation of account/routing numbers, name matching, and account status checks to reduce returns. Integrates with Briefly’s questionnaire completion so clients verify their bank immediately before e‑sign, minimizing drop-off. Includes consent capture, audit logs, and compliance with applicable banking and data protection standards. Outcome: clients finish payment setup in minutes without waiting days.

Acceptance Criteria
Instant Bank Auth Success within Questionnaire Flow
Given a client has completed the final questionnaire section and selects Bank Transfer (ACH) And the client’s selected bank supports instant authentication via the vendor When the client clicks Verify instantly Then the authentication modal loads within 2 seconds And the client can search/select their bank, authenticate, and grant consent And upon success, the system receives a verified account token, account holder name, account type, routing last4, and account last4 And the UI displays the bank name with masked last4 and a Success state And the e‑sign step is enabled And the time from clicking Verify instantly to receiving the verified token is ≤ 3 minutes for 95% of sessions
Fallback to Micro‑Deposit When Instant Unavailable
Given instant authentication is unavailable, fails, or is declined by the client When the system offers fallback verification Then the client can input routing and account numbers And the routing number is validated against the ABA registry in real time; invalid values block continuation with an inline error And basic account number format heuristics validate length/pattern; failing inputs block continuation And the UI displays an ETA of 1–2 business days and next steps And upon submission, two micro‑deposits are initiated and verification status is set to Pending with a timestamp And the client receives email/SMS instructions to return and confirm deposit amounts And entering the correct two deposit amounts within 10 days marks the account Verified And three failed confirmation attempts lock the verification and require a restart
Account Type Detection and Support
Given an account is verified via instant authentication When account metadata is returned from the provider Then the system records subtype (checking/savings) and owner type (personal/business) And unsupported account types (credit, prepaid, loan, investment) are rejected with a clear error message And the payment method is tagged with account type metadata for downstream NSF/settlement workflows And the firm sees the detected owner type in the admin detail view
Name Matching and Ownership Checks
Given the client’s legal name(s) from the intake and the owner name(s) returned by the provider When verification completes Then names are normalized (case/whitespace/punctuation) and a match score is computed And if score ≥ 0.80, Name Match = Pass and setup proceeds And if 0.60 ≤ score < 0.80, the client must attest ownership; capture attestation text and timestamp; mark as Review And if score < 0.60, block setup with guidance to use a matching account or contact the firm And for business accounts, allow matching against the provided business/DBA name And all inputs, score, decision, and user identifiers are written to the audit log
Secure Tokenization and Storage
Given the system receives verified bank details When persisting payment method data Then only provider tokens and non‑sensitive metadata are stored; raw routing/account numbers are not persisted And all stored tokens/identifiers are encrypted at rest with KMS‑managed AES‑256 keys And all in‑transit communications use TLS 1.2+ with strong ciphers And access to tokens is restricted to authorized services/users via RBAC, with audit logging of access And logs contain only masked account identifiers (last4); attempts to log full numbers are prevented by automated checks And encryption keys are rotated at least every 12 months or on compromise And CI security tests validate encryption-at-rest, TLS configuration, and log redaction on each release
Consent Capture and Auditability
Given a client is about to start bank verification When the consent screen is presented Then the consent text includes authorization for ACH verification/debits, data sharing with the provider, and revocation instructions And the client must explicitly accept before proceeding to authentication And the system records consent version, timestamp, IP, user agent, client ID, and locale And audit logs capture events: start, consent accepted, provider selected, success, failure, fallback chosen, micro‑deposit initiated, verified, locked And authorized staff can export an audit report by matter within 60 seconds And audit records are immutable and retained for at least 2 years
Real‑Time Validation and Account Status Checks
Given a client enters routing/account numbers manually or instant auth returns account metadata When validation runs Then the routing number is confirmed active and ACH‑enabled; inactive values block submission with an inline error And the account status (open/closed/restricted) is queried; closed/restricted accounts are blocked with a specific error code and guidance And non‑ACH‑enabled or non‑transactional accounts are rejected with a clear reason And each failure returns a machine‑readable reason code for analytics and support And on success, Verification Status is set to Verified and made available to payment orchestration within 1 second
Funds-Cleared Engagement Gate
"As a firm owner, I want engagement to be gated until funds clear so that we avoid starting work on unfunded retainers."
Description

Allow firms to configure rules that delay countersignature of retainers and/or work start until ACH funds are confirmed settled. Provide per-matter and firm-wide settings, with optional manual override by authorized roles and full audit trail. Automatically release countersignature and trigger task/workflows when settlement confirms; if payment fails, hold signature, notify stakeholders, and prompt retry. Integrates with Briefly’s e‑sign module and task automation, ensuring that engagement only proceeds when funds are secured. Outcome: prevents unfunded engagements and reduces financial risk without adding manual steps.

Acceptance Criteria
Firm-Wide ACH Settlement Gate for Countersign
Given a firm has enabled "Hold countersign until ACH funds settle" at the firm level And a client signs a retainer and initiates payment via ACH When the payment status is Pending or Processing Then the countersignature is not applied And the retainer status displays "Pending Settlement" to firm users And automations with trigger "On Countersign" do not execute And an audit log entry records the hold state with matter ID, user, timestamp, and payment ID
Per-Matter Engagement Gate Overrides
Given a matter-level Engagement Gate setting is configured to one of {Hold Countersign, Hold Work Start, Disabled} And a conflicting firm-level default exists When the retainer is sent and client signs Then the matter-level setting prevails And an "Override active" indicator is shown in the matter header And the applied rule value is saved on the matter record and visible in the audit log When set to Hold Countersign Then countersign is withheld until settlement and no "On Countersign" automations run When set to Hold Work Start Then countersign applies immediately after client signs but work-start-gated tasks/workflows do not start until settlement When set to Disabled Then the engagement proceeds with no holds regardless of payment method
Authorized Manual Override with Full Audit Trail
Given an engagement is on hold due to ACH settlement rules When a user with role in {Managing Attorney, Billing Admin} clicks "Override" and enters a required reason (min 10 chars) Then the system releases the selected hold (countersign and/or work start) immediately And creates an immutable audit entry capturing user ID, role, reason, prior state, new state, timestamp, IP, matter ID, payment ID And notifies assigned team and the client of the override When a user without the required role attempts override Then the action is blocked with an authorization error and no state change or notification occurs
Automatic Release and Workflow Triggers on ACH Settlement
Given an engagement is held awaiting ACH settlement And a payment intent is linked to the retainer When the processor sends a Settled/Success webhook for that payment Then the system idempotently applies pending actions exactly once: applies countersign if held and starts all work-start-gated tasks/workflows And updates the matter status to Engaged and the retainer status to Countersigned (if applicable) And sends notifications to the client and assigned team And completes these actions within 60 seconds of receiving the settlement event When duplicate settlement events are received Then no duplicate countersignatures, tasks, or notifications are produced
NSF/Failure Handling and Retry Prompt
Given an engagement is on hold due to an ACH payment When the processor returns a failure/NSF code for the payment Then countersign remains withheld and work-start-gated tasks/workflows remain blocked And the client receives an email and in-app notice within 1 minute explaining the failure and offering a "Retry bank payment" action And the firm receives a notification with the failure code and link to the matter And the system schedules up to the configured number of retries (default 2) with the configured spacing (default 24 hours) unless the firm cancels retries When retries are exhausted or the firm cancels Then the matter shows Payment Failed status and no gated automations run until a successful payment is captured
Settlement ETA and Status Visibility
Given a client initiates ACH payment from a retainer When viewing the client portal or the firm matter view Then the UI displays payment status (Initiated, Pending, Settled, Failed) and an estimated settlement date/time with timezone And the ETA updates if the processor provides new information And a status timeline shows key events (Initiated, Debited, In Transit, Settled/Failed) And no sensitive bank details (full account numbers) are shown And status changes are reflected in the UI within 1 minute of receiving processor updates
Payment Method Scope and Partial/Threshold Payments
Given the Engagement Gate is configured to apply to ACH only When a client pays the retainer via card Then no hold is applied and normal countersign and workflows proceed Given a retainer allows a minimum deposit amount When the client pays an amount greater than or equal to the minimum via ACH Then if mode is Hold Work Start, countersign occurs but work start remains held until the total required funds settle And if mode is Hold Countersign, countersign remains held until the total required funds settle When multiple ACH payments are linked to the matter Then the hold releases only when the sum of settled ACH payments meets or exceeds the required amount
Settlement ETA & Live Status
"As a client, I want to know when my bank payment will settle so that I feel confident my retainer is on track and don’t need to call the firm."
Description

Display clear, client-facing settlement ETAs at checkout and within post-payment receipts, and provide live status updates (initiated, pending, retrying, settled, failed) in the client portal and firm dashboard. Calculate ETAs using banking calendars, cutoff times, and holidays, updating dynamically when retries occur. Offer proactive notifications via email/SMS for key events and surface a timeline in the matter record for staff. Localize time zones and include plain-language explanations to reduce support inquiries. Outcome: clients and firms stay informed, lowering payment uncertainty and support volume.

Acceptance Criteria
Checkout ETA Display (Client)
Given a client selects Bank Transfer at checkout and completes instant account verification When the payment is initiated before or after the configured bank cutoff time Then the UI displays a settlement ETA as a specific date and time localized to the client’s time zone And the ETA calculation respects banking business days and recognized holidays And if initiated after cutoff or on a non‑business day, the ETA rolls to the next applicable business day And a plain‑language explanation is shown adjacent to the ETA describing why it may take multiple days And no bank account numbers or sensitive details are exposed in the explanation
Receipt ETA and Status (Post‑Payment)
Given a bank transfer payment is initiated When the post‑payment receipt is generated and delivered via email and SMS Then the receipt includes the current payment status, the settlement ETA, and the payment reference ID And the ETA and status in the receipt match those shown in the client portal within 60 seconds And all timestamps in the receipt include the time zone abbreviation And if the payment is initiated after cutoff, the receipt reflects the adjusted ETA
Live Status Updates in Portals
Given the payment processor sends a status webhook/event When the status transitions to initiated, pending, retrying, settled, or failed Then the client portal and firm dashboard update the visible status within 60 seconds of receiving the event And only valid forward transitions are allowed (no transition from failed/settled back to pending) And each status displays a short, plain‑language description under the status label And the last update timestamp is shown with time zone
Dynamic ETA Recalculation on Retry
Given a payment encounters an NSF or similar retryable failure When a retry is scheduled or a retry attempt begins Then the settlement ETA is recalculated using the retry attempt’s initiation time, banking calendar, and cutoff rules And the recalculated ETA replaces prior ETAs across checkout, portal, dashboard, and receipts within 60 seconds And a timeline entry records the previous ETA, the new ETA, and the reason for change And email/SMS notifications include the updated ETA
Proactive Notifications for Key Events
Given notification preferences allow transactional messages When a payment enters initiated, retry scheduled, retry attempted, settled, or failed Then an email and SMS notification are sent within 2 minutes of the status event And the message includes the current status, the latest settlement ETA (or final outcome), and any next steps And duplicate notifications for the same event are suppressed And delivery failures are logged in the matter timeline
Matter Timeline for Staff
Given any payment status change or ETA recalculation occurs When the matter record is viewed by staff Then a chronological timeline shows each event with timestamp, actor/source, previous status, new status, current ETA, and any processor reason code And timeline entries are immutable and cannot be edited or deleted And staff can filter the timeline by event type (status change, retry, notification) And the timeline retains entries for at least 12 months
Time Zone Localization and Clarity
Given a signed‑in viewer (client or staff) with an associated time zone or locale When viewing ETAs, timestamps, and status update times across checkout, receipts, portal, and dashboard Then all times are displayed in the viewer’s local time zone with explicit abbreviation And server‑side calculations use UTC and are correctly converted for display, including daylight saving changes And if a viewer’s time zone cannot be determined, the firm’s default time zone is used and indicated
NSF Detection & Smart Retry
"As a billing administrator, I want failed bank payments to retry automatically with clear notifications so that we recover retainers without manual chase."
Description

Automatically detect ACH returns (e.g., NSF, account closed) and execute a configurable retry schedule that adheres to network rules. Provide firm-level settings for retry count, spacing, and cutoff; collect updated consent if required; and notify clients with actionable links to retry or switch methods. Update settlement ETAs upon retry, log return codes, and surface alerts to staff with recommended next steps. Integrates with Briefly notifications and the Funds-Cleared Gate to keep engagement state accurate. Outcome: higher recovery on failed payments and reduced manual collections effort.

Acceptance Criteria
ACH Return Detection & Retry Initiation
Given an ACH debit attempt associated to a retainer payment When a return event (e.g., R01 NSF, R09 Uncollected) is received via webhook or file Then the system links the return to the payment with a deterministic match (trace ID or equivalent) and 0 false positives And records return code, description, and received-at timestamp And updates payment state to "Returned — Retry Scheduled" for retriable codes And creates/updates a retry plan within 2 minutes according to firm settings And writes an immutable audit log entry with correlation IDs
Firm-Configurable Retry Rules Enforcement
Given firm settings define max_retries, spacing_business_days, and cutoff_days_from_first_attempt And default settings are max_retries=2, spacing_business_days=3, cutoff_days_from_first_attempt=30 unless overridden When scheduling retries for retriable returns (R01, R09) Then the system schedules no more than max_retries total attempts And ensures each attempt is at least spacing_business_days apart using US banking business days (skip weekends/Fed holidays) And does not schedule any attempt beyond cutoff_days_from_first_attempt from the first debit date And caps retries for NSF-like codes at 2 even if max_retries is higher to comply with network rules And never retries if the prior attempt is still pending settlement
Non-Retriable Return Codes Handling
Given a return with a non-retriable/fatal/unauthorized code (e.g., R02 Account Closed, R03 No Account/Unable to Locate, R04 Invalid Account, R07 Authorization Revoked, R08 Stop Payment, R10 Customer Advises Not Authorized, R16 Account Frozen, R20 Non-Transaction Account, R29 Corporate Customer Advises Not Authorized, R51 Item is Ineligible) When the return is processed Then the system sets payment state to "Returned — Non-Retriable" And schedules zero retries And triggers client and staff notifications with recommended remediation (update bank details or switch method) And records rationale for no-retry in the audit log
Client Notification with Actionable Recovery Paths
Given a payment is returned for any reason When the system processes the return Then the client is notified via configured channels (email/SMS/in-app) within 5 minutes And the message includes plain-language reason, current status, and next-step options And provides secure, expiring links to: update bank account, authorize a new retry, or switch to card And selecting an option successfully updates the payment plan and authorization prerequisites within the same session And all notifications and client actions are tracked with delivery/open/click outcomes
Consent and Authorization Refresh When Required
Given a retry would occur more than 30 days after the original WEB authorization date, or the client changes bank account, or the client switches to a different payment method (e.g., card) When the client initiates the chosen recovery path Then the system presents a compliant authorization/consent flow (amount, account mask, date/schedule, terms) and captures explicit agreement And stores an immutable authorization record (timestamp, IP/device, terms version, signature/e-consent) And blocks any further retries until required consent is captured And proceeds without new consent only for re-presentments of R01/R09 within 30 days and without amount changes
Settlement ETA Recalculation & Funds‑Cleared Gate Update
Given a retry is scheduled or executed When the retry plan is created or updated Then the system recalculates and displays a new settlement ETA (e.g., T+2 US banking days) to client and staff within 2 minutes And adjusts the engagement gating per firm policy: hold countersign/work until funds = Cleared; release immediately on clearance; prevent release if retries exhausted And updates state transitions consistently across Briefly (intake, engagement, documents) and logs them for audit And cancels/updates prior ETAs so only the latest is visible
Staff Alerts, Return Code Logging & Next‑Step Guidance
Given any ACH return is ingested When processing completes Then assigned staff receive an in-app alert within 2 minutes (and optional email/Slack per firm settings) And the alert includes client/matter, return code with human-readable explanation, attempt count, next scheduled action/time, and recommended steps And staff can pause/cancel/reschedule retries or switch payment method with confirmation dialogs And all return codes, schedule changes, notifications, and staff actions are recorded in an immutable audit trail with actor and timestamp
Trust/IOLTA Deposit Routing
"As a firm accounting manager, I want retainer deposits to go into trust with fees paid from operating so that we remain compliant and reconcile easily."
Description

Support compliant legal trust accounting by routing client retainers to designated trust/IOLTA accounts while directing processing fees to the firm’s operating account. Prevent fee netting from trust, enforce account mapping per matter/practice, and generate reconciliation-ready records with transaction IDs, settlement dates, and fee breakdowns. Provide exports and integrations for accounting systems and trust ledgers. Include guardrails that block noncompliant configurations and surface exceptions for review. Outcome: preserves ethical compliance and simplifies reconciliation for consumer-law practices.

Acceptance Criteria
Trust Deposit and Fee Split Routing for Bank Transfers
Given a matter has mapped trust/IOLTA and operating accounts And a client initiates a bank-transfer retainer payment When the payment settles Then 100% of the gross retainer amount is deposited to the mapped trust/IOLTA account And 100% of processing fees are debited exclusively from the operating account And the trust ledger shows no fee netting or deductions And both trust deposit and fee debit include a shared transaction ID, settlement date/time (UTC), and exact amounts And any attempt to route fees to the trust account is blocked with a compliance error before submission
Per-Matter Trust/Operating Account Mapping Enforcement
Given an admin configures Bank Pay Saver for a practice or matter When required trust and operating account mappings are missing or invalid Then the system blocks payment initiation and displays field-level errors identifying the missing/invalid mappings And mappings are stored and enforced per practice and per matter at runtime And an audit log records who set/changed the mappings, what changed, and timestamps And payments for a matter cannot proceed unless both mappings are valid and active
Reconciliation-Ready Transaction Records Generation
Given a payment is submitted, settled, or returned When the system records the transaction Then each record includes: unique transaction ID, client name, matter ID, practice, payment method, gross amount, fee amount, net to trust, currency, trust account ID, operating account ID, initiation date/time (UTC), settlement date/time (UTC) if applicable, status, return/NSF flag, retry attempt, and memo/reference And records are immutable, with corrections appended as new versioned entries linked to the original ID And monetary amounts are stored to 2 decimal places with currency code And users can filter by date range, account, matter, and status for reporting
Trust Accounting Exports and Integrations
Given a user requests an export for a date range and account(s) When the export is generated Then CSV and JSON files include all reconciliation fields and match on-screen totals exactly (tolerance = 0) And totals for gross, fees, and net by account are included in export footers And API/webhooks emit events for created, settled, returned, and exception states within 60 seconds of state change with an idempotency key And payloads validate against a published schema and include the reconciliation fields And a connected accounting/trust-ledger integration receives entries that reproduce the same totals without fee netting
Noncompliant Configuration Guardrails and Preventive Controls
Given an admin attempts to enable fee netting from trust or route principal and fees to the same trust account When saving the configuration Then the system rejects the change with a compliance explanation and references required separate routing And the default configuration routes principal to trust and fees to operating And if “Delay countersign/work until funds clear” is enabled, countersignature and work-start signals remain blocked until the trust deposit status is Cleared/Settled And remapping a trust account with unsettled transactions is blocked or requires a guided reassignment that preserves original destinations for in-flight items, with explicit confirmation and audit logging
NSF/Return Handling and Trust Ledger Reversal Workflow
Given a previously submitted trust deposit is returned (NSF/ACH return) When the return event is received Then the system posts reversing entries to the trust ledger to restore the pre-deposit balance And processing fees remain posted to operating and are not deducted from trust And the client and firm receive notifications with reason codes and next steps And the payment link can be retried per configured limits, creating a new attempt linked to the original transaction ID And the matter remains in Funds Not Cleared state until a successful settled deposit exists And exports show both original and reversal entries with linked reference IDs
Exceptions Queue and Reconciliation Blockers
Given a transaction has missing mapping, failed routing, integration errors, unmatched settlement, or total discrepancies When the condition is detected Then the transaction is placed in an Exceptions queue with severity, reason code, impacted accounts, required action, owner, and timestamps And exceptions prevent reconciliation closure for the affected account/date period until resolved And users can assign, comment, and resolve with mandatory resolution notes And all exception lifecycle events are audit logged and included in exports
Fee Controls & Savings Insights
"As a firm owner, I want to configure ACH fee handling and see savings versus cards so that I can reduce costs while keeping client conversion high."
Description

Allow firms to configure who pays ACH fees (firm or client) within applicable regulations, set thresholds for fee absorption, and display transparent fee disclosures at checkout. Provide a dashboard showing cost savings from bank transfers versus cards over time, with filters by matter, attorney, and date range. Include alerts recommending threshold adjustments to maximize savings without hurting conversion. Integrates with Briefly analytics and billing settings. Outcome: measurable reduction in payment costs with data to guide optimization.

Acceptance Criteria
ACH Fee Payer Configuration & Jurisdiction Guardrails
Given a Firm Admin is on Billing Settings > Bank Pay Saver > Fee Controls, When they select “Firm pays ACH fees” or “Client pays ACH fees” and click Save, Then the selection persists and applies to all new checkouts created after the save timestamp. Given “Client pays ACH fees” is selected, When the matter’s client jurisdiction is flagged as restricted by the policy engine, Then the Save action is blocked with an inline error and help link, and the prior valid policy remains active. Given a new checkout is generated, When the fee payer is computed, Then the computed value is stored in the payment intent metadata and visible in the audit log with user, timestamp, and policy version.
Threshold-Based Fee Absorption Rules
Given a Threshold Amount T is set to $1,000 with rule “Firm pays if amount <= T”, When a checkout total equals $1,000.00, Then fee payer = Firm; When it equals $1,000.01, Then fee payer = Client. Given the threshold is Disabled, When a checkout occurs, Then the fee payer is determined solely by the base setting (Firm pays vs Client pays). Given the threshold value or rule is updated, When a pending checkout link is opened before payment, Then the payer is recomputed using the latest rule and the disclosure updates accordingly.
Transparent Fee Disclosure at Checkout
Given the client selects Bank Transfer and fee payer = Client, When the checkout page loads, Then show a separate line item for “ACH processing fee” with amount, the total including fee, and require an explicit acknowledgment checkbox before payment. Given fee payer = Firm, When the checkout page loads, Then display “ACH fee paid by firm ($X.XX)” and show the client total excluding the fee. Given the user toggles between Card and Bank Transfer, When the method changes, Then fee line items and totals recalculate and render within 200 ms and remain accurate to 2 decimal places. Given the matter jurisdiction requires prescribed wording, When detected by the policy engine, Then the disclosure text uses the jurisdiction-specific template. Given a mobile viewport of 360x640, When the checkout loads, Then all fee disclosures are visible without horizontal scroll and meet WCAG 2.1 AA contrast ratios.
Savings Dashboard, Metrics, and Filters
Given transactions include both ACH and Card, When viewing the Savings Dashboard for a selected date range, Then display totals for processed volume, total fees, ACH fees, estimated card fees avoided, and Savings = Estimated Card Fees − Actual ACH Fees. Given card fee schedules (percent + fixed) are defined in Billing Settings, When computing estimated card fees, Then use those schedules; if multiple schedules are configured, use the configured weighted mix; otherwise use the default global schedule. Given filters for Matter, Attorney, and Date Range, When a filter is applied, Then charts, tables, and KPIs update accordingly within 2 seconds for datasets up to 10,000 transactions. Given the user clicks Export CSV, When the export is generated, Then include columns: transaction_id, date, method, amount, actual_fee, estimated_card_fee, savings, matter_id, attorney_id.
Savings Alerts and Threshold Recommendations
Given at least 100 checkouts exist in the last 30 days, When the model detects conversion rate decrease > 3% associated with client-paid fees and net savings < $200/month, Then display an in-app alert recommending a new threshold T* with estimated monthly savings delta and confidence band. Given the user clicks Apply on the alert, When the action succeeds, Then the threshold updates, an A/B holdback of 10% is created for 14 days, and an audit log entry is recorded with old/new values and user. Given the user dismisses or snoozes the alert, When the action is taken, Then suppress repeat alerts of the same type for 14 days and record the preference. Given a recommendation is shown, When the user clicks “Why?”, Then show a methodology panel with sample sizes, observed conversion, fee costs, and assumptions used.
Integration with Analytics and Billing Permissions
Given a fee policy change is saved, When the event is emitted, Then analytics event fee_policy.updated contains org_id, user_id, old_value, new_value, and ISO8601 timestamp. Given a checkout is created, When analytics events fire, Then checkout.created includes fee_payer, payment_method, amount, currency, and jurisdiction_code. Given user role = Firm Admin, When accessing Fee Controls, Then edit actions are enabled; Given role != Firm Admin, Then settings are read-only and changes are blocked with a permissions notice. Given the organization currency is set, When amounts and thresholds display, Then they use the org currency and 2-decimal precision consistently across UI and exports.
Outcome Measurement and Reporting
Given Bank Pay Saver was enabled on a known date, When viewing the Outcome card, Then show percent change in processing cost rate (fees/processed volume) and absolute monthly savings versus the prior 30-day baseline. Given the date range spans policy changes, When rendering charts, Then annotate policy change dates and allow segmentation by fee payer policy state. Given the user schedules a Monthly email report, When the next cycle runs, Then send a report summarizing KPIs, top matters by savings, and the latest recommendation outcome, with a link to the dashboard.

Smart Map AI

Auto-detects fields, signatures, and checkboxes in PDFs/Word and maps them to Briefly merge fields with confidence scoring. One-click fixes resolve low-confidence matches, cutting hours of manual mapping and reducing template errors on day one.

Requirements

Document Field Auto-Detection
"As a template preparer, I want Briefly to auto-detect all fillable elements in my PDF/Word documents so that I don’t have to manually mark each field before mapping."
Description

Automatically parses uploaded PDFs and Word (.docx) templates to identify interactive and implicit fields—text inputs, dates, checkboxes, radio groups, signature/initial blocks, and multi-line paragraphs—returning field type, label text, page number, reading order, and bounding coordinates. Supports AcroForm and .docx content controls plus heuristic detection of non-form elements (e.g., underlined blanks, drawn checkboxes, signature lines). Emits a normalized schema consumable by Briefly’s template engine and downstream mapper, with deterministic, idempotent output and clear diagnostics for unsupported elements.

Acceptance Criteria
Native Form Control Extraction (PDF AcroForm and DOCX Content Controls)
Given a PDF containing AcroForm controls of types text, date, checkbox, radio button (grouped), signature, initials, and a DOCX containing equivalent content controls When the file is uploaded and auto-detection is executed Then 100% of native controls are emitted as fields with correct type ∈ {text,date,checkbox,radioGroup,signature,initials,multiline} And each emitted field includes label (from control caption/title), pageNumber, readingOrder, and bbox values And for radio buttons, options are consolidated into a single radioGroup with ≥2 options and a shared groupId And pageNumber values are between 1 and total pages; bbox=[x,y,w,h] has w>0 and h>0 and lies fully within page bounds
Implicit Field Heuristic Detection (Blanks, Drawn Checkboxes, Signature Lines)
Given a curated benchmark set of at least 50 non-interactive forms with underlined blanks, drawn checkboxes, and signature lines When auto-detection runs Then underlined blanks are emitted as text or date fields with heuristic detectionMethod and achieve precision ≥ 0.85 and recall ≥ 0.85 on the benchmark And drawn checkboxes are emitted as checkbox fields with precision ≥ 0.90 and recall ≥ 0.85 And signature/initial lines with adjacent labels (e.g., “Signature”, “Initials”) are emitted as signature or initials with precision ≥ 0.95 and recall ≥ 0.90 And each heuristic-detected field includes confidenceScore ∈ [0,1]; fields with confidenceScore < 0.60 are flagged lowConfidence=true
Normalized Schema Shape and Coordinate System
Given any supported document processed by auto-detection When the normalized schema is produced Then every field object validates against Briefly Template Field Schema v1 with required properties: {id, type, label, pageNumber, readingOrder, bbox, source, detectionMethod} And bbox is [x,y,width,height] in points (pt) with coordinateSystem="top-left"; 0 ≤ x < pageWidth, 0 ≤ y < pageHeight, width>0, height>0 And type ∈ {text,date,checkbox,radioGroup,signature,initials,multiline} And source ∈ {pdf,docx}; detectionMethod ∈ {native,heuristic} And schema output includes document-level metadata {totalPages, pageSizes[]} and passes JSON Schema validation with 0 errors
Deterministic, Idempotent Output and Stable Field IDs
Given the same input file processed three times under identical configuration When outputs are canonicalized (stable key order, no timestamps) Then the SHA-256 hash of the normalized schema is identical across all runs And field ids are stable, derived from content features (e.g., control name + geometry hash), and remain unchanged across runs And readingOrder values are strictly increasing by the defined ordering (pageNumber asc, then y asc, then x asc; deterministic tie-break by width then id) And reprocessing an unchanged file does not create duplicate fields nor change field ordering
Label Association and Field Typing Accuracy
Given documents where each field has a nearby textual prompt (left-of or above within 150 pt) When auto-detection runs Then ≥95% of native controls have correct label text extracted (trimmed, whitespace-normalized, without trailing colon) And ≥90% of heuristic-detected fields have correct type assignment (text vs date vs checkbox vs signature/initials vs radioGroup vs multiline) compared to ground truth And when no suitable label text is found, label is null and no placeholder value is used as a label And radioGroup fields include a non-empty options[] array with unique values and visible labels when present
Unsupported Elements Diagnostics and Non-Crash Behavior
Given documents containing unsupported elements (e.g., image-only scans without OCR, complex freehand annotations, embedded spreadsheets) When auto-detection runs Then processing completes without crash and returns diagnostics[] entries for each unsupported element with {pageNumber, bbox, reasonCode, message} And the overall result status is "completed_with_warnings" when diagnostics[] is non-empty; it is "failed" only for unrecoverable parsing errors (e.g., corrupt file), with errorCode and message present And no unsupported element is silently dropped without a corresponding diagnostics[] entry
Merge Field Auto-Mapping & Confidence Scoring
"As a solo attorney, I want the system to propose accurate merge field matches with clear confidence so that I can trust the first pass and only review edge cases."
Description

Maps detected document fields to Briefly’s merge field taxonomy using NLP-based label matching, local context, and type compatibility, outputting a primary match plus alternatives with confidence scores (0–1). Provides configurable thresholds (auto-accept, needs review, reject) and respects tenant-specific synonym lists and jurisdictional vocabulary. Persists stable mapping IDs for reuse across re-uploads and template versions, and exposes match rationales to the UI for transparency.

Acceptance Criteria
Primary Match and Alternatives with Confidence Scores
Given a document with at least 10 detected form fields and an available merge field taxonomy When Smart Map AI processes the document Then for each detected field the API returns exactly one primary match and up to four alternative matches (if available) And each candidate includes mergeFieldId, label, type, and confidence And confidence values are numeric in the inclusive range [0,1] with at least 3 decimal places And candidates for a field are sorted by descending confidence and the primary has the highest confidence And no two candidates for the same field share the same mergeFieldId
Configurable Thresholds Drive Auto-Accept, Review, Reject
Given tenant thresholds set to autoAccept >= 0.85, needsReview >= 0.60 and < 0.85, reject < 0.60 And a document is mapped producing candidates with a spread of confidence scores When classification is applied Then candidates with confidence >= 0.85 are auto-accepted and marked status "Auto-Accepted" And candidates with confidence >= 0.60 and < 0.85 are marked status "Needs Review" and queued to the review list And candidates with confidence < 0.60 are not mapped and marked status "Rejected" And changing the thresholds in tenant settings takes effect for new mappings within 60 seconds And all classification decisions are recorded in the audit log with timestamp, thresholds used, and user/tenant identifiers
Tenant Synonyms and Jurisdiction Vocabulary Influence Matching
Given Tenant A defines synonyms { "SSN": ["Social Security #", "Soc. Sec. No."] } and selects jurisdiction "CA" And Tenant B has no synonyms and default jurisdiction And a document contains the label "Social Security #" When both tenants run Smart Map AI on the same document Then under Tenant A the field maps to mergeFieldId for "SSN" with confidence increased by synonym hits and rationale.synonymHits > 0 And under Tenant B the field maps based on baseline label similarity with rationale.synonymHits = 0 And no synonym or vocabulary configuration from Tenant A appears in Tenant B's results
Stable Mapping IDs Across Re-Uploads and Template Versions
Given Template v1 is mapped producing mappingId values per detected field When the exact same file is re-uploaded and mapped Then each previously mapped field retains the same mappingId When Template v1 is modified to v1.1 with formatting-only changes (pagination/whitespace) and re-mapped Then fields with identical normalized labels and types retain their mappingId And newly added or substantively renamed fields receive new mappingId values And mappingId values are opaque stable UUIDs and deterministic across runs for the same tenant and template
Match Rationale Exposed for Transparency
Given a document is mapped When the API returns mapping results Then each candidate includes a rationale object containing tokenSimilarityScore, typeCompatibility, contextSignals[], synonymHits[], jurisdictionTerms[], and contributingRules[] And the UI can render a textual explanation using these fields without additional server calls And rationale.tokenSimilarityScore and rationale.typeCompatibility directly correspond to components used to compute confidence
One-Click Fix Resolves Low-Confidence Matches and Learns
Given a field classified as "Needs Review" with alternatives shown When the user clicks one alternative to fix the mapping Then the selected alternative becomes the primary mapping within 500 ms and is marked status "User-Selected" And the change is persisted as a feedback rule scoped to tenant + template + field signature And on subsequent mappings of the same template, the system preselects the user-selected mapping with confidence >= the current auto-accept threshold and rationale.contributingRules includes "userOverride"
Type Compatibility Enforced in Mapping
Given the merge field taxonomy defines types: text, date, number, boolean, signature When mapping candidates are generated Then checkbox fields only map to boolean merge fields and signature lines only map to signature merge fields And candidates with incompatible types have rationale.typeCompatibility = false and confidence capped below the reject threshold And no auto-accepted mapping may have incompatible types
One-Click Fix Review Panel
"As a paralegal, I want to resolve mapping mismatches in a single streamlined panel so that I can finalize a template in minutes."
Description

Delivers an in-context review UI overlaying the document to triage low-confidence or unresolved fields, showing top suggestions with confidence and allowing accept/change/ignore in one click or keyboard shortcut. Supports quick search of merge fields, batch-accept of high-confidence items, inline remap with live preview, and per-field comments. Captures reviewer actions for analytics and feeds them back to the learning subsystem.

Acceptance Criteria
Document Overlay Triage View
Given a document with unresolved or low-confidence mapped fields When the user opens the One-Click Fix Review Panel Then the document is overlaid with bounding boxes for flagged fields and a side panel lists items grouped by status (Unresolved, Low Confidence, Resolved) And list selection scrolls and zooms the document to the corresponding field within 300 ms And initial overlay renders within 1500 ms for a 25-page document with up to 200 detected fields And the panel displays counts and allows filtering by status and field type And the highest-priority unresolved field is focused by default
Suggestions List with Confidence Scoring
Given a flagged field is selected in the review panel When Smart Map AI suggestions are available Then the panel shows the top 3 suggestions with confidence scores (0–1), field type, and source And items below the low-confidence threshold (< 0.80) are labeled Low Confidence And items above the auto-accept threshold (>= 0.95) are labeled Auto-accept Eligible And a More options control reveals up to 10 candidates And if no suggestions exist, an empty state appears with a prompt to use Search
One-Click Resolve Actions and Shortcuts
Given a flagged field is selected When the user clicks Accept, Change, or Ignore Then the action applies immediately, the item status updates, and the next item in the queue is focused And the action is undoable for 10 seconds And keyboard shortcuts (A=Accept, C=Change, I=Ignore, Enter=Confirm, Esc=Cancel) perform the same actions And controls meet WCAG 2.1 AA for focus and ARIA labeling And each action is logged with userId, docId, fieldId, actionType, oldMapping, newMapping, confidence, timestamp and queued for analytics within 2 seconds (with offline retry)
Quick Merge Field Search and Insert
Given the review panel is open When the user invokes search (Ctrl/Cmd+K or clicking the search input) and types a query Then results return within 200 ms for the top 20 entries and are ranked by relevance (exact match > synonym > fuzzy) And the user can filter by field type and data source And selecting a result assigns/remaps the current field and marks it Resolved And an empty-state message appears when no results match And catalogs up to 5,000 merge fields are supported without UI freeze
Batch Accept High-Confidence Items
Given there are multiple items with confidence >= the selected threshold When the user chooses Batch Accept and confirms Then only items meeting the threshold and without conflicts are applied And a preview shows the count to be accepted and exclusions with reasons And the operation completes within 1500 ms for up to 200 items And a summary banner reports accepted count and any failures, leaving failed items in the queue
Inline Remap with Live Preview
Given a flagged field is selected When the user chooses Change and selects a different merge field Then the mapping updates and a live preview renders the new value using sample client/matter data within 300 ms And differences from the prior mapping are highlighted And a type-mismatch warning appears if the target field type differs (e.g., date vs string) And Revert restores the previous mapping and preview And the new mapping persists to the template upon save
Per-Field Comments and Mentions
Given the user opens the comments for a specific field When a comment is added with optional @mention Then the comment is saved with author, timestamp, and fieldId, and mentions trigger notifications to mentioned users And comments support basic formatting and can be edited or deleted by the author And a thread can be marked Resolved/Unresolved, with state visible in the item list And users with view-only permissions cannot post comments And all comment events are recorded for audit export
Field Type Validation & Constraints Enforcement
"As a template maintainer, I want the system to catch and help fix incompatible or missing mappings so that generated retainers and pleadings are error-free."
Description

Verifies that each mapping adheres to Briefly’s schema constraints (e.g., data types, required/optional, signature vs. initials, checkbox group exclusivity) and flags conflicts such as many-to-one collisions or missing required mappings. Provides actionable guidance and auto-fixes where safe (e.g., date format normalization), blocks publishing on critical errors, and exports a validation report for QA.

Acceptance Criteria
Enforce Field Type Compatibility
Given a mapping between a source document field and a Briefly schema field When validation runs Then if the types match, the check passes And if the types differ and no safe auto-fix rule exists, a Critical error TYPE_MISMATCH is recorded and publish is blocked And if the types differ but a safe auto-fix exists (e.g., date text → date), the auto-fix is applied, a Warning TYPE_COERCED is recorded, and details include fromType, toType, and fixDescription
Required Field Coverage
Given a template with N required schema fields When validation runs Then 100% of required fields must be mapped And any unmapped required fields are listed with code REQUIRED_MISSING and severity Critical And the validation summary shows countMissing and blocks publish until countMissing = 0
Signature vs Initials Constraint
Given a mapping to a schema field of type signature When the source field is not a signature field Then a Critical error SIGNATURE_TYPE_MISMATCH is recorded and publish is blocked Given a mapping to a schema field of type initials When the source field is not an initials field Then a Critical error INITIALS_TYPE_MISMATCH is recorded and publish is blocked And the UI offers a one-click fix to remap to a compatible field if available
Checkbox Group Exclusivity Enforcement
Given a schema field group defined as single-select (exclusive) When more than one document checkbox is mapped such that multiple selections can be true Then a Critical error CHECKBOX_EXCLUSIVITY_VIOLATION is recorded and publish is blocked And when exactly one checkbox is allowed true and others are mutually exclusive false Then the check passes And a one-click fix is offered to convert the group to radio buttons or unmap extras
Many-to-One and One-to-Many Collision Detection
Given mappings exist between source fields and schema fields When multiple source fields map to the same non-repeatable schema field Then a Critical error MANY_TO_ONE_COLLISION is recorded and publish is blocked When a single source field maps to multiple schema fields without explicit alias permission Then a Warning ONE_TO_MANY_DUPLICATION is recorded with guidance to confirm or split the mapping When the target schema field is repeatable (array) Then many-to-one mapping is allowed and the check passes
Block Publish on Critical Errors
Given one or more Critical validation errors exist When the user attempts to publish the template Then the Publish action is blocked with an error listing Critical issues and a link to open Validation And when all Critical errors are resolved and validation shows zero Critical Then Publish becomes enabled and proceeds successfully
Validation Report Export
Given validation has been run on a template When the user selects Export Report Then a downloadable CSV and JSON are produced within 5 seconds for templates with ≤ 500 mappings And each record includes templateId, checkId, checkType, severity, status (Pass/Warning/Critical), schemaFieldKey, sourceFieldId, message, autoFixApplied (true/false), timestamp, and guidanceUrl And the report reflects the latest validation run and totals match the UI summary And auto-fixed items are marked with status Warning and autoFixApplied = true
Learning from Corrections (Adaptive Mapping)
"As an attorney, I want the tool to get smarter from my edits so that the next template maps correctly without my intervention."
Description

Persists user corrections and outcomes to improve future suggestions via per-tenant and global models while preserving data isolation. Supports opt-in controls, reset of learned associations, and monitoring of precision/recall lift over time. Periodically refreshes synonym dictionaries and weighting without regressing previously accepted mappings, with safe rollout and rollback.

Acceptance Criteria
Persist Corrections Per Tenant
Given a tenant user corrects an auto-mapped target field in a specific template category, When the correction is saved, Then the system persists a per-tenant association linking source cues to the target merge field with a context hash and timestamp. Given the same tenant uploads a document whose context hash matches or has ≥0.90 similarity to the saved association, When Smart Map AI proposes mappings, Then it suggests the corrected target with confidence ≥0.80 and labels it as Learned. Given a different tenant processes an identical document, When Smart Map AI proposes mappings, Then the per-tenant correction is not applied unless promoted to the global model, and no tenant identifiers appear in logs, responses, or artifacts.
Global Model Learning With Data Isolation
Given a tenant admin has opted in to Contribute to Global Learning, When ≥100 distinct opted-in tenants have accepted the same association across ≥500 documents, Then the association is eligible for global promotion and is suggested to all tenants with confidence ≥0.75. Given a tenant admin has opted out of Contribute to Global Learning, When corrections are made, Then those corrections do not update global artifacts and do not affect other tenants’ suggestions. Then all model artifacts (embeddings, weights, dictionaries) contain no tenant IDs, user IDs, document content, or file names; automated static checks and PII scanners pass with zero findings.
Opt-In/Opt-Out Controls and Reset
Given a tenant admin, When they toggle Use Learning and Contribute to Global in Settings, Then the change takes effect within 5 minutes and is reflected in audit logs. Given a tenant admin clicks Reset Learned Associations, When they confirm, Then all per-tenant learned associations and their effects are cleared within 5 minutes, and subsequent suggestions revert to baseline confidence distributions. Then a downloadable audit event is created for toggle and reset actions including actor, timestamp (UTC), and before/after values.
Monitoring Precision/Recall Lift
Given the monitoring dashboard, When at least 200 predictions exist in the selected 30-day window for a document type, Then baseline and post-learning precision, recall, and F1 are displayed with 95% confidence intervals and absolute/relative lift. Given a 7-day rolling window, When any metric drops by >5% absolute compared to the previous 7-day window, Then an alert is generated to Ops with a link to rollback controls. Then metric computations are reproducible: same inputs yield identical outputs; a checksum of the dataset and version of the evaluation code are recorded.
Safe Refresh of Synonyms and Weighting
Given a new synonym dictionary or weighting release, When canary rollout to 10% of traffic is initiated, Then accepted mapping rate and error rate are compared against a 10% control for 24 hours and must meet guardrails: acceptance rate delta ≥ -1%, error rate delta ≤ +0.5%. When guardrails are not met, Then automatic rollback to the previous version completes within 5 minutes and all traffic is returned to control. Then previously accepted mappings in the last 90 days remain suggested post-rollout with confidence drop ≤ 0.05 or are explicitly whitelisted to maintain prior behavior.
One-Click Fix Feedback Loop
Given a low-confidence match (<0.60) is resolved via one-click fix to a specific target, When the same field/context recurs, Then the suggested confidence increases by ≥0.10 and the suggestion ranks in the top 1 for that field. When multiple users within the same tenant make identical fixes (n ≥ 3), Then the mapping is auto-promoted to high-confidence (≥0.80) for that tenant. Then persistence latency from correction to being reflected in suggestions is ≤ 10 minutes at p95 under normal load.
Auditability and Versioning
Given any learned association creation, update, promotion, reset, rollout, or rollback, When an auditor requests records, Then an immutable audit log entry exists with actor, tenant, action, object ID, model/dictionary version, and timestamp (UTC). When exporting tenant learned associations, Then a CSV is generated within 2 minutes (p95) containing context hashes, target fields, confidence before/after, acceptance counts, and excluding any raw document text or PII. Then model and dictionary versions use semantic versioning (MAJOR.MINOR.PATCH) and release notes include change summary and rollout/rollback IDs.
Audit Trail & Versioned Mapping
"As a firm owner, I need auditable change history and easy rollback so that I can comply with QA and revert mistakes quickly."
Description

Maintains a complete, immutable history of mapping changes per template, including actor, timestamp, and before/after diffs. Enables rollback to any prior version, branching for experiments, and compatibility checks when importing mappings into new template revisions. Provides export/import of mapping sets as JSON for backup and reuse across similar templates.

Acceptance Criteria
Immutable Audit Log for Mapping Changes
Given an authenticated user with edit permissions and a template with existing field mappings When the user creates, updates, or deletes a mapping and saves the change Then the system appends an audit record that includes templateId, templateRevision, mappingId, action (create|update|delete), actorId, actorEmail, timestamp (UTC ISO8601), before JSON, after JSON, and a cryptographic hash chained to the previous record And any attempt to modify or delete an existing audit record is rejected and a security event is logged And GET /templates/{id}/mappings/audit returns the new record within 2 seconds in reverse chronological order And the hash-chain verification endpoint reports "valid" for the audit log after the change
Automatic Versioning of Mapping Sets
Given a template and its current mapping version Vn When any mapping change is saved Then a new mapping version Vn+1 is created atomically with a label (default "Auto-save") and optional commit message And the diff between Vn and Vn+1 is stored and accessible via GET /templates/{id}/mappings/versions/{versionId}/diff And the active version pointer updates to Vn+1 And versionId is unique and timestamps are strictly monotonic (UTC ISO8601)
Rollback to Prior Version
Given a mapping history with versions V1..Vn and a selected prior version Vk (k < n) When the user clicks "Rollback to Vk" and confirms Then the system creates a new version Vn+1 whose content exactly equals Vk And all prior versions remain preserved; none are deleted or mutated And an audit record is written with action "rollback", sourceVersion=Vk, targetVersion=Vn+1 And the active version pointer updates to Vn+1 and is used for subsequent document generation And the rollback completes within 3 seconds for templates up to 5,000 mappings
Branching for Experiments
Given mapping version Vn on the main branch When the user creates a branch named "Experiment A" from Vn Then a new branch is created with its own version sequence starting at Vn-branch.1 And changes on "Experiment A" do not alter main branch history or active version And the user can switch the active branch per template via UI/API and GET /templates/{id}/mappings/active reflects the selection And deleting a branch requires confirmation and is blocked if the branch is currently active
Compatibility Check on Import to New Template Revision
Given a JSON mapping set exported from template T revision R1 and a target template T revision R2 When the user imports the mapping set into R2 with compatibility check enabled Then the system validates field existence, type compatibility (text/date/checkbox/signature), and coordinate/anchor constraints And a report is returned with counts: total entries, mappable, auto-remapped, conflicts, missing targets, and type mismatches And import is blocked if conflicts > 0 unless the user selects "allow partial import", in which case only mappable entries are applied and conflicts are skipped And the compatibility report is persisted to the audit log and available for download as JSON
Export Mapping Sets as JSON
Given a template with an active mapping version on branch X When the user exports the mapping set Then a JSON file is generated conforming to schema version S that includes templateId, templateRevision, branch, versionId, createdAt (UTC), checksum (SHA-256), and an array of mappings with source selectors and target merge fields And the export is deterministic (stable field ordering) and includes no secret credentials And re-importing the file unchanged into the same template and branch produces a no-op (no new version) when deduplication is enabled And export completes within 5 seconds for templates up to 5,000 mappings and reports file size and counts
Import Mapping Sets as JSON
Given a JSON mapping set file When the user imports it into the same template revision and branch Then the file is validated against schema S; on failure, import is rejected with line- and field-specific error messages And on success, a new mapping version is created containing the imported content; if identical to current and deduplication is enabled, no new version is created And an audit record is written with action "import", checksum, mapping counts, and any skipped entries And the API returns a summary with total imported, skipped, created versionId (or no-op), and operation duration
Security & Privacy Controls for Document Processing
"As a legal practitioner handling sensitive PII, I want robust controls over how my documents are processed and retained so that I meet ethical and regulatory obligations."
Description

Executes parsing and mapping under least-privilege, tenant-scoped access with encryption in transit and at rest. Minimizes storage of page imagery and transient artifacts, supports configurable data retention and purge schedules, and records access logs for sensitive operations. Honors data residency configurations to keep PII within specified regions and provides admin controls for consent and redaction settings.

Acceptance Criteria
Tenant-Scoped Least-Privilege Execution
Given a processing job is started for Tenant A When the job accesses storage, queues, models, and logs Then all resource accesses are limited to Tenant A scoped principals and access to Tenant B resources returns 403/denied And privilege escalation beyond predefined roles is blocked and generates an audit log within 5 seconds And an automated cross-tenant read/write test fails with 403 and emits a corresponding audit entry
End-to-End Encryption In Transit and At Rest
Given any upload, download, or service-to-service call Then TLS 1.2+ is enforced and downgrade attempts are rejected with an appropriate error (e.g., 426) And at-rest encryption uses KMS-managed keys (AES-256 or equivalent) for object, database, and queue payloads And encryption headers/metadata are present on stored objects and rows And key rotation occurs at least every 365 days and is recorded in audit logs
Minimal Transient Artifacts and Ephemeral Storage
Given a document is processed into page images and feature maps When processing completes or fails Then transient artifacts are deleted from ephemeral storage within 15 minutes And no page imagery is persisted to durable storage unless explicitly enabled by tenant policy And system metrics report deletion success rate ≥ 99.9% over a rolling 30-day window
Configurable Data Retention and On-Demand Purge
Given a tenant retention setting (e.g., 0, 7, 30, 90 days) When a document and its derived artifacts reach retention expiry Then a purge job deletes all related content across object storage, cache, and search within 24 hours And access/audit logs remain but contain no PII due to enforced redaction policy And a tenant admin can initiate an on-demand purge that completes within 2 hours at the 95th percentile and emits a purge receipt with counts and object IDs
Access Logging for Sensitive Operations
Given any sensitive operation (document open, processing, mapping, download, purge, retention change) When performed by a user or system principal Then an immutable audit log entry is created with timestamp, actor/service principal, tenant ID, document ID, operation, purpose, outcome, and source IP/agent And logs are tamper-evident (WORM or hash-chained) and retained for at least 365 days or tenant-defined policy And tenant admins can query and export logs by date range and operation with response time under 10 seconds for up to 10,000 entries
Data Residency Enforcement
Given a tenant data residency setting (e.g., EU, US, CA) When documents are uploaded, processed, stored, and logs are written Then all data paths remain within the selected region and cross-region calls or storage are blocked And any attempted cross-region egress is prevented and logged with severity High within 5 seconds And scheduled compliance tests verify residency weekly with zero allowed violations
Consent Gate and Redaction Controls
Given tenant policy requires client consent and redaction When a user attempts to process a document without recorded consent Then processing is blocked with a consent-required error and no document content is persisted And when previews or logs are generated, configured PII fields are redacted/masked across UI, exports, and logs And consent and redaction policies are editable by tenant admins only, with changes logged and taking effect within 60 seconds

Clause Compass

Recommends the right clauses by practice area and jurisdiction, with plain-language rationale and rule citations. Highlights required language and risk flags, so solos can insert compliant wording in seconds and draft with confidence.

Requirements

Jurisdiction & Practice Area Auto-Detection
"As a solo consumer-law attorney, I want the system to auto-select my jurisdiction and practice area so that clause recommendations are accurate without extra clicks."
Description

Automatically determines the governing jurisdiction and practice area for a matter using intake data (client address, court selection, counterparty location, claim type) and Briefly’s matter metadata. Provides a clear selector with manual override and audit trail, supports multi-jurisdiction matters (primary and secondary), and normalizes to canonical court and state codes. Outputs a normalized context object consumed by Clause Compass for library scoping and citation selection. Ensures consistent, low-friction setup on mobile and desktop, reducing misclassification and improving recommendation accuracy.

Acceptance Criteria
Primary Jurisdiction from Court Selection
Given a matter where the user selects a court during intake And the selected court exists in the Briefly Court Catalog When the intake step is saved Then primary_jurisdiction.state_code is set to the court’s state as ISO 3166-2:US And primary_jurisdiction.court_id is set to the catalog court_id And the Jurisdiction selector displays these values preselected And no validation errors are shown
Practice Area Detection from Claim Type and Metadata
Given a matter with claim_type selected and available matter metadata And claim_type maps to a Briefly practice_area_id When the intake step is saved or the claim_type is confirmed Then practice_area_id is auto-set to the mapped taxonomy id And the Practice Area selector displays the detected value And if the user had previously overridden the practice area, the system does not overwrite the manual choice and logs a non-overriding detection attempt And on the labeled validation set for supported claim types, practice_area_id detection achieves at least 95% accuracy
Manual Override with Audit Trail
Given jurisdiction and practice area have been auto-detected When a user changes any detected value via the selector Then an audit_log entry is recorded containing matter_id, user_id, field_name, previous_value, new_value, source="manual", and an ISO 8601 UTC timestamp And the updated values persist across sessions and are used by Clause Compass And a Revert to Auto option is available When the user selects Revert to Auto Then values are recomputed based on current signals and an audit_log entry is recorded with source="revert"
Secondary Jurisdiction Support and Precedence
Given intake signals from court selection, client address, and counterparty location indicate more than one jurisdiction When auto-detection runs Then the primary jurisdiction is chosen by precedence: court > client address > counterparty location And exactly one secondary jurisdiction is added when it differs from the primary and is supported by signals And the selector allows the user to add or remove the secondary jurisdiction And the final primary and secondary jurisdictions are shown in the selector and persisted
Canonical Code Normalization and Validation
Given inputs that may include state names, abbreviations, or variant court names When normalization runs Then state_code is normalized to a two-letter ISO 3166-2:US code And court_id resolves to an existing Briefly Court Catalog identifier And practice_area_id resolves to a Briefly taxonomy identifier And any value that does not validate against the schema is not persisted, a non-blocking prompt requests correction, and the rest of the form remains usable
UX Consistency and Performance on Mobile and Desktop
Given a supported mobile device and desktop browser When the user completes the minimum required signals for detection Then auto-detection completes within 800 ms at P95 and within 2 s at P99 from the last input change And the jurisdiction and practice area selectors require no more than 2 taps/clicks to change each value And the selectors are keyboard accessible and screen-reader compatible per WCAG 2.1 AA And the fields, labels, and options are functionally equivalent on mobile and desktop
Context Object Delivery to Clause Compass
Given a matter with detected or overridden values When Clause Compass is invoked for that matter Then a normalized context object is produced containing jurisdictions.primary.state_code, jurisdictions.primary.court_id, optional jurisdictions.secondary[0].state_code, and practice_area_id And all codes conform to the canonical enumerations and secondary is omitted if none And Clause Compass scopes recommendations to the provided practice area and jurisdictions, verified by the absence of recommendations outside those jurisdictions and the presence of at least one clause citing the primary jurisdiction And the delivery returns success (e.g., in-process call or HTTP 200) and includes a correlation_id recorded in both systems’ logs
Clause Recommendation Engine & Relevance Scoring
"As a drafter, I want a ranked list of recommended clauses tailored to my case so that I can insert the right language quickly."
Description

Delivers a ranked list of clauses scoped to the detected practice area and jurisdiction using a rules-driven engine with tag matching (e.g., venue=CA, practice=debt collection, relief=injunctive) and confidence scoring. Supports hard requirements, soft preferences, and exclusions, with transparent factors contributing to ranking. Returns top results with metadata (required/optional, dependencies, conflicts) via an internal API consumed by the editor UI. Caches frequent queries for performance and supports offline-safe fallbacks on mobile.

Acceptance Criteria
Ranked Clause List by Practice Area and Jurisdiction
Given context tags include practice="debt_collection" and jurisdiction="CA" When the engine generates recommendations without overrides Then the response contains only clauses scoped to practice "debt_collection" and jurisdiction "CA" And the list is sorted by descending relevance_score And the default page returns 20 items unless a limit parameter is provided And ties are broken by clause_id ascending And no duplicate clause_id appears in the list
Hard Requirements and Exclusions Enforcement
Given hard_required_tags and excluded_tags are provided in the request When recommendations are generated Then every returned clause matches all hard_required_tags And no returned clause matches any excluded_tags And if zero clauses satisfy the hard_required_tags, the API returns an empty list with reason="NO_RESULTS_HARD_FILTER"
Soft Preferences Affect Relevance Scoring
Given soft_preference_tags are provided When recommendations are generated Then clauses matching more soft_preference_tags receive higher relevance_score than otherwise identical clauses that match fewer And soft preferences do not exclude clauses from the result set And at least 80% of the top 10 results match at least one soft_preference_tag when such matches exist in the corpus
Transparent Factors and Confidence Score Returned
Given a recommendation response Then each clause object includes fields: clause_id, title, relevance_score (0.000-1.000), confidence (0.000-1.000), and factors[] And factors[] contains at minimum entries for practice_match, jurisdiction_match, and tag_overlap with each entry having name, weight, contribution, and explanation And the sum of factor contributions equals the relevance_score within a tolerance of 0.01 And confidence is present and computed from data coverage and historical selection rate And numeric fields use 3-decimal precision
Metadata for Dependencies and Conflicts
Given a recommendation response Then each clause includes metadata.requiredness with values "required" or "optional" And each clause may include metadata.dependencies as an array of clause_id values and metadata.conflicts as an array of clause_id values And the engine does not place mutually conflicting clauses in the same page of results unless allow_conflicts=true is provided in the request
Internal API Contract and Pagination
Given the editor UI calls the internal recommendations API with a valid request payload containing context_tags, hard_required_tags, soft_preference_tags, excluded_tags, and limit When the request is processed Then the API responds with HTTP 200 and a JSON body matching the published schema including fields: clauses[], total, cursor.next, cursor.prev And invalid inputs yield HTTP 400 with error codes and no partial results And pagination by cursor returns consistent ordering across pages for the same request_id And for identical requests within 5 minutes, response etag is reused and results are byte-identical
Caching and Offline-safe Fallback on Mobile
Given an identical recommendations request made within the cache_ttl When the engine receives the request Then a cache hit is served with p95 latency <= 150 ms and includes header cache="hit" And cache entries are invalidated within 60 seconds of rules or clauses updates And when a mobile client is offline, the client SDK returns the most recent cached recommendations for the same context (if <= 7 days old) marked is_stale=true And if no cached data exists, the client SDK returns clauses=[] with reason="OFFLINE_NO_CACHE"
Plain-Language Rationale & Rule Citations
"As a time-pressed solo, I want plain-language reasons and citations for each clause so that I can trust the recommendation without deep research in the moment."
Description

Displays a concise, plain-language explanation for each recommended clause, paired with authoritative citations (statutes, court rules, regulations, or leading cases). Includes effective dates, jurisdiction, and clickable links to sources, plus a short excerpt where permitted. Provides ‘why this matters’ context and applicability notes (e.g., thresholds, exceptions), enabling informed decisions without leaving the drafting flow. Cites the specific rule text when required language is mandated.

Acceptance Criteria
Inline Rationale Panel During Drafting
Given a user is drafting and a clause is recommended When the user expands the “Rationale & Citations” for that clause Then a panel renders inline without navigating away from the editor, and the editor remains visible and editable And the panel shows a plain‑language explanation no longer than 120 words And the panel includes distinct subsections labeled “Why this matters” and “Applicability” And if applicability thresholds or exceptions exist in the underlying authority, at least one note is displayed in “Applicability” And on a viewport width ≤ 480px, the panel is responsive, non‑modal, and vertically scrollable without obscuring the editor’s primary action buttons
Complete Citation Metadata and Links
Given the panel displays citations for a recommended clause When citations are rendered Then each citation displays: authority type (statute, court rule, regulation, case), jurisdiction, effective date or “current through” date, and a human‑readable citation string And each citation includes a clickable link to an official or authoritative source that opens in a new tab And when an official source is unavailable, a secondary source link is shown and labeled “secondary source” And where license permits, a short excerpt up to 250 characters is displayed with an ellipsis if truncated; otherwise the message “excerpt unavailable” is shown And case citations include a pin cite (page/paragraph) when an excerpt is shown
Mandated Rule Text Quoted and Insertable
Given at least one controlling authority mandates specific wording for the clause When the panel renders Then the exact mandated text is displayed as a verbatim quotation with a “Required language” badge And a pinpoint reference (section/subsection or paragraph) is shown adjacent to the quote And an “Insert required language” action is available that inserts the quoted text into the current clause at the cursor or replaces a highlighted placeholder And the inserted text preserves original capitalization, punctuation, and bracketed elements And if multiple authorities mandate conflicting language, the user is prompted to choose one, with jurisdiction shown for each
Jurisdiction and Practice Area Relevance Filtering
Given the matter has a set jurisdiction and practice area When citations are listed for a recommended clause Then only citations from the matter’s jurisdiction and applicable federal authorities are shown by default And each citation is labeled with a relevance badge: “Direct” (same jurisdiction), “Federal/General”, or “Analogous” (neighboring/model/other) And if no direct authorities exist, a notice “No direct authority for [jurisdiction]” is shown with a toggle to reveal analogous sources And when the toggle is enabled, analogous citations appear grouped under an “Out‑of‑jurisdiction” header with a risk note And changing the matter’s jurisdiction refreshes the list within 300ms to reflect the new scope
Currency Validation and Expiration Alerts
Given each citation includes an effective date or current‑through date When a citation is past its effective period, marked repealed/superseded, or lacks a current‑through date within 12 months Then the citation displays a visible warning badge: “Out of date” (red) for repealed/superseded, or “Verify currency” (amber) for stale/unknown And out‑of‑date citations are sorted below current ones and the “Insert required language” action is disabled for them And each citation displays a “Last checked” timestamp (UTC) And 95% of citations in production environments show a “Last checked” date within the past 30 days
Performance and Accessibility of Rationale Panel
Given a user opens the “Rationale & Citations” panel When content is requested from services Then initial skeleton placeholders appear within 100ms And 95th percentile content render time is ≤ 400ms on a 5 Mbps connection and ≤ 800ms on 3G Fast emulation And all interactive elements are keyboard navigable with visible focus states And link text is descriptive (no bare “click here”), opens in a new tab, and announces purpose to screen readers via aria‑labels And color contrast for text and badges is ≥ 4.5:1 and the panel passes WCAG 2.1 AA checks for role, name, and state
Required Language Highlighter & Variable Prompts
"As a drafter, I want required phrases and fill-ins clearly highlighted so that I can ensure compliant wording with minimal edits."
Description

Highlights mandatory statutory or rule-based language within recommended clauses and clearly marks fillable variables. Enforces presence and exact wording where required, prompts for missing values, and auto-binds variables to intake fields (e.g., party names, dates, amounts). Provides inline validation and preview of the fully populated clause before insertion, reducing compliance errors and rework.

Acceptance Criteria
Jurisdiction-Specific Required Language Highlighting
Given a recommended clause with mandatory statutory phrases and jurisdiction tags matching the case When the clause loads in the editor Then 100% of mandatory phrases are visually highlighted and locked against editing And each highlighted segment displays a tooltip with plain-language rationale and rule citation on hover or focus And non-required text remains unhighlighted
Variable Detection and Auto‑Binding to Intake Fields
Given intake data exists for party names, dates, and monetary amounts And the clause contains placeholders for those variables When the clause is opened Then variables are auto-bound to matching intake fields by schema or name mapping And all bound variables are prepopulated with existing values And unbound variables are visually marked as required or optional
Enforcement of Exact Wording for Mandatory Phrases
Given a clause contains mandatory phrases When a user attempts to edit text within a mandatory phrase Then the editor prevents changes and shows an inline notice explaining edit restrictions with citation When a user attempts to insert the clause with altered or missing mandatory wording Then insertion is blocked and a diff view highlights the discrepancies And the error message references the governing rule or statute
Prompting and Validation for Missing Variable Values
Given a clause has one or more required variables without values When the user proceeds to preview or insert the clause Then a prompt lists missing variables with input controls and validation rules (e.g., date format, currency) And invalid inputs show inline error messages until corrected And the user cannot insert the clause until all required variables pass validation or are completed
Inline Preview of Fully Populated Clause Before Insertion
Given a clause contains mandatory phrases and variables When the user clicks Preview Then a preview renders the clause with all variables resolved and mandatory phrases highlighted And a status indicator confirms all required wording and variable validations pass And the Insert button is enabled only when the preview passes all checks And inserted text exactly matches the approved preview
Rule Version and Jurisdiction Mismatch Risk Flagging
Given a clause’s required language is tied to a specific jurisdiction and rule version When the case jurisdiction differs or the rule version is outdated Then a risk flag appears with plain-language rationale and citations And the system recommends a jurisdiction-appropriate alternative clause if available And insertion of the mismatched clause is blocked unless the user selects an approved alternative
Risk Flags & Conflict Detection
"As a cautious practitioner, I want proactive risk flags with explanations so that I can avoid noncompliance and contradictions in my drafts."
Description

Identifies missing required clauses, outdated citations, and conflicts between selected clauses or with case facts (e.g., incompatible venue or inconsistent remedies). Assigns severity levels, explains the risk in plain language, and suggests corrective actions or alternative clauses. Runs continuously as clauses are selected and as facts change, surfacing issues before signature or filing.

Acceptance Criteria
Detect Missing Required Clause by Jurisdiction
Given a matter with practice area = Consumer Debt Defense and jurisdiction = California And a drafting session where the "Venue Consent" clause is required by jurisdictional rules And the current draft does not contain the required clause When the system scans the draft Then a risk flag with severity = "Critical" and title = "Missing required clause: Venue Consent" is created within 500 ms of the last edit And the flag includes a plain‑language rationale (<= 200 words) and a citation to the controlling rule And an action "Insert Required Clause" is available that inserts the compliant clause at the correct section And upon insertion the system rescans within 300 ms and automatically marks the flag as Resolved and removes it from the active list And on a regression set of 50 known missing‑clause cases, detection recall is >= 95% and false‑positive rate is <= 5%
Flag Outdated Citation in Selected Clause
Given a selected clause contains a statutory citation that has been superseded or amended When the system scans the draft Then a risk flag with severity = "High" titled "Outdated citation" is created within 500 ms And the flag shows the current controlling citation and effective date And a one‑click action "Replace with current citation" updates the clause text and citation in place without breaking formatting or merge fields And after replacement, the system rescans within 300 ms and the flag is marked Resolved And on a test suite of 100 known outdated citations across 5 jurisdictions, detection accuracy is >= 98% and erroneous flags are <= 2%
Identify Clause–Fact Conflict: Venue Mismatch
Given intake facts specify filing county = Travis County, Texas And the selected venue clause specifies Harris County, Texas When the system scans the draft and facts Then a risk flag with severity = "High" titled "Venue mismatch with case facts" is created within 500 ms And the flag proposes the corrected venue derived from intake facts and displays a one‑click "Apply suggested venue" action And applying the suggestion updates the clause and triggers a rescan within 300 ms that resolves the flag And on a test set of 40 known venue mismatches, detection rate is >= 97% and false‑positive rate is <= 3%
Detect Conflicting Remedies Between Clauses
Given the draft includes both a "Binding Arbitration" clause and a "Jury Trial Demand" clause When the system scans the draft Then a risk flag with severity = "Critical" titled "Inconsistent remedies" is created within 500 ms And the flag explains the conflict in plain language and cites relevant authority or drafting guidance And the flag offers actions: "Remove Jury Demand", "Remove Arbitration", and "Insert Carve‑Out" with previews And selecting any action updates the draft accordingly and resolves the flag on rescan within 300 ms And in a library of 30 known remedy conflicts, detection rate is 100% with 0 false negatives
Severity, Explanation, and Citation Completeness
Given any risk flag is generated When the flag is displayed in the UI Then it includes: severity level (Critical/High/Medium/Low), plain‑language explanation <= 2 sentences at Flesch‑Kincaid grade <= 10, at least one jurisdiction‑specific citation or rule ID, a hyperlink to primary source when available, and timestamp of detection And severity assignment follows the rules: Critical = legal invalidation/blocking issue; High = likely non‑compliance or adverse outcome risk; Medium = procedural/formatting that may delay; Low = stylistic And in a QA sample of 60 flags across 4 jurisdictions, 100% contain all required elements and respect the severity rules
Corrective Actions and Alternative Clause Application
Given a risk flag of type Missing, Outdated, or Conflict is present When the user opens the flag Then at least one corrective action is shown with: action label, plain‑language outcome, and a preview of resulting clause text And alternatives are filtered to the matter’s practice area and jurisdiction And clicking an action applies the change without breaking numbering, cross‑references, or merge fields, and preserves document styles And the system provides Undo within 1 step and logs the action with user, timestamp, and rule ID And in 20 representative correction scenarios, at least 95% of actions apply successfully without manual edits
Continuous Scanning and Pre‑Signature Gate
Given the user is editing clauses or intake facts When any clause selection changes or any fact field is saved Then the risk scan runs automatically and updates visible flags within 1,000 ms without requiring manual refresh And scans are debounced so rapid edits (>= 5 edits/sec for 10 sec) result in no more than 3 UI re‑renders while the final state reflects the latest content And if any Critical or High flags remain unresolved, the actions "Send for e‑sign" and "Export for filing" are disabled with a tooltip listing blocking flags And a user with proper permission may override the gate only after providing a justification note; overrides are logged with user, timestamp, flags overridden, and justification and appear in the audit report export
One-Click Insert & Merge Mapping
"As a mobile-first user, I want to insert a recommended clause with one tap and have it pre-filled so that I can draft fast without formatting hassles."
Description

Inserts the selected clause into the active draft at the correct location with preserved formatting, numbering, and defined styles. Automatically maps and merges intake data into variables, supports undo/redo, and provides a quick preview. Works seamlessly across mobile and desktop editors, enabling insertion from search results or the sidebar with a single tap/click.

Acceptance Criteria
One-Click Insert From Sidebar With Formatting Preservation
Given an open draft with defined styles and a selected clause in the sidebar When the user single-clicks/taps Insert on the clause card Then the clause is inserted at the active insertion point or placeholder tag, retaining paragraph/character styles, indentation, and inline formatting And list and heading numbering auto-continue from surrounding context And footnote/citation markers and hyperlinks in the clause are preserved And the operation completes within 800 ms on desktop and 1200 ms on mobile (p95)
Insert From Search Results Into Last Focused Location
Given the draft has a visible text caret or placeholder selection and Clause Compass search is open When the user single-clicks/taps Insert on a search result card Then the clause is inserted at the last focused location in the draft And the editor scrolls to the inserted content and highlights it for 2 seconds And no more than one clause instance is inserted per click/tap
Automatic Merge Mapping Of Intake Variables
Given a clause containing variables such as {{Client.FullName}}, {{Jurisdiction}}, and {{FilingDate}} and an intake record with those fields populated When the clause is inserted or previewed Then variables with available values are replaced using matter locale formats (e.g., dates in MMM DD, YYYY) And variables without values are rendered as red-highlighted placeholders with a data-gap badge and listed in the Data Gaps panel And merged values retain case and spacing as provided in intake data
Undo/Redo Treats Insert+Merge As Single Atomic Action
Given a clause has just been inserted with variables merged When the user invokes Undo (Ctrl/Cmd+Z or toolbar) Then the document returns to the exact pre-insert state including numbering, spacing, and caret position And when the user invokes Redo, the identical content and formatting are restored at the same location And the history entry label reads "Insert clause"
Quick Preview With Live Merge
Given a clause is visible in the sidebar or search results When the user taps/clicks Preview Then a pane or modal shows a live-rendered preview with available variables merged and original formatting/styles applied within 500 ms And missing variables are annotated with placeholders and data-gap badges And selecting Insert from the preview produces identical output to direct insertion
Mobile And Desktop Single-Tap/Click Support
Given the editor is loaded on Chrome 122+, Edge 122+, Safari 17+, iOS Safari 17+, or Android Chrome 122+ When the user performs a single tap/click Insert from the sidebar or search results Then insertion and merge behave identically across platforms with no layout shift greater than 100 px And touch targets for Insert and Preview are at least 44x44 px and keyboard focus allows activation via Enter/Space And p95 insert time is <= 1200 ms on mobile and <= 800 ms on desktop
Style And Numbering Preservation In Complex Contexts
Given the insertion point is inside a numbered list, table cell, or a styled section with a custom numbering scheme When the clause is inserted Then numbering continues correctly without resetting surrounding lists or headings And table and paragraph styles are preserved or mapped to document equivalents when missing And no additional empty paragraphs are introduced before or after the inserted clause
Knowledge Base Versioning & Change Alerts
"As a solo managing many templates, I want to be alerted when rules change so that my clauses stay current without manual tracking."
Description

Manages versioned clause content and citations with effective dates and jurisdictional scope. Logs authorship and rationale changes, deprecates superseded clauses, and auto-updates recommendations when authorities change. Notifies users when an open draft or saved template is impacted, and allows pinning to a prior version with an override note for auditability.

Acceptance Criteria
Versioned Clause Storage with Effective Dates & Scope
Given a contributor creates a new clause version with effective start/end dates, jurisdictional scope, and citations When they save the version Then the system stores version metadata (version ID, parent clause ID, effective start, effective end/null, jurisdiction codes, citation IDs, author ID, rationale) And validates effective start <= effective end (or end is null) And prevents overlapping effective windows for the same parent clause and jurisdiction unless the new version is flagged as superseding And exposes the new version via API and UI search within 5 seconds of save
Auto-Update Recommendations on Authority Change
Given an authoritative source update is ingested that changes clause eligibility or required language When the knowledge base re-index job runs Then the recommendations engine reflects the new authoritative state within 10 minutes And superseded clause versions are marked Deprecated with a superseded-by pointer And new recommendations prefer the latest effective version for each jurisdiction And a system audit entry records the authority change ID and affected clause version IDs
Deprecation and Fallback Behavior at Insert Time
Given a user attempts to insert a deprecated or expired clause version via Clause Compass When the insert action is initiated Then the UI labels the clause as Deprecated and blocks default insertion And offers a one-click switch to the latest compliant version for the same jurisdiction/practice area And shows a concise plain-language rationale and citation diff And logs the user decision (switched vs. canceled) to analytics
Impact Alerts for Open Drafts and Saved Templates
Given a user has open drafts or saved templates containing affected clause versions When an authority change is published that impacts those versions Then the user receives an in-app banner and an email within 15 minutes enumerating impacted documents and clauses And each impacted draft shows an inline Update to vX.Y control with a side-by-side diff preview And applying the update replaces the clause content and citations without altering user-entered variables And the system records the update event in the audit log with user, timestamp, old/new version IDs
Pin to Prior Version with Override Note & Auditability
Given a user elects to keep a prior clause version despite a newer compliant version When they choose Pin to version on the clause instance Then the system requires an override note (minimum 20 characters) and a reason code selection And records user, timestamp, clause instance ID, pinned version ID, and note in an immutable audit log And displays a Pinned to vX.Y badge in the document and suppresses further update alerts for that instance And allows unpinning, which restores update alerts and is also logged
Authorship, Rationale, and Citation Change Logging
Given an editor updates a clause’s rationale text, required language highlights, or citations When the new version is published Then the system captures author ID, change summary, semantic diff of rationale, changed citation list, affected jurisdictions, and linked work item ID And exposes a version history timeline in the UI with time, author, and change summary And provides a CSV export of the change log with stable IDs for external audit And prevents deletion or modification of historical log entries
Jurisdiction Resolution and Scope Enforcement in Recommendations
Given a matter is tagged with jurisdiction metadata (e.g., state, federal district) and an as-of date When Clause Compass generates clause recommendations Then only clause versions whose jurisdiction scope includes the matter and whose effective window covers the as-of date are eligible And if no eligible version exists, the UI displays No compliant clause found with the nearest broader-scope alternative and disclaimer And unit tests cover a jurisdiction/date matrix with 100% pass rate for inclusion/exclusion logic And the recommendation API returns the evaluated scope decision per clause (eligible/ineligible with reason)

Variant Builder

Spin up jurisdiction-specific template variants from a single base. Changes cascade safely with side-by-side diffs, ensuring local compliance while keeping firm-wide consistency and reducing maintenance overhead.

Requirements

Template Inheritance & Override Engine
"As a template admin, I want to create jurisdiction variants that inherit from a base so that I can keep consistency while only overriding local differences."
Description

Provide a core engine that allows a base template to define shared content, variables, logic blocks, and styles. Jurisdiction-specific variants can override or extend sections at a granular level (clauses, paragraphs, fields, conditions) without copying the whole template. Changes to the base automatically cascade to variants unless explicitly overridden, preserving local deviations. The engine must support hierarchical inheritance (e.g., country > state > county > court), deterministic resolution order, and fallback behavior. Integrates with Briefly’s template DSL and data model, preserving variable bindings from guided questionnaires. The expected outcome is faster template maintenance, reduced duplication, and consistent firm-wide language while allowing compliant localizations.

Acceptance Criteria
Base changes cascade to non-overridden variant sections
Given a base template with Section A defined and a State variant with no override for Section A When the base Section A content is updated and the State variant is rendered Then the State variant output for Section A equals the updated base content And only Section A reflects the change; unrelated sections remain unchanged And the render completes successfully with no validation errors
Local override prevents base cascade
Given a base template with Section B defined and a County variant that overrides Section B When the base Section B content is changed and the County variant is rendered Then the County variant output for Section B remains as the local override And a diff between the County variant and its base marks Section B as overridden And descendants of the County variant inherit the overridden Section B unless they provide their own override
Deterministic hierarchical resolution and fallback
Given a hierarchy Country > State > County > Court where Section C is defined in Country, overridden in State, and undefined in County and Court When rendering the Court variant Then Section C resolves to the State override per nearest-ancestor-wins order Court → County → State → Country And repeated renders with the same inputs produce identical resolution results And if all ancestors lack Section C, the render succeeds by omitting Section C or using the configured fallback per DSL rules
Granular override and extension at clause, paragraph, field, and condition levels
Given a base clause with paragraphs P1 and P2, a conditional sub-block shown when isMinor is true, and a field clientName And a State variant that overrides P2, appends text to P1, adds a preface before the clause, and changes the condition to (isMinor OR isDependent) When rendering with isMinor = false, isDependent = true, clientName = "Alex" Then the output includes the preface, P1 with the appended text, P2 as overridden, and the conditional sub-block included based on the updated condition And unmodified parts of the clause continue to reflect any updates made in the base And no duplicate or missing paragraph identifiers occur in the output
Preservation of variable bindings and formatting rules through overrides
Given a base template that binds variables client.firstName and matter.filedDate with formatting rules And a County variant that overrides a block but does not redefine those variables When rendering the County variant with questionnaire data Then all variable references resolve without re-binding and use the base formatting rules And inherited sections produce identical values to the base for the same data And no undefined-variable or scope-collision errors are reported
Structured diff API reports provenance and change types
Given a State variant that overrides clauses X and Y and extends clause Z When requesting a diff between the State variant and its base Then the API returns a structured list where each affected block includes id, type, changeType in {overridden, extended, inherited}, and ancestorOrigin And unchanged blocks are listed or countable as inherited with lineage depth And diff generation completes within 500 ms for a template with 200 blocks on a standard build agent
Jurisdiction Metadata & Rule Validation
"As an attorney, I want templates to auto-select the correct jurisdictional variant so that my filings comply without manual checks."
Description

Introduce a structured metadata model to tag templates and variants with jurisdiction attributes (country, state, county, court, division), effective dates, and applicability conditions. Provide a rule engine to validate that a variant meets mandatory local requirements (e.g., caption format, service addresses, filing fees, signature blocks). Enforce selection at document assembly time based on matter metadata from intake, preventing assembly with mismatched jurisdictions. Surface validation errors with actionable guidance. Outcome: fewer compliance errors and auto-selection of the correct variant during assembly.

Acceptance Criteria
Auto-Select Variant by Matter Jurisdiction
Given a matter contains jurisdiction metadata (country, state, county, court, division) and an assembly date And the base template has one or more variants tagged with jurisdiction attributes, effective dates, and applicability conditions When the user initiates document assembly from the base template Then the system auto-selects the single variant whose specified jurisdiction attributes all match the matter metadata at the highest specificity level available And the variant is eligible only if effective_start <= assembly date <= effective_end (or no end) and its applicability condition evaluates to true And if multiple variants qualify, the system deterministically selects by specificity precedence (division > court > county > state > country), then by most recent effective_start, then by highest variant version And the selection decision is logged with variant_id, matched_attributes, precedence_reason, and timestamp
Prevent Assembly on Jurisdiction Mismatch
Given a matter contains jurisdiction metadata and assembly date And no variant meets all matching, effective date, and applicability criteria When the user attempts to assemble the document Then assembly is blocked and no document is generated And the user sees an error with code JURISDICTION_MISMATCH, listing which attributes failed to match and which criteria (date/condition) disqualified candidates And the error provides actionable options: review matter jurisdiction, choose a different template, or request/create a new variant (deep link) And the failure event is logged with matter_id, template_id, attempted_attributes, and candidate_count=0
Validate Mandatory Local Rules During Assembly
Given a selected variant has a ruleset including, at minimum: caption format, service addresses, filing fees, and signature block requirements When assembly executes Then each rule is evaluated and returns a structured result {rule_id, name, severity in [Error, Warning], status in [Pass, Fail], message} And assembly is blocked if any Error-severity rule status is Fail; assembly proceeds if only Warnings fail And the user sees a validation summary with counts (passed, failed_errors, failed_warnings) and per-rule messages And rule evaluation completes within 500 ms for up to 50 rules on a standard environment And the full validation report is persisted with the assembly run record
Effective Dates and Applicability Conditions Enforcement
Given a variant defines effective_start and optional effective_end (inclusive) and an applicability condition expression referencing matter/template fields When the assembly date is within the effective window and the condition evaluates to true Then the variant is considered eligible for selection and its rules are enforced When the assembly date is outside the effective window or the condition evaluates to false Then the variant is excluded from selection and its rules are not enforced And all date evaluations use the firm default timezone; boundary dates are inclusive And if no assembly date is provided, the system uses the current timestamp
Jurisdiction Hierarchy and Specificity Resolution
Given multiple variants exist at different specificity levels (e.g., state-only, county-level, court-level, division-level) When matching variants to a matter’s jurisdiction Then a variant matches if all of its specified jurisdiction attributes equal the matter’s corresponding attributes And the system chooses the most specific matching variant based on precedence: division > court > county > state > country And if only a less-specific variant matches, it is selected and assembly proceeds with that variant And the chosen precedence path and considered candidates are recorded in the selection log
Actionable Guidance for Validation Failures
Given one or more rule validations fail during assembly When the user views the error details Then each failed rule displays: rule_id, rule_name, failing value or location, expected format/reference, severity, and suggested fix And each message includes deep links to edit the relevant intake answer or template component And, where available, a jurisdictional citation or reference link is provided And the UI supports copying the full failure details to the clipboard in a single action
Side-by-Side Diff, Merge & Conflict Resolution
"As a managing attorney, I want to review and selectively merge base updates into variants so that local compliance is preserved while staying consistent."
Description

Provide an interactive viewer that displays differences between base and variant templates at token, paragraph, and logic-block levels, with syntax highlighting for the template DSL. Allow reviewers to accept or reject incoming base changes into variants, and to compare across variant hierarchies. Detect conflicts when both base and variant modify the same section and offer guided resolution. Include a change summary and impacted jurisdictions list. Outcome: safe propagation of updates with transparent visibility and control.

Acceptance Criteria
Multi-level diff rendering with DSL syntax highlighting
Given a base template and a variant template with changes at token, paragraph, and logic-block levels When the reviewer opens the side-by-side diff viewer Then a two-pane view renders with synchronized scrolling and stable line numbers And the default granularity is Paragraph When the reviewer switches granularity to Token Then inserted, deleted, and modified tokens are highlighted with distinct add/remove/modify colors and unchanged tokens are unstyled When the reviewer switches granularity to Logic Block Then changes to conditional/loop blocks and variables are highlighted with DSL-aware syntax coloring and block boundaries are visibly delineated And collapsed unchanged regions display an expand control with an accurate count of elided lines And the total number of highlighted changes matches the count shown in the change summary
Accept/reject incoming base changes into variant
Given a variant with pending incoming base changes visible in the diff viewer When the reviewer selects a change and clicks Accept Then the variant content updates to include the base change, the item status updates to Accepted, and the remaining pending count decrements by 1 And focus moves to the next unresolved change without scrolling jumps When the reviewer selects a change and clicks Reject Then the variant content remains as-is for that region, the item status updates to Rejected, and the remaining pending count decrements by 1 And the reviewer can undo or redo the most recent accept/reject action within the session
Conflict detection and guided resolution
Given both the base and the variant modified the same paragraph or logic block When the reviewer initiates merge Then the system flags a conflict and opens a 3-way diff with base, variant, and incoming versions clearly labeled And the reviewer can resolve by choosing Keep Variant, Take Base, or Edit Combined And live DSL validation prevents saving a resolution that contains syntax errors, showing an inline error message When all conflicts are resolved Then the merge can be finalized and no unresolved conflict indicators remain And a summary lists the number of conflicts and the chosen resolution type counts
Cross-hierarchy comparison (base, parent, child variants)
Given a hierarchy Base → State → County exists for a template When the reviewer selects any two nodes (e.g., Base vs County) for comparison Then the side-by-side viewer indicates for each section whether it is Inherited, Overridden, or Missing And navigation supports Next/Previous difference across the entire document When the reviewer enables tri-compare (Base vs State vs County) Then a three-pane view renders with synchronized scrolling and consistent difference counts across panes
Change summary and impacted jurisdictions panel
Given pending changes are loaded for a merge session When the reviewer opens the summary panel Then it displays counts of Adds, Deletes, Modifies, and Moves grouped by granularity (Token/Paragraph/Logic Block) And it lists impacted jurisdictions (variants) with per-variant counts and status (Pending/Accepted/Rejected/Conflicted) When the reviewer selects a jurisdiction filter Then the diff view filters to that variant scope and the counts update accordingly And clicking a summary item navigates to the first matching change in the viewer
Performance and mobile responsiveness
Given a template up to 250 KB (~5,000 lines, ~10k tokens) When the reviewer opens the diff viewer on a standard laptop Then initial render completes within 2 seconds and UI remains responsive during navigation When opened on a mid-range mobile device in portrait orientation Then initial render completes within 3 seconds and the layout adapts without horizontal scrolling of text content And Accept/Reject targets meet a minimum 44×44 px touch size and support swipe navigation between changes And applying Accept or Reject completes within 500 ms and preserves scroll position And the viewer maintains state (selected granularity, current change) across a page refresh
Safe Propagation & Release Management
"As an operations lead, I want staged releases and rollbacks for template changes so that I can deploy updates safely across jurisdictions."
Description

Implement versioning for base and variant templates, with draft, review, and released states. Provide bulk propagation workflows to apply base changes to selected variants, with preview, batch conflict detection, and rollback. Support release channels such as staging and production, and scheduled effective dates. Ensure changes are atomic and audit-safe; assemblies reference immutable version IDs for reproducibility. Outcome: controlled, low-risk rollouts and the ability to revert quickly if issues arise.

Acceptance Criteria
Version Lifecycle Governance
- Given a base or variant template is in Draft, when the author submits it for Review, then a new immutable versionId is recorded with state=Review. - Given a template is in Review, when an approver releases it, then the state changes to Released, editing is disabled, and further changes require creating a new Draft version with a new versionId. - Given a version is Released, when a user attempts to edit it directly, then the action is blocked with a clear message. - Given a version is in Draft or Review, when it is referenced by any scheduled or active release, then deletion is blocked; otherwise, deletion is soft and captured in the audit log.
Immutable Version IDs and Reproducible Assemblies
- Given a document assembly runs using a selected channel, when the assembly completes, then the record stores the exact baseVersionId and variantVersionId used. - Given the same inputs and the stored version IDs, when reassembling, then the output is text-equivalent to the original assembly. - Given versions are superseded or rolled back, when viewing past assemblies, then they still reference the original version IDs and remain reproducible.
Bulk Propagation Preview and Selection
- Given the base template has changes since last propagation, when the user opens Bulk Propagation, then the system lists all variants with status (Up-to-date, Conflict, Ready) and provides side-by-side diffs per variant. - Given the propagation screen, when the user selects a subset of variants, then only the selected variants are marked for apply; unselected variants are not modified. - Given a variant has no conflicts, when the user stages Apply, then a pre-apply summary shows the count of variants to update and the new versionIds that will be created.
Batch Conflict Detection and Blocking
- Given a variant contains local edits overlapping with incoming base changes, when precheck runs, then the variant is flagged as Conflict and the number of conflicting elements is displayed. - Given one or more selected variants are in Conflict, when the user attempts to apply, then the operation is blocked until conflicts are resolved or those variants are deselected. - Given conflicts are resolved, when precheck is re-run, then the variant status updates to Ready with zero conflicts.
Atomic Batch Apply and Rollback
- Given N selected variants pass precheck, when the user clicks Apply, then the system either creates new versions for all N variants or for none if any step fails, and returns a single batchId. - Given an error occurs during apply, when the operation completes, then no selected variant is left partially updated and the batch is marked Failed with error details. - Given a successful batch apply, when the user initiates Rollback for that batch, then the active channel pointers for all affected variants revert to the prior versionIds in a single transaction and an audit entry is created.
Release Channels and Scheduled Effective Dates
- Given a release is scheduled to Staging or Production at future timestamp T, when server time reaches T, then the channel’s active version switches to the scheduled version without user action. - Given multiple schedules exist for a channel, when T1 < T2, then the schedule at T1 activates first and does not skip order. - Given a scheduled release exists, when a user edits or cancels it before T, then the change is logged and the channel remains on its current active version until the next effective schedule. - Given a channel is specified during assembly, when the assembly starts, then the system resolves to the channel’s active version at request time.
Comprehensive Audit Trail
- Given any state change, propagation, release, rollback, or schedule change occurs, when viewing the audit log, then an entry exists with timestamp, actor, action type, affected templates/variants, before/after versionIds, and batchId if applicable. - Given an audit entry is created, when attempting to modify or delete it, then the action is blocked and only append-only entries are allowed. - Given a batch apply or rollback completes, when exporting the audit report, then the export includes a machine-readable record sufficient to reconstruct the set of active versions per channel at any timestamp.
Clause Library with Rule-Based Insertion
"As a practitioner, I want jurisdiction-aware clauses to auto-insert based on facts so that my first drafts are accurate without manual edits."
Description

Maintain a centralized clause library tagged by jurisdiction, matter type, and conditional logic. Enable variants to reference clauses by rule rather than copy-paste, allowing automatic inclusion or exclusion based on intake answers such as county, party role, or amount in controversy. Provide preview of clause resolution within variants and guardrails to prevent conflicting clauses. Outcome: reusable, compliant content that stays in sync across variants.

Acceptance Criteria
Auto-insert jurisdiction and matter-type clauses
Given a base template that references rules for clause inclusion And a clause library where clauses are tagged by State="CA" and MatterType="Debt Collection" And an intake with jurisdiction.state="CA" and matter_type="Debt Collection" When the variant is assembled Then all clauses matching State=CA AND MatterType=Debt Collection are included exactly once And no clauses with non-matching tags are included And a rule resolution report lists included and excluded clause IDs and rule evaluations
Conditional clauses by party role and amount thresholds
Given a clause with rule: party_role == "Plaintiff" AND amount_in_controversy >= 10000 And an intake with party_role="Defendant" and amount_in_controversy=20000 When the variant is assembled Then the clause is excluded Given an intake with party_role="Plaintiff" and amount_in_controversy=8000 When the variant is assembled Then the clause is excluded Given an intake with party_role="Plaintiff" and amount_in_controversy=15000 When the variant is assembled Then the clause is included
Inline preview of clause resolution in Variant Builder
Given a variant that references clauses by rule And a set of test intake answers is applied in Preview mode When Preview Resolved Clauses is invoked Then the editor displays resolved clause content inline And each clause shows an Include or Exclude badge with the evaluated rule And a summary shows counts of Included, Excluded, and Conditional clauses And no changes are persisted from Preview mode
Conflict detection for mutually exclusive clauses
Given two clauses tagged as MutuallyExclusiveGroup="ArbitrationVsJury" And rules evaluate both clauses to include for the current answers When the variant is assembled or previewed Then assembly is blocked with a clear conflict message listing clause names and rule paths And the user must choose one clause, adjust rules, or cancel before proceeding And the system prevents publishing a variant with unresolved conflicts
Cascade clause updates with side-by-side diffs
Given Clause C is referenced by Variants V1, V2, and V3 And Clause C text is edited and published to the library When V1, V2, and V3 are opened Then each variant displays an update banner with a side-by-side diff of Clause C (previous vs current) And on assembly, each variant uses the updated Clause C content without manual copy-paste And the diff view records the clause version applied in each assembly log
Rule authoring validation and test matrix
Given a new or edited clause rule When the rule is saved Then the system validates syntax, field references, and tag existence and blocks save with specific errors if invalid And a Test Inputs panel allows entering sample answer sets and shows Include/Exclude results in real time And users can export a CSV of test cases with inputs, expected outcome, and actual outcome
Assembly performance under high clause count
Given an intake that triggers evaluation of 200 clause references When the variant is assembled Then rule evaluation and clause assembly complete within 2 seconds at the 95th percentile and 4 seconds at the 99th percentile on baseline hardware And the system returns a complete resolution report with zero timeouts or partial results
Role-Based Permissions & Approvals
"As a template administrator, I want approval gates on template changes so that only authorized, reviewed updates go live."
Description

Define granular roles and permissions controlling who can create, edit, approve, and release base templates versus jurisdiction variants. Require configurable approval chains for high-risk jurisdictions or global changes. Integrate with firm SSO and maintain separation of duties. Outcome: governance that reduces risk of unauthorized or non-reviewed changes.

Acceptance Criteria
SSO Role Mapping and Deprovisioning
Given SSO (SAML/OIDC) is configured with group-to-role mappings (e.g., Briefly-BaseOwner → Base Template Owner, Briefly-VariantEditor → Variant Editor, Briefly-Approver → Approver, Briefly-Publisher → Publisher, Briefly-Viewer → Viewer) When a user logs in with SSO asserting Briefly-VariantEditor and Briefly-Viewer Then the user is assigned Variant Editor and Viewer roles only Given a user is removed from all Briefly-* groups in the IdP When the user’s session refreshes or they next log in Then access to Briefly is revoked and active sessions are invalidated within 15 minutes Given an IdP asserts an unrecognized group When the user logs in Then no elevated permissions are granted and the group is ignored Given a user’s group membership changes in the IdP When the user next logs in or their token refreshes Then new permissions apply without manual admin intervention
Permission Enforcement for Base Templates vs Jurisdiction Variants
Given a user has Variant Editor role for TX and FL only When they attempt to create or edit a CA variant or any base template Then the UI disables those actions and the API returns 403 PERMISSION_DENIED Given the same user edits a TX variant When they save Then the draft saves successfully and they cannot self-approve or release it Given a user has Base Template Owner role only When they attempt to edit a jurisdiction variant Then they have read-only access unless also assigned Variant Editor for that jurisdiction Given a user has Viewer role only When they access Variant Builder Then all edit/approve/release controls are hidden and API mutations return 403 Given any user without Publisher role When they attempt to release a base template or variant Then release is blocked with a clear error and a 403 response from the API
Configurable Approval Chains by Risk and Scope
Given firm policy config: High-risk jurisdictions require 2 Approvers and a separate Publisher; Medium-risk require 1 Approver and a separate Publisher; Global base changes require 3 Approvers and a separate Publisher When an author submits a draft change for a High-risk jurisdiction (e.g., CA) Then the system requires approvals from 2 distinct approvers (not the author) and blocks release until collected Given a draft affects multiple jurisdictions with differing risk When computing required approvals Then the highest applicable approval requirement is enforced Given any draft with one or more approvals recorded When the draft content is modified Then prior approvals are invalidated and must be re-obtained Given all required approvals have been collected When a Publisher attempts to release Then release succeeds; if any approval is withdrawn pre-release, release is blocked Given no explicit policy exists for a jurisdiction When an approval chain is needed Then the system applies the default policy (configurable) and logs the policy used
Separation of Duties at Author, Approver, Publisher Stages
Given a user authored a change When they attempt to approve or publish that change Then the actions are blocked and the API returns 403 SELF_APPROVAL_BLOCKED Given a user has approved a change When they attempt to publish that same change Then publishing is blocked unless policy explicitly allows approver-as-publisher; default is blocked Given the only available approver is the author When an approval is requested Then the system prevents selection and prompts for an eligible, distinct approver Given a global base template change When roles are assigned for workflow Then at minimum three distinct individuals are required: one author, one approver, and one publisher
Mandatory Side-by-Side Diff in Approval Workflow
Given a draft has pending approvals When an approver opens the approval task Then a side-by-side diff of all textual/structural changes and affected jurisdictions/clauses is displayed Given the approval screen is open When the diff has not been opened and the reviewer attest checkbox is unchecked Then the Approve action is disabled and cannot be triggered via API Given diff generation fails When an approver attempts to approve Then approval is blocked with an explicit error; blind approvals are not permitted Given an approval is recorded When storing the approval artifact Then a snapshot of the reviewed diff and reviewer notes is persisted with the approval record
Comprehensive Audit Trail and Evidence Export
Given any create, edit, submit, approve, reject, withdraw, release, or permission change occurs When the action completes Then an immutable audit entry is recorded with UTC timestamp, actor SSO subject, roles, action, object IDs, prior/new version IDs, change hash, IP, and outcome Given an auditor requests an export for a template/variant and date range When the export is requested Then the system produces a CSV or JSON export within 60 seconds containing all relevant entries and approval artifacts (diff snapshots, comments) Given a permission denial (403) occurs for a protected action When logging the event Then an audit entry records the target action, reason, and user context Given the log retention period elapses (default 7 years, configurable) When archival runs Then logs are archived in a tamper-evident store and remain queryable by authorized auditors
Audit Trail & Variant History
"As a compliance officer, I want a detailed audit trail of variant changes so that we can evidence control and trace issues."
Description

Capture a complete, immutable history of changes to base and variant templates, including who changed what, when, and why via change notes, plus diffs, approvals, and release versions. Provide exportable reports and searchable timeline views by jurisdiction. Link assembled documents back to the exact template version used. Outcome: defensible compliance records and easier troubleshooting.

Acceptance Criteria
Immutable Change Log with Required Change Notes
Given a user edits any base or variant template, When they click Save, Then the system writes an append-only audit event containing template ID, variant ID (if applicable), actor ID, actor role, UTC timestamp, action type, change note (required, >=5 characters), and pre/post content hashes. Given the change note is missing or <5 characters, When Save is attempted, Then the save is blocked with a validation error and no audit event is created. Given any user (including admins) attempts to alter or delete an existing audit event via API or UI, When the request is made, Then the system returns 403 Forbidden and no event is changed; a security event is logged. Given an audit event ID, When its integrity is verified, Then its checksum validates against the stored signature and the payload has not been modified.
Side-by-Side Diff and Field-Level Changes
Given two selected template versions (base or variant), When the diff view is opened, Then a side-by-side diff renders within 2 seconds for templates up to 200k characters, highlighting insertions, deletions, and modifications at token level. Given a template with structured fields, When viewing the diff, Then field-level changes (added/removed/modified fields and default values) are listed with before/after values. Given a diff is viewed, When the user exports the diff, Then a PDF and CSV export is generated that preserves highlights and includes version IDs and timestamps.
Approval Workflow and Release Tagging
Given a draft template version, When a user with approver role reviews it, Then they can Approve or Reject with a comment; the decision, approver ID, and UTC timestamp are recorded immutably. Given a version is Approved, When it is released, Then a release tag is assigned, release notes are required, and the content is snapshotted read-only; subsequent edits require a new draft version. Given a version lacks approval, When a release is attempted, Then the system blocks release and explains required approver(s).
Jurisdiction Timeline Search and Filters
Given a jurisdiction and date range filter, When the timeline is queried, Then only matching audit events for the base and associated variants in that jurisdiction are returned, sorted by time descending. Given a keyword, actor, action type, or template ID filter, When applied with a jurisdiction filter, Then the result set reflects the intersection of filters. Given a dataset of up to 100k audit events, When a timeline query is run, Then 95% of responses complete within 2 seconds and 99% within 5 seconds.
Exportable Audit Reports
Given a set of filtered timeline results, When Export is requested, Then the system generates downloadable CSV and PDF files containing all visible columns, applied filters, generation timestamp, and a file checksum. Given an export is completed, When the file is opened, Then it includes per-event details (event ID, template/variant IDs, version IDs, actor, action, UTC timestamp, change note, approval/release state) and, if requested, an embedded or linked diff snapshot. Given an export link is created, When 24 hours elapse, Then the link expires and further access returns 410 Gone.
Assembled Document Traceback to Exact Template Version
Given a document is assembled, When the assembly completes, Then the document metadata stores and displays the exact template version ID and variant ID used, the release tag, and a link to the diff from its base. Given a stored assembled document, When viewed in the UI or fetched via API, Then a one-click link navigates to the template version details and audit trail used at assembly time. Given the underlying template later changes, When viewing the assembled document, Then its recorded version linkage remains unchanged and clearly marked as historical.
Lineage Across Base and Variants
Given a variant is created from a base version, When lineage is viewed, Then the system displays parent base version ID, derivation timestamp, and divergence points with diffs. Given a variant receives updates while the base evolves, When lineage is viewed, Then the timeline shows merge or rebase events with approver decisions and notes. Given a lineage graph is rendered, When exported, Then it includes all nodes and edges with IDs and timestamps and is included in the audit report.

Field Harmonizer

Normalizes field names across imported forms (e.g., SSN vs. Social_Security_Number), merges duplicates, and enforces a reusable schema that drives questionnaires and documents. Eliminates retyping and keeps data flowing cleanly across matters.

Requirements

Canonical Schema Registry & Versioning
"As a firm admin, I want a versioned canonical field schema so that all questionnaires and documents stay consistent even when imported forms use different labels."
Description

Provide a central, versioned registry of canonical data fields (e.g., Social Security Number, Date of Birth, Client Address) with metadata including field keys, display labels, data types, validation rules, requiredness, default values, and relationships. The registry must support schema versioning (draft, active, deprecated), backward compatibility policies, and deprecation workflows to evolve the schema without breaking existing questionnaires or document templates. It exposes read/write APIs and SDK hooks so intake questionnaires, document assembly, and e‑sign flows always reference canonical fields instead of raw import names. Firm-level extensions allow adding custom fields and aliases while inheriting platform defaults, ensuring consistent data flow across matters and minimizing rework when forms change.

Acceptance Criteria
Create and publish canonical field with metadata
Given an admin supplies key "person.ssn", displayLabel "Social Security Number", dataType "string", validation /^\d{3}-\d{2}-\d{4}$/, required false, default null, and relationship "person" When they POST to /fields with this payload Then the registry stores the field as version Vn in state "draft", returns 201 with {id, version: Vn}, and an audit record is written And GET /fields/{id} returns the exact metadata persisted And POST /versions/{Vn}/activate sets state to "active" and there is at most one active version per field key And attempting to create another field with key "person.ssn" returns 409 Conflict
Versioning and immutability with backward-compatible revisions
Given field key "person.address" exists with active version V1 When an editor attempts to change its dataType or validation Then the system creates a new version V2 in state "draft" and V1 remains immutable And POST /versions/{V2}/activate sets V2 to "active" and sets V1 to "deprecated" And GET /schema/diff?from=V1&to=V2 flags breakingChange=true for dataType changes and lists impacted templates/questionnaires And any questionnaire or template pinned to V1 continues to resolve without errors after V2 activation And attempts to edit an "active" version directly return 409 Conflict
Alias normalization from imported forms
Given an import payload contains fields ["SSN", "Social_Security_Number", "Client SS No."] with values And the registry defines aliases ["SSN", "Social_Security_Number", "Client SS No."] -> canonical "person.ssn" When the Field Harmonizer runs Then the normalized record contains a single field "person.ssn" with value chosen by configured source precedence (firm-level) and logs the chosen source And conflicting non-equal values are resolved deterministically and a warning event with traceId is emitted And unknown import fields are returned in an "unmapped" list with suggestions when alias similarity >= 0.8 And normalization of 1000 input fields completes within 500ms at P95
Firm-level extensions and inheritance
Given firm F creates custom field key "firmF.employer_name" (dataType "string") and alias "Work_Employer" When firm F calls GET /schema?scope=firm Then the response includes platform canonical fields plus firm F custom fields, each annotated with {scope: "platform"|"firm"} And aliases defined by firm F apply only within firm F; GET from firm G does not return them And firm F may override displayLabel of "person.ssn" but attempts to change its dataType or key return 403/422 with explanation And templates and questionnaires within firm F can persist and resolve both "person.ssn" and "firmF.employer_name" without collisions
Deprecation workflow and usage warnings
Given field "person.middle_name" is set to state "deprecated" with sunsetDate D and replacement "person.middle_initial" When an existing template referencing "person.middle_name" is opened before date D Then the UI and API return a deprecation warning and show the suggested replacement And creating a new template/questionnaire that adds a reference to a deprecated field requires explicit override and logs an event When date D passes Then creating new references to the deprecated field is blocked with 422 and suggestion to use the replacement, while existing matters pinned before D still resolve And GET /deprecations returns all deprecated fields with {replacement, sunsetDate, usageCount}
Read/write APIs and SDK hooks
Given a caller with token scope schema:read When they GET /schema?version=active Then the API returns 200 with the full canonical field list including metadata and relationships within 200ms P95 Given a caller with token scope schema:write When they POST /fields with an Idempotency-Key header Then the API returns 201 with {id, etag}; repeating the same request returns 200 and the same resource per idempotency And POST /versions/{id}/activate enforces state transitions and emits an audit event with actor, timestamp, and change summary And errors are returned as application/problem+json with traceId and machine-readable codes And the SDK method resolveFields(inputMap) maps raw names to canonical keys per registry and achieves ≥99% alias resolution on a seeded test set
Runtime validation enforcement across flows
Given a questionnaire input bound to canonical "person.ssn" When a user enters an invalid value (not matching /^\d{3}-\d{2}-\d{4}$/) Then the UI blocks progression and shows a localized error; a valid value allows progression and persists the canonical field value And document assembly replaces placeholders using canonical keys and applies defaults for missing optional fields And e-sign fields are named by canonical keys; upon signature, values are saved back to the matter using the same keys and versions And validation failures and successful mappings emit events containing {fieldKey, version, correlationId} for observability
Synonym Mapping & Normalization Engine
"As a paralegal, I want imported fields like 'SSN' to automatically map to our canonical 'Social Security Number' so that I don’t waste time fixing labels by hand."
Description

Implement an engine that normalizes imported field names by stripping punctuation, underscores, and casing differences, and maps them to canonical fields using tokenization, fuzzy matching, and a domain-specific synonym dictionary (e.g., SSN ↔ Social Security Number, DOB ↔ Date of Birth, Phone # ↔ Phone_Number). The engine assigns confidence scores, auto-accepts high-confidence matches, and queues low-confidence candidates for human review. Supports firm-specific custom aliases, locale variations, and abbreviation expansion. Runs at import time and on-demand during questionnaire/template editing to keep data aligned without manual retyping.

Acceptance Criteria
Import: High-Confidence Auto-Accept Normalization
Given the auto-accept threshold τ=0.90 (org default) and an imported form with headers ["SSN", "Phone #", "DOB"], When the engine runs at import time, Then those headers are normalized and mapped to ["social_security_number", "phone_number", "date_of_birth"] with confidence ≥ τ and are auto-accepted without human review. Given multiple variant headers ["Social Security Number", "S.S.N."] in the same import, When normalization runs, Then both map to the single canonical field "social_security_number" and no duplicate canonicals are created. Given an auto-accepted mapping, When the import is saved, Then the source-to-canonical mapping, confidence score, timestamp, and reason codes are persisted to the audit log.
Import: Low-Confidence Queue for Human Review
Given the auto-accept threshold τ=0.90 and an imported header "ID", When the top match confidence < τ, Then the field is not auto-mapped and a review task is created with the top 3 suggestions and their confidence scores. Given a review task exists, When a user selects a canonical field and confirms, Then the mapping is saved with the selected canonical and confidence marked as "human_approved" and the task is resolved. Given a review task exists, When no action is taken, Then the unmapped field is labeled "needs_review" and is prevented from flowing into questionnaires/templates until resolved.
Firm-Specific Custom Alias Overrides Global Synonyms
Given a firm-level alias "Client Phone" → "phone_number", When an import contains a header "Client Phone", Then it maps to "phone_number" with confidence = 1.0 and reason = "firm_alias" regardless of global dictionary suggestions. Given a conflict between a firm alias and a global synonym, When normalization runs, Then the firm alias takes precedence and no warning is raised. Given a firm alias is updated, When normalization is re-run on the same source, Then previous mappings using the old alias are updated to the new target canonical and the change is logged.
Locale-Aware Synonym Resolution for Address and IDs
Given matter locale = "en-GB" and header "Postcode", When normalization runs, Then it maps to canonical "postal_code" with reason including locale = "en-GB". Given matter locale = "en-US" and headers ["ZIP Code", "Zip"], When normalization runs, Then they map to "postal_code" with reason including locale = "en-US". Given a locale-specific synonym conflict (e.g., "NIN" in en-GB vs "SSN" in en-US), When normalization runs per matter locale, Then the locale-appropriate canonical is selected and no cross-locale synonym is applied.
Abbreviation, Punctuation, and Casing Normalization
Given headers ["S.S.N.", "social_security-number", "Phone#", "DOB", "Date Of Birth"], When normalization runs, Then punctuation, underscores, hyphens, symbols, and casing are stripped/standardized and tokens expanded so they map to ["social_security_number", "social_security_number", "phone_number", "date_of_birth", "date_of_birth"]. Given a header "SSN Last 4", When normalization runs, Then it maps to the more specific canonical "ssn_last4" (if present in schema) and not the parent "social_security_number". Given a header contains stop-words (e.g., "the client's date-of-birth"), When normalization runs, Then stop-words are ignored and the correct canonical "date_of_birth" is selected.
On-Demand Normalization During Questionnaire/Template Editing
Given a template editor adds a field label "Date of Birth", When the engine evaluates on-demand, Then a suggestion for canonical "date_of_birth" with confidence ≥ 0.90 appears within 500 ms (95th percentile) and can be accepted with one action. Given a suggestion is accepted, When the template is saved, Then the mapping is persisted and the template field is linked to the canonical so future imports flow into it without manual retyping. Given the editor renames the field label, When the confidence of the existing mapping would drop below τ, Then the engine prompts for review and does not silently remap.
Confidence Scoring, Thresholding, and Determinism
Given identical input headers and dictionaries, When normalization is run multiple times, Then the confidence scores and selected canonicals are deterministic and identical across runs. Given the org changes the auto-accept threshold from 0.90 to 0.95, When normalization runs, Then mappings with 0.90 ≤ confidence < 0.95 are no longer auto-accepted and are queued for review. Given a mapping decision, When inspection is requested, Then the engine exposes the computed tokens, applied synonyms, locale, and reason codes that justify the confidence score.
Duplicate Detection & Merge Rules
"As an intake specialist, I want duplicate fields to be merged into one canonical value so that I avoid conflicting or repeated questions to clients."
Description

Detect and consolidate duplicate fields across and within imported forms by comparing normalized keys, semantics, and data types. Provide configurable merge policies (e.g., prefer non-empty, prefer latest timestamp, form priority, or human approval required) and preserve provenance to trace the origin of each value. Ensure idempotent merges and conflict flags when values disagree. Output a single canonical field per concept to eliminate redundancy and prevent downstream errors in questionnaires and document assembly.

Acceptance Criteria
Detect Duplicates by Normalized Keys and Semantics
Given imported forms contain semantically equivalent fields and a configured alias dictionary and normalization rules When the Field Harmonizer runs duplicate detection Then fields are grouped into a single duplicate cluster per concept using normalized keys, alias matches, and compatible data types And groups exclude fields with incompatible data types or conflicting semantic tags And each group receives a confidence score between 0.00 and 1.00 And detection achieves ≥95% recall and ≥98% precision on the maintained alias test set And the system records a group_id and member source metadata for each grouped field
Configurable Merge Policies per Field
Given a system default merge policy and per-field overrides and form priorities are configured When merging a duplicate group Then the effective policy resolution order is: per-field override > form priority > system default And Prefer Non-Empty selects the first non-empty (post-trim) value by the policy order And Prefer Latest Timestamp selects the value with the greatest updated_at; ties break by ascending source_id And Human Approval Required creates a pending conflict and does not commit a canonical value And the applied policy and decision rationale are persisted in the audit log
Idempotent Merge Execution
Given a matter with duplicate groups and a configured policy set When merge is executed multiple times on unchanged inputs Then the canonical field values and their identifiers are identical across runs And re-importing a previously processed form does not produce new groups or alter canonical values And concurrent merge executions result in a single consistent outcome without race conditions
Conflict Detection and Human Approval Workflow
Given a duplicate group with disagreeing values and a policy that cannot auto-resolve or requires human approval When the merge process evaluates the group Then a conflict record with status "Pending" is created containing all candidate values and their provenance And the conflict appears in the review queue within 2 seconds of detection And the canonical field remains unset until a reviewer approves a value And upon approval, the canonical value is committed, the conflict is marked "Resolved", and all actions are logged with timestamps and user IDs
Provenance and Audit Trail Preservation
Given a canonical field value is committed When a user inspects provenance via API or UI Then the system returns: source form IDs, original field names, source value hashes, timestamps, applied policy, decision rationale, and user IDs (if human approval) And an immutable checksum (SHA-256) of the provenance record is stored And matter export includes provenance for each canonical field And access to provenance is restricted to authorized roles only
Canonical Schema Enforcement and Downstream Compatibility
Given a reusable schema defines the canonical key and data type for a concept When duplicates are merged Then exactly one canonical field exists matching the schema key and data type And all downstream references (questionnaires, document tokens) resolve to the canonical key And attempts to reference non-canonical or deprecated keys raise validation errors at build time And schema-level validations (e.g., SSN format) are enforced on the canonical value
Mapping Review UI with Smart Suggestions
"As a firm admin, I want an interface to review and approve suggested field mappings so that I can control accuracy without slowing down intake."
Description

Deliver an admin interface to review, approve, or edit suggested mappings at scale. Show suggested canonical matches with confidence scores, highlights of matching tokens, and reasons. Support bulk actions, keyboard shortcuts, search/filter, and quick-add of new aliases. Provide an impact preview showing which questionnaires and templates are affected before changes are applied. Integrate into Briefly’s settings and per‑matter import flows with proper access controls so firms can curate mappings quickly and safely.

Acceptance Criteria
Smart Suggestions with Confidence and Reasons
Given an authorized admin opens the Mapping Review UI for an import with unmapped fields When the suggestions list loads Then each row displays the source field label and raw key, the proposed canonical field, an integer confidence percentage (0–100), highlighted matching tokens in both names, and at least one textual reason for the suggestion And the list is sorted by confidence descending by default And reasons are viewable without leaving the list (inline or expandable)
Approve or Edit a Single Suggestion
Given a suggestion is visible in the list When the user clicks Approve Then a mapping is created from the source field to the proposed canonical field And the suggestion moves out of the Unreviewed view and appears as Approved within 1 second Given a suggestion is visible in the list When the user clicks Edit Then an edit dialog opens allowing selection of a different canonical field and management of aliases And duplicate/invalid alias entries are prevented with inline validation Given an approval or edit would change existing assets When the user initiates Save Then an impact preview lists affected questionnaires and templates with counts and names And changes are only applied after the user confirms
Bulk Approve and Assign via Selection
Given multiple suggestions are selected via checkboxes or Select All (respecting current filters) When the user chooses Bulk Approve Then the system applies all selected mappings atomically And on success a confirmation shows the count applied; on failure no mappings are changed and the error lists failed items Given multiple suggestions are selected When the user chooses Bulk Assign to Canonical and selects a canonical field Then all selected sources are mapped to the chosen canonical field subject to validation And an impact preview summarizes total affected questionnaires/templates and requires confirmation before apply Given 100 suggestions are selected When Bulk Approve is applied in the test environment Then the operation completes within 5 seconds
Search, Filter, and Keyboard Shortcuts for Fast Review
Given the Mapping Review UI is open When the user types in the search box Then the list filters by substring match across source and canonical names within 200 ms for 1,000 suggestions Given filter controls for confidence, data type, and review status When the user adjusts any filter Then only matching suggestions are shown and selection counts update accordingly Given focus is in the suggestions list When the user presses J or K Then the active row moves down or up respectively Given focus is in the suggestions list When the user presses A Then the active row is approved Given focus is in the suggestions list When the user presses E Then the Edit dialog opens for the active row Given the Mapping Review UI is open When the user presses / or F Then the search box gains focus Given the Mapping Review UI is open When the user presses ? Then a shortcuts legend is displayed
Quick-Add New Alias to Canonical Field
Given the Edit dialog is open for a suggestion When the user enters a new alias string and chooses Add Alias to the selected canonical field Then the alias is validated case-insensitively with normalization of spaces/underscores And if unique it is added to the canonical field and the current source maps to it And if not unique an inline error explains the conflict without closing the dialog Given a new alias is successfully added When the user closes the dialog Then the alias appears in the schema’s alias list and is available to future imports without a page reload
Access Control and Entry Points
Given a user without the Manage Field Mappings permission When they navigate to the Mapping Review UI via menu or direct URL Then access is denied (403 or gated screen) and the navigation entry is hidden Given a user with the Manage Field Mappings permission When they navigate to Settings > Data Schema > Field Harmonizer Then the Mapping Review UI loads successfully Given a per-matter import contains unmapped fields When a permitted user reaches the Review Field Mappings step Then an embedded Mapping Review UI appears scoped to the matter And any changes that affect the firm-wide schema require explicit confirmation with impact preview before applying
Schema Enforcement & Validation Pipeline
"As an attorney, I want the system to enforce canonical fields and validations so that my documents assemble correctly without data errors."
Description

Enforce the canonical schema across intake questionnaires and document assembly with real-time validation. Validate data types (e.g., SSN mask and checksum, date formats, phone formats), requiredness, and regex patterns; support cross-field rules (e.g., if Client_is_Minor then Guardian_Name required). Provide clear inline error messages in mobile and desktop, preflight checks before e‑sign, and structured error codes for analytics. Block non-canonical field references in templates and guide authors to mapped fields, ensuring clean, reusable data across matters.

Acceptance Criteria
SSN Format and Invalid Range Validation
Given the canonical field key "Client.SSN" on an intake form When the user types into the SSN field Then the input is masked as XXX-XX-XXXX and non-numeric characters are rejected Given a completed SSN value When validation runs Then it fails if area is 000, 666, or 900-999, group is 00, or serial is 0000; otherwise it passes Given an invalid SSN When the user blurs the field or attempts to continue Then an inline error "Enter a valid SSN in the format XXX-XX-XXXX" with code "VAL.SSN.INVALID" is shown and progression is blocked Given a previously invalid SSN When corrected to a valid value Then the error state clears within 300ms and the form allows progression
Cross-Field Dependency for Minor Client
Given canonical fields Client.DateOfBirth, Client_is_Minor, Guardian_Name, and Guardian_Relationship When DateOfBirth indicates age < 18 or Client_is_Minor is true Then Guardian_Name and Guardian_Relationship are required Given the above condition is met When either guardian field is empty Then inline errors with codes "VAL.GUARDIAN.REQUIRED" display and the section cannot be completed Given age ≥ 18 and Client_is_Minor is false When validating Then guardian fields are optional and no dependency errors are raised Given the dependency condition changes due to user edits When recalculated Then requirement states update in real time without a page reload
Regex and Requiredness Enforcement Across Canonical Fields
Given the canonical schema specifies required flags and regex patterns for fields When a required field is left blank Then an inline error "This field is required" with code "VAL.REQUIRED" appears and progression is blocked Given a field with a regex rule (e.g., PostalCode: ^\d{5}(-\d{4})?$) When the value does not match the pattern Then an inline error with code "VAL.REGEX.MISMATCH" appears and the field is marked invalid Given multiple invalid fields on the current step When the user attempts to continue Then focus moves to the first invalid field and an error summary lists all errors and counts
Preflight Validation Before E-Sign
Given a matter is ready to send for e-sign When the user clicks "Send for e-sign" Then a preflight runs all schema and cross-field validations across the questionnaire and mapped templates and completes within 2 seconds at p95 Given any blocking errors are found When preflight completes Then the send action is blocked, a modal lists each error with field label, location, and error code, and deep links navigate to each issue Given only warnings are found When preflight completes Then the user may proceed after acknowledgment, and warnings are logged with codes and timestamps Given all validations pass When preflight completes Then the e-sign request is dispatched and a success event with validation_passed=true is logged
Structured Error Codes Emitted for Analytics
Given any validation rule fails When the error is presented to the user Then a structured event is emitted containing: error_code, canonical_field_key, rule_id, severity, platform (mobile/desktop), and timestamp, with no PII values Given analytics is reachable When an event is emitted Then it is sent at 100% sample rate for errors and retried up to 3 times on transient failures Given analytics is unreachable When retries are exhausted Then events are queued locally and flushed upon restored connectivity
Template Authoring Guardrails for Canonical Fields
Given a template author enters a field token When the token does not match a canonical field Then insertion is blocked and an inline suggestion panel offers mapped canonical fields from the Harmonizer Given a non-canonical token exists in an imported template When the author attempts to save Then save is blocked until each token is mapped or removed, with a count of unresolved tokens and error code "TPL.FIELD.NONCANONICAL" Given a suggested mapping is selected When applied Then the template replaces the token with the canonical key and passes validation
Desktop Inline Error Messaging and Accessibility
Given validation errors exist on desktop When they render Then each error message is immediately below the field, meets WCAG AA contrast (>=4.5:1), includes role=alert, and aria-describedby links to the message Given the user submits with errors on the page When the page processes the submit Then keyboard focus moves to the first error and screen readers announce the error text Given an error is corrected When the field revalidates Then aria-invalid is removed and the error message disappears within 300ms
Audit Trail & Rollback for Field Mappings
"As a compliance-minded practitioner, I want a full audit trail with rollback for field mappings so that I can recover from mistakes and meet audit requirements."
Description

Record a complete, immutable history of mapping and schema changes, including who made the change, when, what changed, and impacted assets (questionnaires, templates, active matters). Provide diff views, change reason notes, and approvals. Allow safe rollback to prior schema or mapping states and offer staged rollout with notifications when changes may break templates. Export logs for compliance and create alerts when high-risk fields (e.g., SSN) mappings are edited.

Acceptance Criteria
Immutable Audit Log for Mapping and Schema Changes
Given I am an authenticated user with permission to modify field mappings or schema When I create, update, or delete a field mapping or schema element via UI or API Then the system writes an append-only audit record containing: actor user ID and role, action (create|update|delete), entity type (mapping|schema), entity ID, timestamp (UTC ISO-8601), request ID, source IP, before payload (for update/delete), after payload (for create/update), change reason note, and impacted assets (counts and IDs for questionnaires, templates, active matters) And the audit store links the record in a tamper-evident hash chain and returns the new record hash And the modification is rejected with an error if the audit write fails And read APIs expose the record within 2 seconds of commit And a reason note is required for update/delete and must be at least 10 characters
Human-Readable Diff View With Impact Summary
Given a recorded mapping or schema change exists When I open the change details view Then I see a side-by-side diff highlighting added, removed, and modified fields including name, type, format, validation rules, and mappings And breaking changes (field removal, type narrowing, required flag added) are flagged with severity levels (warning|critical) And I see counts and direct links to impacted templates, questionnaires, and active matters And I can download the diff as JSON and PDF And the diff renders in under 1 second for changes affecting up to 500 fields
High-Risk Field Edit Alerts and Approval Gate
Given a field (e.g., SSN) is tagged as High Risk in admin settings When a user proposes a mapping or schema change that touches a High Risk field Then a reason note is required (minimum 20 characters) And the change enters a Pending Approval state and is blocked from production deployment until approved by a user with Approver role And approvers receive in-app and email alerts within 60 seconds containing the diff and impact summary And the audit record captures approver ID, decision (approve|reject), timestamp, and approver comments And if no decision occurs within 24 hours, reminder notifications are sent hourly to approvers And any attempt to bypass approval is blocked and logged as a security event
Safe Rollback to Prior Version With Validation
Given prior versions of the field schema and mappings exist When I select a target version and initiate a rollback Then the system performs a dry-run validation that lists conflicts and impacted assets with expected outcomes And I must provide a rollback reason note (minimum 10 characters) And on confirmation, the system creates a new version matching the target state, revalidates affected active matters without data loss, and logs a rollback audit entry linking source and target version IDs And the rollback operation is atomic; on failure no partial changes persist and a detailed error is returned And rollback completes within 2 minutes for environments with up to 5,000 active matters
Staged Rollout With Breakage Detection and Notifications
Given a set of proposed mapping/schema changes When I choose Staged Rollout and select a segment (by environment, template owner, or percentage of active matters) Then the system runs a pre-deploy lint across the selected assets to detect template binding breaks and questionnaire validation failures with severity levels And only the selected segment receives the new version while other segments remain on the prior version And asset owners in the segment receive notifications including diff, impact findings, and a one-click rollback link And rollout metrics (adoption %, error rate, validation failures) are displayed in real time And I can abort the rollout, triggering automatic rollback for the segment and audit logging of the abort
Compliance-Ready Export of Audit Logs
Given I specify a time range, event types, and user/asset filters When I export audit logs Then the system generates digitally signed JSON and CSV exports that include selected records, a hash-chain continuity proof, and a manifest with record counts and checksums And the export completes within 60 seconds for up to 100,000 records and provides a downloadable link And only users with the Audit Export permission can generate exports, and each export is logged with actor, parameters, and checksum

Live Fill Preview

Test templates instantly with sample or real intake data. Toggle fact patterns to see conditional text, unresolved fields, and final PDF/Word output before launch—catching gaps early and accelerating go-live.

Requirements

Instant Template Merge Preview
"As a solo attorney, I want to preview my template with real or sample client answers instantly so that I can validate mappings and catch issues before sending documents for signature."
Description

Provide instant server-side rendering of templates using selected intake data (sample or live). Merge fields, repeaters, tables, and conditional clauses, and stream the preview within 500ms for small templates and under 2s for large filings. Display a unified reading view within the editor, with safe execution sandboxing, deterministic template functions, and clear error boundaries that localize merge failures to the affected block without breaking the whole preview. Support mobile-friendly viewport scaling and refresh on change for both template edits and data toggles.

Acceptance Criteria
Small Template Preview SLA (500ms)
Given a small template (<=3 pages, <=20 merge fields, no repeaters/tables) and selected intake data (sample or live) When the user opens Live Fill Preview or changes a data toggle or saves a template edit Then the server begins streaming the merged preview within 500ms at p95, measured from the user event to first byte received by the client And the update occurs in-place without a full-page reload (only the preview pane re-renders)
Large Filing Preview SLA (under 2s)
Given a large filing template (>=20 pages, includes repeaters/tables, >=100 merge fields) and selected intake data When the user opens Live Fill Preview or changes a data toggle or saves a template edit Then the server begins streaming the merged preview within 2s at p95, measured from the user event to first byte received by the client And the UI remains responsive during streaming (no frozen interactions >250ms)
Merge Field Resolution and Unresolved Field Highlighting
Given the user selects either sample data or live matter data When the template is merged for preview Then all merge fields with available values resolve correctly for the selected dataset, with no data from other matters or users present And unresolved fields render as clearly highlighted placeholders with inline messages, and a visible badge displays the total unresolved count And switching between sample and live data re-merges immediately using only the newly selected dataset
Conditional Clauses Toggle Correctness
Given conditional clauses bound to intake fields When the user toggles related fact pattern values Then the preview includes or excludes the correct text blocks accordingly on the next refresh And no residual condition tokens, orphaned conjunctions, duplicate punctuation, or double spaces remain in the rendered text
Repeaters and Tables Rendering Fidelity
Given repeaters and tables bound to list data that may contain 0, 1, or N items When the template is merged for preview Then the number of rendered rows/paragraphs equals the list length; 0 items hide the block or show the defined empty-state text per template settings And no dangling bullets or empty table rows are rendered, and table content stays within the preview width without horizontal scrolling
Sandboxed, Deterministic Execution with Error Isolation
Given template functions execute in a sandboxed environment When the same function is invoked twice with identical inputs Then outputs are byte-identical across runs (deterministic) And functions cannot access network, filesystem, or OS processes; attempts are blocked and logged And long-running or faulty functions are terminated within the configured timeout (<=1s) and memory limits, emitting an inline error only for the affected block while the rest of the preview renders successfully
Unified Reading View, Auto-Refresh, and Mobile Scaling
Given the editor displays a unified reading view When the preview renders and subsequently auto-refreshes after template edits or data toggles Then only one continuous preview pane is shown; scroll position is preserved within ±100px after refresh; the editor caret/focus is not moved And the refresh meets the SLA defined for the template size (500ms small / 2s large to first byte) And on mobile viewports 360–414px wide, content scales to fit without horizontal scrolling at 100% zoom and remains readable (body text >=14px)
Conditional Logic Toggle Panel
"As a paralegal, I want to flip fact patterns on and off so that I can confirm the right clauses appear for each scenario."
Description

Provide a dedicated panel that discovers and lists all conditional variables and rules in the template. Allow users to toggle boolean and enumerated answers, set numeric and date values, and simulate edge cases, with the preview updating live. Visually annotate included and excluded clauses and display badges for the condition paths taken. Offer a trace view that explains why a clause rendered or was suppressed to simplify debugging. Persist overrides per session and allow reset to intake defaults.

Acceptance Criteria
Discover and List All Conditional Variables and Rules
Given a loaded template containing conditional variables and rules When the Conditional Logic Toggle Panel is opened Then it lists 100% of unique conditional variables and rules defined in the template, with counts matching the template definition And each list item displays: variable/rule name, type (boolean, enum, number, date), and the current effective value derived from intake defaults or prior overrides And the panel supports filtering by type and keyword search, returning results in under 300 ms for datasets up to 500 items
Toggle Boolean and Enumerated Answers
Given a boolean or enum variable present in the panel When the user toggles a boolean or selects an enum option Then the selection is applied immediately and becomes the variable's effective value And only permitted enum options are selectable; attempting to select a disabled option is blocked with an inline explanation tooltip And the live preview recalculates and visually reflects the change within 1 second without full-page reload
Set Numeric and Date Values With Validation and Edge Cases
Given a numeric or date variable with defined constraints (min, max, format) When the user inputs a value Then the control validates inline, displaying specific error text and preventing application until the value complies And the control supports quick edge-case presets (min, max, null/empty where allowed, out-of-range) to simulate boundary conditions And upon valid input, the live preview recalculates and updates within 1 second
Live Preview Delta Highlighting and Unresolved Fields
Given any change to a variable in the panel When the recalculation completes Then the preview highlights added clauses in green and removed clauses in red for at least 3 seconds And the preview provides a "Jump to changes" control that scrolls to the first changed clause And unresolved merge fields are flagged inline with an icon and a count badge; clicking the badge filters the panel to the related variables
Clause Annotation and Condition Path Badges
Given a rendered document preview with conditional clauses When clauses are evaluated Then each clause shows an inline badge of Included or Excluded and a compact label of the path taken (e.g., "DebtType=Medical ∧ Amount>5k") And hovering the badge reveals the evaluated condition summary with the variables and their values used in the decision And badges update in under 1 second after any variable change
Trace View Explains Rendering Decisions
Given a clause with conditional logic When the user opens Trace for that clause Then the trace displays the evaluation tree including each predicate, its evaluated value, the source of each variable (intake default vs override), and the final decision And the trace view offers Copy Trace to clipboard and Expand/Collapse all; it renders in under 500 ms for trees up to 200 nodes And if a clause is suppressed due to multiple rules, the trace shows rule ordering/priority and which rule short-circuited evaluation
Persist and Reset Overrides Per Session
Given a browser session and an open template When the user navigates away and returns within the same session Then all variable overrides and panel filters persist for that template And clicking Reset to Intake Defaults clears all overrides and restores effective values to the intake data, with an undo option available for 10 seconds And overrides are isolated per template and per browser session; opening the same template in a new session starts with intake defaults
Unresolved Field Detection & Quick Fix
"As a template author, I want unresolved fields flagged with guidance so that I can correct gaps quickly and avoid broken drafts."
Description

Automatically detect unresolved placeholders, unmapped variables, and schema mismatches during preview. Highlight occurrences inline, list them in a side panel, and offer quick actions to map to an intake question, define a default value, or create a new field. Provide deep links into the template or intake schema editors and re-run the preview after each fix to confirm resolution. Aggregate counts of unresolved items to block go-live until cleared.

Acceptance Criteria
Unresolved Placeholders Detected on Preview
Given a template contains variables that are not mapped, have missing values, or have schema type mismatches and the user runs Live Fill Preview with sample or real intake data When the preview renders Then the system identifies every unresolved item and classifies each as one of: Unmapped Variable, Missing Value, or Schema Mismatch And the side panel lists each unresolved item with variable key, source document/file name, location reference (page number and paragraph index for DOCX/PDF), and occurrence count And the unresolved badge displays the total number of unique unresolved items and total occurrences across the document(s)
Inline Highlighting and Panel Sync
Given unresolved items are present in the preview When the user hovers or focuses a list item in the side panel Then all occurrences of that variable are highlighted inline in the preview with a consistent unresolved style and a tooltip showing the unresolved type and reason And clicking an inline highlight selects and scrolls to the corresponding list item in the side panel And the user can filter the list by type (Unmapped Variable, Missing Value, Schema Mismatch) and search by variable key, with results updating within 200 ms for lists up to 200 items
Quick Actions to Resolve Unresolved Fields
Given the user selects an unresolved item in the side panel When the user chooses Map to Intake Question Then a searchable selector of existing intake fields appears, incompatible field types are disabled with an explanation, and selecting a compatible field maps the variable and resolves all occurrences When the user chooses Define Default Value Then a modal enforces entry matching the variable type and upon save sets a template-scoped default that resolves all occurrences lacking a value When the user chooses Create New Field Then the user can specify key, label, type, and optional validations; upon save the field is added to the intake schema and the variable is mapped to it
Schema Mismatch Detection and Guidance
Given an unresolved item is classified as Schema Mismatch When the user opens its details Then the panel displays the expected type, the provided value/type, and a concise fix suggestion (e.g., remap to a compatible field or change variable type) And attempts to map to an incompatible field are blocked with a clear error explaining the mismatch And a Learn More link opens documentation in a new tab without losing preview state
Deep Links to Editors with Safe Navigation
Given an unresolved item is selected When the user clicks Open in Template Editor Then the template editor opens with the first occurrence of the variable highlighted and the cursor positioned at that location When the user clicks Open in Intake Schema Then the schema editor opens with the corresponding field (or proposed new field) preselected And unsaved changes prompts appear before navigating, and a Back to Preview control returns the user to the same preview state and scroll position
Auto Re-run and State Update After Fix
Given the user resolves one or more unresolved items via mapping, defaulting, or schema edits When the user saves the change Then the preview automatically re-runs using the same intake data and fact pattern toggles within 3 seconds for documents up to 200 pages or 2 MB And resolved items are removed from the list and inline highlights, and remaining counts are updated accurately And a toast confirms: “Preview updated — X unresolved remaining”
Go-Live Blocker Until Cleared
Given the unresolved item count for the template pack is greater than zero When the user attempts to Publish/Go Live Then the Publish action is disabled and a tooltip states the number of unresolved items and that all must be cleared before publishing And when the unresolved count equals zero across all documents in the template pack, the Publish action is enabled And blocked attempts and successful publishes are recorded with timestamp and user in the audit log
Dual Output Rendering (PDF & Word)
"As an attorney, I want to see exactly how the draft will look in PDF and Word so that I trust the final filing and retainer before go-live."
Description

Generate both PDF and DOCX previews from the same template and data, ensuring pagination, headers and footers, tables, and styling fidelity match final exports. Offer side-by-side or tabbed viewing modes and allow downloading watermarked preview files. Support court-specific formatting such as caption blocks, line numbering, and page breaks. Offload heavy renders to background workers with progress indicators and graceful fallbacks on mobile.

Acceptance Criteria
Side-by-Side Dual Preview Consistency
Given a template and a fixed data snapshot are loaded in Live Fill Preview When the user generates previews in side-by-side mode Then both PDF and DOCX previews are produced from the same data version And the plain-text content of both outputs matches exactly after stripping formatting And headers, footers, tables, and styling render without missing elements in both outputs And the PDF page count matches the page count produced by the final export pipeline for the same inputs And the DOCX, when downloaded and opened in Word, shows the same page count as displayed in the preview
Conditional Text and Unresolved Fields Parity Across PDF & DOCX
Given a template with conditional clauses and required fields And the user toggles fact patterns and leaves at least one required answer unresolved When the user generates both PDF and DOCX previews Then conditional text visibility is identical in both outputs for the same toggle states And unresolved fields are visibly flagged in both outputs (e.g., placeholder tokens or highlight) and listed in the UI And resolving the fields and regenerating clears the flags in both outputs
Court-Specific Formatting Fidelity (Caption, Line Numbers, Page Breaks)
Given a jurisdiction profile requiring a caption block, pleading line numbers 1–28, and forced page breaks at section boundaries When the user generates PDF and DOCX previews Then the caption block renders in both outputs with court name, party names, and case metadata in the specified positions and styles And pleading line numbers appear 1–28 on each pleading page in both outputs, restarting on each new page And forced page breaks occur before the configured sections in both outputs And these elements match the formatting produced by the final export pipeline for the same template and data
Watermarked Preview Downloads (PDF & DOCX)
Given a successful dual-format preview render When the user downloads the PDF or DOCX from the preview Then the file includes a visible diagonal watermark reading "PREVIEW – NOT FOR FILING" on every page And the file name includes the suffix "-preview" for both formats And the download starts within 2 seconds after clicking without triggering a re-render if the preview is fresh (<10 minutes) And downloaded files open without errors in standard viewers (Acrobat/Word)
Background Rendering with Progress Indicators
Given the system estimates the render will exceed 3 seconds or the template exceeds the complexity threshold When the user starts a dual-format preview Then the job is offloaded to a background worker that renders PDF and DOCX against the same data version And the UI displays progress states (Queued, Rendering, Assembling, Complete) with updates at least every 1 second And the user can cancel the job before completion And upon completion both outputs update atomically together And total time-to-first-preview for a 25-page template is under 20 seconds at p95
Mobile Graceful Fallback for Heavy Renders
Given the user is on a mobile device (viewport width < 768px) and initiates a heavy preview When the render is offloaded to background processing Then the UI switches to tabbed preview (no side-by-side) with skeleton loaders and a non-blocking progress toast And the app remains responsive (no main-thread freeze > 200ms) during rendering And on network loss the UI offers to notify on completion and resumes progress on reconnect without losing job state
Resilience When One Format Fails
Given a transient error occurs in generating one output format while the other succeeds When the preview job completes Then the successful format is displayed and downloadable with watermark And the failed format panel shows an error message with a retry action and a reference error code And retrying reuses the same data snapshot if within 10 minutes; otherwise prompts to refresh data And no partial or corrupt files are offered for download
Test Data Scenarios Management
"As a practice owner, I want reusable test datasets so that my team can validate templates consistently across common fact patterns."
Description

Enable creation, saving, and reuse of named test scenarios derived from the intake schema (e.g., common consumer-law fact patterns). Provide a generator for realistic sample values and an importer to clone anonymized data from real intakes with PII masked. Tie scenarios to specific template versions, allow export and sharing within the workspace, and surface a quick picker in the preview to switch scenarios rapidly.

Acceptance Criteria
Create and Save Named Scenario from Intake Schema
Given a published intake schema is selected, When the user clicks “New Scenario” and enters a unique name within the workspace, Then a scenario record is created and associated to the selected schema. Given a scenario name that duplicates an existing name in the workspace (case-insensitive), When the user attempts to save, Then the save is blocked and an inline error explains the conflict. Given required fields in the schema, When the user saves the scenario with missing required values, Then the scenario saves as Draft and the missing fields are listed with counts; it cannot be marked Ready until all required fields are populated. Given a saved scenario, When reopened, Then all previously entered values persist exactly and the last-edited timestamp and editor are displayed. Given concurrent edits, When two users edit the same scenario, Then optimistic locking prevents overwrites and prompts the second user to resolve conflicts before saving.
Generate Realistic Sample Data Respecting Schema Constraints
Given the user selects “Generate Sample Data,” When generation runs, Then values comply with each field’s type, format, enum, regex, and min/max constraints defined in the schema. Given dependency rules (e.g., if Married == true then SpouseName required), When generation completes, Then dependent fields are populated consistently to satisfy those rules. Given the user provides a seed value, When generating sample data multiple times with the same seed, Then the outputs are deterministic and identical; with no seed, successive generations vary. Given a schema up to 200 fields, When generating sample data, Then the operation completes within 2 seconds on desktop and 3 seconds on mobile. Given locale set to en-US, When generating addresses, phones, and dates, Then formats match the locale (e.g., (555) 555-1212, MM/DD/YYYY) and no real PII sources are queried.
Import and Anonymize Real Intake to Test Scenario
Given a completed intake submission and user permission to view it, When the user selects “Import as Scenario,” Then a new scenario is created with values cloned from the intake. Given PII fields designated by the schema or data classification, When import runs with anonymization (default ON), Then all PII values are masked with consistent tokens per entity (e.g., NAME_1), preserving data shape (e.g., email format a***@example.com). Given repeated PII occurrences across fields/documents, When anonymized, Then the same source value maps to the same token across the entire scenario. Given the import completes, When exporting or previewing the scenario, Then no unmasked PII from the source is present (PII scanner returns zero high-confidence matches). Given the user lacks access to the source intake, When attempting import, Then the action is blocked with a 403 error and no scenario is created. Given an import occurs, When viewing audit logs, Then an entry exists with actor, timestamp, source intake ID, anonymization setting, and scenario ID.
Version Binding and Compatibility Alerts for Scenarios
Given a scenario is created against Template Version V, When Template Version V+1 is published, Then the scenario displays an “Out of date” badge and a “Migrate” action. Given a scenario bound to Version V, When opened in preview, Then the system loads Version V by default and indicates the bound version visibly. Given the user initiates migration to Version V+1, When fields have changed, Then a diff report lists added, changed, and removed fields; added fields default to null, removed fields are retained as inactive metadata. Given migration completes with no blocking errors, When saving, Then the scenario is re-bound to Version V+1 and preview renders successfully; if blocking errors exist (e.g., missing required fields), save is blocked with explicit error counts. Given a scenario bound to a different version than the active template, When selected in the quick picker, Then the user is prompted to switch template version or migrate before applying.
Export and Workspace Sharing of Test Scenarios
Given a scenario, When the user selects Export, Then a JSON file downloads containing scenario name, workspace ID, schema ID, template version, created/updated metadata, and the data payload; the file validates against the public scenario JSON schema. Given a valid exported scenario file, When importing, Then the system validates signature and schema compatibility; on success the scenario is added and de-duplicated by name with a suffix if needed; on failure the user sees exact validation errors. Given workspace roles, When a scenario is shared, Then Viewers can use it in preview but cannot edit or delete; Editors and above can edit; only Owners/Admins can delete. Given a shared scenario link, When accessed by a non-member, Then access is denied (403) and no scenario metadata is leaked. Given a scenario is updated by an Editor, When another user opens it, Then they see the latest version and a change history entry with actor, timestamp, and summary.
Quick Picker to Switch Scenarios in Live Preview
Given the document preview is open, When the user opens the Scenario Quick Picker and selects a scenario, Then the preview re-renders with that scenario’s data and unresolved fields are highlighted within 700 ms for templates up to 50 pages or 200 merge fields. Given multiple scenarios, When the user types at least 2 characters in the picker search, Then typeahead results return within 200 ms and include name, tags, and bound template version. Given the currently edited ad-hoc data differs from the saved scenario, When the user attempts to switch scenarios, Then the system prompts to discard or save changes; selecting discard proceeds, selecting cancel keeps the current scenario. Given a scenario bound to a different template version, When displayed in the picker, Then it is labeled with its bound version and selecting it prompts to switch or migrate before applying. Given keyboard users, When navigating the picker, Then scenarios are selectable via up/down arrows and Enter, and focus management returns to the preview after selection.
Access Controls & Live Data Safeguards
"As a firm admin, I want safeguards around previews with real client data so that we maintain confidentiality and compliance."
Description

Enforce role-based permissions for previews that use live client data. Default to anonymized view with explicit consent required to reveal PII fields, and watermark all previews containing live data. Log every live-data preview event to an immutable audit trail. Prevent external sharing of previews with live data and automatically expire preview artifacts per firm retention policies.

Acceptance Criteria
RBAC Enforcement for Live Data Previews
Given a user without the "Live Data Preview" permission or without matter access attempts to open a Live Fill Preview that uses live client data When the preview is requested via UI or API Then the request is denied with HTTP 403 and an in-app message "You do not have permission to preview live client data" And no live data is queried, loaded, or transmitted to the client And an anonymized sample-data preview is offered as a fallback And an audit event type "live_preview_denied_rbac" is recorded Given a user with the "Live Data Preview" permission and matter access opens a Live Fill Preview When the preview loads Then the preview opens in anonymized mode by default with no PII values rendered client-side
Default Anonymized View for Live Data Previews
Given a permitted user opens a template preview that references live client data When the preview renders in Web, PDF, and Word modes Then all fields flagged as PII in the template mapping are masked with placeholders and not included in network responses And the UI displays a badge "Anonymized" and the Download action is disabled with tooltip "Enable by revealing PII" And inspection of API payloads confirms PII fields are absent from responses and not present in client memory
Explicit Consent Gate to Reveal PII
Given a permitted user clicks "Reveal PII" in a live-data preview When the user selects a required permitted purpose from a dropdown and checks the attestation checkbox Then PII values render in the current session and mode And an audit event "live_preview_reveal_pii" is stored with user_id, role, firm_id, matter_id, template_id, purpose, timestamp (UTC), ip, and record_hash And if the user's role lacks the "Reveal PII" entitlement or omits the purpose, the action is blocked with HTTP 403 and no PII is revealed
Watermarking of Live-Data Previews and Artifacts
Given any preview screen or exported artifact contains live (unmasked) client data When the content is displayed, printed, or downloaded as PDF/Word Then a non-removable diagonal watermark appears on every page containing "LIVE DATA — INTERNAL USE ONLY", firm name, user name, timestamp, and matter ID And the watermark persists in browser print preview and generated files And attempts to alter, hide, or remove the watermark via settings, query parameters, or CSS are ignored and logged
Immutable Audit Trail for Live-Data Preview Events
Given any live-data preview is opened, PII is revealed, an export is attempted, or a share is attempted When the action occurs Then an append-only audit record is written with event_type, timestamp (UTC), user_id, role, firm_id, matter_id, template_id, ip, user_agent, action_outcome, previous_hash, and record_hash And update/delete operations on audit records are not available; any attempt returns HTTP 405 and is separately logged And integrity verification of the audit chain succeeds, proving tamper-evidence for the time window under test
External Sharing Prevention for Live-Data Previews
Given a live-data preview is open (PII revealed or reveal-capable) When the user attempts to create a public share link, send via email, or access a public URL Then share controls are hidden/disabled in the UI and corresponding API requests return HTTP 403 with error "External sharing disabled for live data" And view URLs require authenticated firm access; anonymous access redirects to login without disclosing document existence And Download/Export is enabled only when the preview is anonymized; if PII is revealed, Download/Export controls remain disabled
Auto-Expiration of Live-Data Preview Artifacts per Retention Policy
Given a firm retention setting for live preview artifacts is configured (default 24h if unset) When a live-data preview artifact reaches its expiration timestamp Then the artifact and cached renders are purged, signed URLs revoked, and subsequent access returns HTTP 410 Gone And an audit event "live_preview_expired" is recorded with artifact_id, matter_id, timestamp (UTC), and action_outcome And admins can trigger manual purge, which immediately expires artifacts and produces the same outcomes
Performance, Caching, and Concurrency Controls
"As a mobile user, I want fast, reliable previews even on flaky connections so that I can finalize engagements on the go."
Description

Implement caching of compiled templates and recent previews, cancel stale renders when new edits arrive, and throttle concurrent preview requests per user to maintain stability. Target p95 preview time under 2 seconds for typical retainers and under 5 seconds for long filings, including on mobile networks. Provide streaming status, retry on transient errors, and clear user messaging when system limits or timeouts occur.

Acceptance Criteria
Compiled Template Cache Reuse
Given a template is previewed for the first time after a save, When the first preview runs, Then the system compiles the template and stores the compiled artifact in cache keyed by template version ID. Given subsequent previews of the same template version within 30 minutes, When previews start, Then the compile step is skipped and the cached compiled artifact is used, and a cache-hit metric is recorded. Given the template is edited and saved to a new version, When a new preview runs, Then the prior compiled artifact is invalidated and a fresh compilation occurs. Given 10 consecutive previews of the same version, When measured, Then at least 9 previews report a compilation cache hit.
Recent Preview Output Cache (Per User and Input)
Given a user previews a template version with identical input data and output format within 10 minutes, When a subsequent identical preview is requested, Then the system returns the cached rendered output with p95 latency <= 400 ms and marks response as cache-hit. Given different input data or toggled conditionals, When a preview is requested, Then the cache is bypassed and a new render occurs. Given another user requests the same input and template, When the preview is requested, Then their cache is isolated and not served from another user's cache. Given the cache TTL of 10 minutes elapses, When a preview is requested, Then a re-render occurs and the cache is refreshed.
Cancel Stale Previews on New Edits
Given a preview is in progress, When the user changes template content or intake answers and triggers a new preview, Then the in-flight render is canceled within 500 ms server-side and emits a canceled status with reason=superceded. Given the prior render was canceled, When the new preview starts, Then only the latest request produces a downloadable output; no stale output is delivered to the client. Given multiple rapid edits (>=3 within 2 seconds), When previews are triggered, Then at most one active render remains at any time for that user/template.
Per-User Concurrency Throttling and Queuing
Given a user launches 6 preview requests simultaneously, When the system enforces limits, Then at most 2 renders run concurrently, up to 3 are queued, and the 6th returns HTTP 429 with Retry-After and an explanatory message. Given queued items exist, When active renders complete, Then queued requests start in FIFO order and the status stream reflects state=queued with position index. Given the user cancels the latest preview, When a queued request is superseded by a newer edit, Then the superseded queued job is removed and marked canceled with reason=superceded.
Preview Performance Targets (Typical and Long) Including Mobile Networks
Given a typical retainer template (<=10 pages, <=50 conditional blocks) and realistic intake data, When previewed over a simulated 4G network (400 ms RTT, 10 Mbps down, 3 Mbps up, 1% packet loss), Then p95 end-to-end time from click to first downloadable output <= 2.0 s and p99 <= 3.0 s across 200 runs. Given a long filing (<=50 pages, <=300 conditional blocks), When previewed under the same network conditions, Then p95 <= 5.0 s and p99 <= 7.0 s across 200 runs. Given server-side timing, When measured, Then server processing p95 <= 1.5 s (typical) and <= 4.0 s (long) excluding cache hits.
Streaming Preview Status Updates
Given a preview is initiated, When the client subscribes to the preview status stream, Then the client receives ordered status events: queued, starting, compiling, rendering, generating_output, uploading, completed or canceled or failed. Given network interruptions up to 30 seconds, When the client reconnects, Then the stream resumes without losing the final terminal event. Given a cancellation, When emitted, Then the event includes reason (superceded, user_request, throttle) and a correlation ID.
Retry on Transient Errors and Clear Messaging on Limits/Timeouts
Given a transient error (HTTP 5xx, storage timeout, function cold-start timeout), When encountered during preview, Then the system retries up to 2 times with exponential backoff (initial 300 ms, factor 2, jitter 20%) before failing. Given a non-retryable error (4xx validation, compile error), When encountered, Then no retry occurs and the status stream includes error_code and human-readable guidance. Given a request exceeds a 20-second hard timeout, When the timeout triggers, Then the job is aborted, a timeout-specific message is shown with actions (retry, download logs if permitted), and metrics record the timeout event.

Precedent Miner

Upload past retainers and pleadings to auto-extract reusable clauses, tag them by outcome and jurisdiction, and surface the most proven language first. Builds a trusted clause library in minutes instead of weeks.

Requirements

Secure Upload & OCR Parsing
"As a solo attorney, I want to quickly upload my existing retainers and pleadings in any format so that the system can process them without manual cleanup or delays."
Description

Enable users to upload past retainers and pleadings in common formats (PDF, DOCX, image scans) with automatic OCR for scanned and rotated pages, virus scanning, and tenant‑isolated encrypted storage. Normalize extracted text with layout preservation, classify document type, and support batch uploads with progress tracking, retries, and deduplication by checksum. Emit structured text and document metadata for downstream extraction while providing clear error handling and audit entries. Integrates with Briefly’s file store and job queue for scalable, asynchronous processing.

Acceptance Criteria
Multi-format Upload with Virus Scan and Encrypted, Tenant-Isolated Storage
Given an authenticated user in Tenant A uploading files in PDF, DOCX, JPG, PNG, or TIFF up to 50MB per file and 200 files per batch When the upload is initiated Then each file is streamed to a staging area, scanned for malware using the configured AV engine, and rejected if infected with error code UPLOAD_VIRUS_DETECTED And clean files are persisted to Briefly’s file store with AES-256 encryption at rest and TLS 1.2+ in transit And storage paths and object metadata contain no PII beyond a system GUID And files are stored in a tenant-isolated namespace such that Tenant B cannot list or access Tenant A’s objects, even if checksums match And a successful upload event with fileId, tenantId, size, checksum, and uploaderId is recorded
OCR for Scanned and Rotated Pages with Layout Preservation
Given an uploaded scanned PDF or image file with pages rotated at 0/90/180/270 degrees When OCR processing runs Then page orientation is auto-detected and corrected prior to OCR And if a digital text layer is present (PDF/DOCX), OCR is skipped and text is extracted natively And text is extracted with 95%+ character accuracy on a 300 DPI English text test set and returned per page And line breaks, paragraph breaks, bullet/numbered lists, and page boundaries are preserved in the normalized text output And tables are represented as tab-delimited rows preserving cell order And a flag indicates OCR was applied per page with rotationFixApplied true/false
Automatic Document Type Classification
Given normalized text and metadata from an uploaded document When classification executes Then the document is labeled as one of: retainer, pleading, complaint, answer, motion, exhibit, unknown And jurisdiction and court level are extracted when present (e.g., 'CA Superior Court, Los Angeles County') And a confidence score [0..1] is produced; if below 0.6 the type is 'unknown' and a warning is attached And all labels and confidences are included in metadata for downstream consumers
Batch Uploads with Progress, Retries, and Checksum Deduplication
Given a batch upload of up to 200 files totaling up to 200MB When processing begins Then a batchId is created and per-file status transitions through Queued -> Uploading -> Scanning -> Processing -> Complete|Error And a real-time progress indicator shows percent complete within ±5% based on files completed And transient processing failures (network, queue timeout, OCR service 5xx) are retried up to 3 times with exponential backoff And file-level SHA-256 checksums are computed; if a matching checksum exists within the same tenant, the file is marked Duplicate and is not reprocessed, and the prior documentId is referenced And batch summary reports counts of Completed, Error, and Duplicate files
Emit Structured Text and Metadata for Downstream Extraction
Given a file successfully processed When emitting results to downstream systems Then a JSON payload conforming to schema v1 is produced with fields: documentId, tenantId, originalFilename, mimeType, fileType, sizeBytes, pageCount, checksumSHA256, ocrAppliedByPage[], rotationFixAppliedByPage[], normalizedTextByPage[], docType, jurisdiction, confidence, processingStartedAt, processingCompletedAt, errors[] And the full normalized text is available by page and as a concatenated document-level field And the payload is written to the file store alongside the source and an event 'document.processed' is published to the job queue with batchId and documentId
Clear Error Handling, User Feedback, and Audit Logging
Given an error occurs at any step (unsupported type, virus detected, upload failure, OCR failure, classification low confidence, storage failure) When the user views the batch details Then the UI displays a human-readable message with an actionable recommendation and a stable error code (e.g., OCR_TIMEOUT, UNSUPPORTED_FORMAT) And the user can retry failed files individually without re-uploading the entire batch And audit entries are recorded for upload_started, scan_passed|scan_failed, ocr_started|ocr_failed|ocr_completed, classified, stored, and emitted with actorId, tenantId, timestamp, documentId, batchId, and outcome And no stack traces or internal paths are exposed to the end user
Asynchronous, Scalable Processing via Job Queue Integration
Given uploads occur concurrently across tenants When jobs are enqueued for scanning, OCR, normalization, classification, and emission Then each step runs asynchronously via Briefly’s job queue with idempotent handlers keyed by documentId and step And the system sustains at least 10 concurrent batches (up to 2,000 files total) without error rate exceeding 1% and with p95 end-to-end processing time under 10 minutes for a 50-file, 500-page workload And duplicate deliveries from the queue do not result in duplicate stored artifacts or events And operational metrics are captured for throughput, latency, error rate, and retry count per step
AI Clause Extraction & Canonicalization
"As a practitioner, I want uploaded documents automatically broken into clean, reusable clauses so that I can build a clause library without manual copy‑paste."
Description

Automatically detect and segment clauses, headings, and subclauses using NLP models and rule assists, then canonicalize text by redacting parties, dates, and amounts into standardized placeholders. Assign clause types from a legal taxonomy, preserve formatting, and compute confidence scores per clause. Low‑confidence extractions route to a human review queue. Output a canonical clause object with type, text, placeholders, source offsets, and confidence for indexing and reuse across Briefly’s assembly workflows.

Acceptance Criteria
Accurate Clause Segmentation with Source Offsets
Given a labeled benchmark document containing 50 clauses, headings, and subclauses with gold-standard start/end character offsets When the document is processed by the extractor Then at least 95% of clauses are correctly segmented, with start/end offsets matching the gold standard within ±1 character And no two extracted clauses have overlapping source offsets And each heading is associated with the immediately following clause or clause group from the same section Given a document containing nested numbering (e.g., 1., 1.1, 1.1(a)) When processed Then each numbered item is extracted as a discrete clause/subclause unit with contiguous offsets
Canonicalization and Placeholder Redaction
Given clause text containing party names, calendar dates, and monetary amounts When canonicalization runs Then all party names are replaced with standardized tokens {{PARTY_A}}, {{PARTY_B}}, {{PARTY_C}} as applicable And all dates are replaced with {{DATE}} And all monetary amounts (with currency symbols or codes) are replaced with {{AMOUNT}} And placeholder insertion preserves surrounding punctuation and spacing Given a labeled evaluation set for entities (parties, dates, amounts) When canonicalization is evaluated Then precision ≥ 95% and recall ≥ 95% for each entity type Given canonicalization is run twice on the same text When the second run executes Then no additional or duplicate placeholders are introduced (idempotent)
Clause Type Classification via Legal Taxonomy
Given the system’s legal taxonomy v1.x is loaded When a clause is classified Then type is assigned as a valid taxonomy identifier and not null Given a held-out validation set with gold clause types When classification is evaluated Then top-1 accuracy ≥ 90% And any clause with confidence below the routing threshold is still assigned a provisional type and flagged for review Given a clause that does not match any taxonomy category When classified Then the type is set to OTHER and confidence ≤ 0.5
Confidence Scoring and Human Review Routing
Given each extracted clause has a computed confidence in [0.0, 1.0] When the default routing threshold is 0.75 Then clauses with confidence < 0.75 are placed into the “AI Review” queue with source document reference and offsets And clauses with confidence ≥ 0.75 are not queued Given an administrator updates the routing threshold to T When extraction runs Then only clauses with confidence < T appear in the “AI Review” queue Given a clause is queued for review When a reviewer approves it Then the clause is marked reviewed, removed from the queue, and its reviewed flag is true
Formatting Preservation in Canonical Text
Given a document with paragraph breaks, numbered lists, and bullet points When clauses are canonicalized Then at least 95% of original paragraph breaks and list markers are preserved in the canonical text And legal numbering (e.g., “1.”, “1.1”, “(a)”) remains intact And redactions do not introduce double spaces or break sentence punctuation Given canonicalized text is rendered in the Clause Library and inserted into a document When viewed Then line breaks and indentation match the source clause’s layout
Canonical Clause Object Schema Validation
Given an extracted clause is serialized When the object is produced Then it contains required fields: type (string, taxonomy id), text (string, canonical text), placeholders (array), sourceOffsets (object with start and end integers), confidence (number between 0.0 and 1.0) And JSON schema validation passes And sourceOffsets.start < sourceOffsets.end And all placeholder index ranges, if present, refer to valid spans within text Given placeholders are emitted When inspected Then each placeholder item includes kind ∈ {PARTY, DATE, AMOUNT} and token ∈ {“{{PARTY_A}}”, “{{PARTY_B}}”, “{{DATE}}”, “{{AMOUNT}}”}
Indexing and Reuse in Assembly Workflows
Given extraction completes for a source document When indexing runs Then 100% of canonical clause objects are searchable by type within the Clause Library within 2 minutes And search results for a given type are ordered by confidence descending Given a user inserts a clause from the Clause Library into an assembly workflow When inserted Then the canonical text is used with placeholders intact And no raw party names, dates, or amounts are displayed
Outcome and Jurisdiction Auto‑Tagging
"As a user, I want clauses tagged with the relevant jurisdiction and outcomes so that I can quickly find the most applicable language for my current case."
Description

Infer and attach tags such as jurisdiction, venue, judge, case type, matter category, and outcome (e.g., settled, dismissed, won) from captions, headers, footers, docket references, and internal matter metadata. Allow user override and enrichment, with inheritance from document‑level tags to clause‑level tags. Maintain a consistent tagging schema and validation rules to power search, filtering, analytics, and ranking.

Acceptance Criteria
Auto-tagging from Pleading Caption
Given a pleading PDF with a standard caption containing court name, county/venue, judge, case number, and case type indicators When the document is uploaded to Precedent Miner Then the system extracts and assigns tags for jurisdiction, venue, judge, case type, matter category, and outcome when present And any missing fields remain unset and are flagged as "Needs review" And all assigned tags conform to the controlled vocabulary and pass schema validation And each extracted tag includes a confidence score between 0 and 1 And the median extraction precision >= 95% and recall >= 90% on the regression test set of at least 200 annotated pleadings And processing completes within 10 seconds for a 50-page PDF on a standard processing queue
Docket Reference and Header/Footer Parsing
Given a document containing recognizable docket references in headers/footers or body (e.g., "No. 2:23-cv-00123 (S.D.N.Y.)" or "Case No. 20STCV12345") When the document is uploaded for auto-tagging Then the system maps docket patterns to jurisdiction and court (federal/state) using a maintained mapping table And parses judge initials to full judge name when resolvable via internal reference data And extracts outcome if phrases like "Order of Dismissal", "Stipulated Settlement", or "Judgment for Plaintiff" appear in the header/footer/title and sets outcome accordingly (dismissed/settled/won) And all mappings are logged with source location (page number and region) And precision >= 93% and recall >= 88% on a test set of 150 annotated documents And parsing completes in <= 5 seconds per document for docket metadata
User Override and Enrichment of Tags
Given a document with auto-assigned tags When a user edits, adds, or removes a tag value in the tag panel Then the user’s override persists and is labeled as "User-set" And subsequent reprocessing does not overwrite user-set values unless the user explicitly selects "Reapply auto-tags" And a change log records who, what, and when for each tag change And the UI enforces controlled vocabulary while allowing free-text notes only in a separate "Notes" field And the user can bulk-apply the edited tags to selected clauses within the document
Document-to-Clause Tag Inheritance
Given a document with validated document-level tags When clauses are extracted by Precedent Miner Then each clause inherits document-level tags (jurisdiction, venue, judge, case type, matter category, outcome) as non-destructive defaults And inherited tags are visually indicated and can be overridden at the clause level And clause-level overrides do not modify the document-level tags And inheritance completes in < 500 ms for a document with up to 200 clauses And export and search APIs include both inherited and clause-specific tags with provenance ("inherited" vs "explicit")
Tagging Schema and Validation Rules
Given the controlled vocabulary and schema version in effect When tags are created or updated by automation or users Then values must validate against the schema (e.g., jurisdiction must be a maintained court with country/state codes; outcome must be one of {won, settled, dismissed, default, unknown}) And invalid entries are blocked with actionable error messages And deprecated values are auto-mapped to current canonical forms with a deprecation notice And the active schema version is stored with each tag record And updating the schema triggers migration that maintains 100% backward compatibility for search, filtering, analytics, and ranking
Ambiguity Handling and Confidence Thresholds
Given multiple candidate values for a tag with close confidence scores When the top candidate confidence is < 0.80 or the delta to the runner-up is < 0.05 Then the tag is set to a "Needs review" state and no value is committed And the UI presents the top 3 candidates with source snippets for quick selection And selecting a candidate updates the tag and trains the per-firm disambiguation model for future documents And all unresolved tags appear in a "Review queue" filter until resolved
Search/Filter/Ranking Powered by Tags
Given a clause library populated from tagged documents When a user filters by jurisdiction = "California Superior Court" and outcome = "won" Then only clauses with matching jurisdiction (explicit or inherited) and outcome are returned And results are ranked with clauses matching both filters and most recent outcomes first, breaking ties by frequency of successful outcomes in that jurisdiction And the API returns the same filtered and ranked set with response time <= 1 second for up to 10,000 clauses And analytics dashboards can aggregate counts by jurisdiction, outcome, and judge using the tag schema without errors
Provenance, Confidence, and Versioning
"As an attorney, I want to see where a clause came from and how it has changed so that I can trust and justify using it in client matters."
Description

Track end‑to‑end provenance for every clause including source document ID, page range, uploader, import date, model version, and extraction confidence. Support edit history with diff view, version rollback, and status states (Draft, Approved, Deprecated). Display provenance inline in the library and during insertion, enabling trust and auditability while meeting legal record‑keeping expectations.

Acceptance Criteria
Metadata Capture on Clause Extraction
Given I upload one or more source documents to Precedent Miner And automated clause extraction completes successfully Then each extracted clause record stores sourceDocumentId, sourceDocumentName, pageRange, uploaderUserId, importDatetime (ISO 8601 with timezone), modelVersion, and extractionConfidence And extractionConfidence is a numeric value between 0.0 and 1.0 inclusive with two decimal places And pageRange maps to the correct pages in the stored document and deep-link preview opens at the start of the clause And metadata fields sourceDocumentId, pageRange, importDatetime, modelVersion, and initial extractionConfidence are immutable after creation And if any required metadata is missing or invalid, the clause is quarantined and excluded from the library until reprocessed, and the import summary lists the issue
Inline Provenance Display in Clause Library
Given I open the Clause Library When clause cards/rows render Then each clause visibly shows sourceDocumentName (clickable), pageRange, uploaderDisplayName, importDatetime, modelVersion, extractionConfidence badge, and currentStatus And clicking sourceDocumentName opens a preview of the source document focused at pageRange And the extractionConfidence badge displays the numeric value on hover And provenance values in the list match the values stored on the clause record
Provenance Display During Clause Insertion
Given I am inserting a clause into a retainer or pleading draft When I select a clause from the picker Then the insertion panel displays sourceDocumentName, pageRange, uploaderDisplayName, importDatetime, modelVersion, extractionConfidence, and currentStatus And if currentStatus is Deprecated, insertion is blocked and a warning explains the clause is deprecated with a link to view history And if currentStatus is Draft, a warning is shown and the user must confirm before inserting And the clause inserted into the draft matches the selected version identifier shown in the panel
Edit History and Diff View
Given I open a clause detail page When I save changes to the clause text or status Then a new version record is created with versionNumber incremented, editor identity, and timestamp And the History view lists versions in reverse chronological order with editor, timestamp, and status snapshot And selecting two versions shows a side-by-side diff highlighting additions and deletions And non-editable provenance fields (sourceDocumentId, pageRange, importDatetime, modelVersion, initial extractionConfidence) are read-only across all versions
Version Rollback with Audit Trail
Given I am viewing a prior version of a clause When I choose Rollback and confirm Then a new latest version is created whose text equals the selected prior version And the rollback action is recorded in history with actor, timestamp, fromVersion, and toVersion And immutable provenance fields remain unchanged And rollback is prevented if the selected version content equals the current version
Status States and Visibility Rules
Given a clause exists in the library When no explicit status has been set Then the clause status defaults to Draft When a user changes status to Approved or Deprecated Then the status change is saved and recorded in history with actor and timestamp And clauses with Deprecated status are clearly labeled and excluded from default search and recommendations, and flagged in insertion flows And currentStatus is displayed consistently in library lists, detail pages, and insertion panels
Proven Clause Ranking & Recommendations
"As a practitioner, I want the best‑performing clause for my jurisdiction to appear first so that I can draft faster with higher confidence."
Description

Rank and surface clauses based on multi‑factor signals: jurisdiction and case‑type match, historical outcome success, peer usage frequency, recency, approval status, and user feedback (pin/downvote). Provide "most proven" recommendations within search and in‑context assembly, with sub‑200ms response time from an indexed store. Continuously learn from selections and outcomes to improve rankings while offering transparent rationale for suggested clauses.

Acceptance Criteria
Search: Most-Proven Clauses Ranked by Multi-Factor Signals
Given a matter with jurisdiction J and case type T and a clause library with clauses that have recorded signals (historical outcome success, peer usage, recency, approval status, user feedback) When the user executes a keyword search K in the clause library Then results are ordered by a composite score that prioritizes exact J and T matches over partial or mismatched values, increases with higher historical outcome success rate, higher peer usage (last 90 days), and more recent usage/approval, and boosts approved clauses while demoting unapproved ones And user feedback is applied so that pinned clauses rank first for that user/team in matching J,T contexts and downvoted clauses are removed from that user’s top 10 for the same query/context And if at least one clause with exact J and T exists, at least 4 of the top 5 results are exact J and T matches And server-side response time from the indexed store for the query is <= 200ms p95 and <= 120ms p50 under normal load with a warm index
In-Context Assembly: Sub-200ms Proven Recommendations
Given a document assembly session with the cursor in a clause placeholder and matter metadata J,T available to the recommender When the recommendation panel is opened or refreshed Then the top 5 recommended clauses are retrieved from the indexed store with server-side latency <= 200ms p95 and <= 120ms p50 And the ordering is consistent with the search ranking for the equivalent query K with the same J,T context And selecting a recommendation records a selection event linked to J,T and the clause ID for learning
Recommendation Rationale Transparency Panel
Given a list of recommended clauses for a specific query K and context J,T When the user opens the rationale for any clause Then the system displays the factor breakdown including: jurisdiction match (exact/partial/mismatch), case-type match (exact/partial/mismatch), historical outcome success rate (%) with sample size n, peer usage count (last 90 days), recency (last used/approved timestamp), approval status, and user feedback state (pinned/downvoted) And each factor shows its normalized contribution (0–1) and the total composite score used for ranking And re-running the same calculation with the same inputs in a deterministic test reproduces the displayed score and the list order
User Feedback (Pin/Downvote) Adjusts Rankings
Given a list of recommended clauses for context J,T When a user pins a clause Then that clause moves to rank 1 for that user/team for matching J,T contexts immediately and persists across sessions until unpinned When a user downvotes a clause Then that clause is removed from the top 10 for that user for the same query/context and its score is reduced for that user in subsequent lists And feedback events are persisted within 2 seconds and reflected on the next refresh And feedback events are recorded for aggregation and are available to the ranking function within 24 hours
Outcome-Based Learning Improves Rankings Over Time
Given resolved matters emit outcome events (success/failure) with referenced clause IDs and context J,T When new outcome events are ingested Then the historical outcome success rate signal is updated per clause within its J,T cohort within 24 hours And in subsequent recommendations for matching J,T, clauses with improved success rate move up (or maintain) relative position and clauses with worsened success rate move down, all else equal And an audit entry records the ingestion timestamp, number of outcomes processed, and affected clauses
Indexing Freshness and Discoverability SLA
Given a clause is newly uploaded and approved or an existing clause is updated When the indexing pipeline processes the change Then the clause and its metadata become searchable and eligible for recommendations within 5 minutes of approval/update And the recency signal reflects the approval/update timestamp used in ranking And clause IDs remain stable across re-indexing so rationale links remain valid
Deterministic Ranking and Fallbacks with Missing Signals
Given a query K and context where one or more signals are missing (e.g., unknown jurisdiction or no outcome data) When computing the ranking Then missing factors are ignored without error and remaining signals are applied And tie-breaking is deterministic in the following order: higher outcome success rate, then higher peer usage (last 90 days), then newer recency, then lower lexicographic clause ID And repeated requests with identical inputs return an identical ordering
Clause Library Management UI
"As a user, I want an easy way to review, edit, and curate my clause library so that I can keep only trusted language ready for reuse."
Description

Deliver a mobile‑friendly interface to search, filter, and sort clauses by tags, confidence, approval status, and performance. Enable rich‑text editing with placeholder highlighting, duplicate detection and merge, bulk approve/deprecate, inline comments, and export. Provide review queues for low‑confidence items and activity feeds for transparency. Integrate with Briefly auth and respect tenant isolation.

Acceptance Criteria
Search, Filter, and Sort Clauses
- Given a library with >=100 clauses tagged by outcome, jurisdiction, approval status, and performance, When a user searches "fee waiver" and applies filters (jurisdiction: CA, approval: Approved, confidence >= 0.80), Then only clauses matching all filters and containing the keyword in title or body are returned. - Given results are displayed, When the user sorts by Confidence (desc), Then items are ordered by confidence value and ties are broken by Last Updated (desc). - Given results are displayed, When the user sorts by Performance (win rate) (desc), Then ordering reflects the performance metric and each item shows its metric to 1 decimal place. - Given no clauses match the query, When the search executes, Then the UI shows "No clauses found" with a Clear Filters action. - Given mobile viewport 375x667, When the filters panel is opened, Then all controls are visible, keyboard-accessible, and no horizontal scrolling occurs. - Given a change in any filter or sort, When the query executes on a dataset up to 5,000 clauses, Then results update within 500 ms.
Rich-Text Editing with Placeholder Highlighting
- Given a clause is opened in the editor, When it contains placeholders like {{Client.Name}} or [[Court.County]], Then placeholders are visually highlighted and cannot be accidentally broken by typing (tokens remain atomic). - Given the placeholder picker is used, When a user inserts a placeholder, Then only schema-valid placeholders can be inserted and invalid entries show an inline error. - Given the clause is modified, When Save is clicked, Then a version is created with required change summary (<=120 chars) and autosave occurs every 5 seconds without losing formatting. - Given invalid or unrecognized placeholders exist, When Save is attempted, Then saving is blocked and the UI lists the invalid tokens with line references. - Given mobile viewport 375x667, When the formatting toolbar is used, Then core actions (bold, italic, underline, bullets, numbering, link, placeholder) are accessible via a collapsible menu and operate correctly.
Duplicate Detection and Merge
- Given a clause is uploaded or saved, When another clause has >=85% textual similarity, Then the system flags a potential duplicate with a duplication score within 2 seconds for clauses under 5,000 characters. - Given potential duplicates are flagged, When the user selects Compare, Then a side-by-side diff shows additions, deletions, and placeholder differences. - Given two or more duplicates are selected, When the user initiates Merge, Then the user can select a master, choose line-level content to keep, and union all tags, jurisdictions, and outcomes. - Given a merge is confirmed, When it completes, Then the merged clause replaces duplicates, originals are archived (read-only) with redirects, and provenance is recorded. - Given a false positive is identified, When the user dismisses a duplicate suggestion, Then that pair will not be re-suggested for that tenant. - Given merge or dismiss actions occur, When the activity feed updates, Then it records actor, timestamp, and a link to the diff.
Review Queue Triage and Bulk Approve/Deprecate
- Given low-confidence items (confidence < 0.70) exist, When a Reviewer opens the Review Queue, Then items are listed and groupable by jurisdiction and outcome with count badges. - Given multiple items (up to 200) are selected, When Bulk Approve is executed, Then approval status changes to Approved, approver and timestamp are recorded, and items become searchable immediately. - Given multiple items are selected, When Bulk Deprecate is executed, Then status changes to Deprecated, items are removed from suggestions, and remain discoverable via filters. - Given feedback is required, When Request Changes is applied in bulk, Then an assignee and comment are mandatory and tasks are created per item. - Given bulk actions are triggered, When processing completes, Then per-item success/failure is displayed and overall operation finishes within 3 seconds for 200 items. - Given role-based access control, When a non-Reviewer accesses the Review Queue, Then bulk action controls are hidden and API calls are rejected with 403.
Inline Comments and Activity Feed Transparency
- Given a clause is open, When a user selects text and adds a comment, Then the comment anchors to that text range and supports @mentions with notifications to mentioned users. - Given an open comment thread, When a user resolves it (Editor or Reviewer), Then the thread moves to Resolved with resolver and timestamp, and the anchor remains in history. - Given clause lifecycle events occur (create, edit, approve, deprecate, merge), When viewing the Activity feed, Then each event shows actor, timestamp, and a link to the related version or diff and can be filtered by type and date range. - Given multiple users collaborate, When new comments or events occur, Then comments and activity feed update in real time within 2 seconds. - Given a user has read-only access, When they attempt to add or resolve a comment, Then the UI prevents the action and the API returns 403.
Export Selected Clauses
- Given 1–100 clauses are selected, When the user exports DOCX or PDF, Then the file downloads within 5 seconds and preserves rich-text formatting and placeholder tokens intact. - Given 1–100 clauses are selected, When the user exports CSV or JSON, Then the export includes metadata (id, title, tags, jurisdiction, outcome, confidence, approval status, performance metrics, last updated) and adheres to the current filter set. - Given the "Keep order" option is enabled, When exporting, Then the export respects the current sort order in the results list. - Given tenant branding is configured, When exporting, Then the file name includes the tenant short name and timestamp and DOCX/PDF include the tenant logo watermark. - Given role-based permissions, When a user without Export permission attempts to export, Then the action is disabled and API calls return 403.
Authentication, Authorization, and Tenant Isolation
- Given a user session via Briefly auth, When accessing the Clause Library, Then the session is validated and unauthenticated users are redirected to login. - Given Tenant A user is authenticated, When searching, viewing, or exporting clauses, Then only Tenant A data is accessible; direct URL access to Tenant B resources returns 403 and is logged with tenantId and userId. - Given role-based permissions, When a Viewer, Editor, Reviewer, or Admin signs in, Then the UI only exposes actions allowed by the role and the API enforces the same checks. - Given background jobs (duplicate detection, review queue) run, When operating, Then they execute within the tenant context and never read or write across tenants. - Given audit requirements, When any read or write occurs, Then an immutable audit record is stored with tenantId, userId, action, resource id, and timestamp.
Variable Mapping & Assembly Integration
"As a solo attorney, I want clause placeholders to auto‑fill from my intake so that I can assemble retainers and first drafts instantly without manual edits."
Description

Map canonical placeholders in clauses to Briefly’s intake variables and conditional logic, enabling one‑click insertion into retainers and pleadings with live previews populated from client answers. Support fallback prompts for unmapped variables, validation rules, and jurisdiction‑specific variants. Ensure seamless use in e‑sign retainer generation and first‑draft assembly without retyping.

Acceptance Criteria
One-Click Clause Insertion with Live Preview
Given a clause has all required placeholders mapped and values available from intake When the user selects the clause and clicks Insert Then the clause is inserted at the cursor location in the target document And the live preview renders with client-specific values within 500 ms And the inserted text contains zero unresolved placeholders (no {{...}} tokens) And the insertion requires exactly one user click after clause selection And the insertion can be undone in a single undo action
Placeholder-to-Intake Variable Mapping
Given a clause containing canonical placeholders formatted as {{PlaceholderName}} When the user opens the Mapping panel for the clause Then each detected placeholder is listed with a suggested intake variable match And the user can map each placeholder one-to-one to a Briefly intake variable via search/select And unmapped placeholders are clearly flagged with a count badge And saved mappings persist at the clause level across matters And a test preview using a selected client record shows substituted values for mapped placeholders
Conditional Logic for Clause Variants
Given a clause has variants with conditions defined on intake variables When a client’s answers satisfy a variant’s condition Then that variant is selected; otherwise the defined default variant is used And conditions support operators ==, !=, >, <, >=, <=, contains, and in And multiple conditions can be combined with AND/OR and parentheses for grouping And changing an input value updates the selected variant in the preview within 500 ms
Fallback Prompts for Unmapped Variables at Insert Time
Given a clause contains placeholders without saved mappings When the user clicks Insert Then a prompt lists all missing variables with human-readable labels and input controls And required fields must be completed before continuing; optional fields may be skipped And user-provided values are applied for the current matter only unless "Save mapping" is checked And after completion, insertion proceeds with zero unresolved placeholders And the prompt appears within 1 second of clicking Insert
Validation Rules on Variable Values
Given placeholders have validation rules (required, data type, regex/pattern, min/max, allowed values) When preview or insertion is executed Then validations run client-side and server-side And blocking validation failures prevent insertion and display the failed rule, field, and value And non-blocking warnings can be overridden only with explicit user confirmation And validation outcomes are consistent between retainer generation and pleading assembly
Jurisdiction-Specific Clause Variants and Overrides
Given clause variants are tagged by jurisdiction hierarchy (Country > State > Court) When a matter includes jurisdiction metadata Then the most specific matching variant is auto-selected with fallback to broader scopes And the user can manually override the auto-selected variant before insertion And the final selected variant is recorded in the matter’s audit log And if no jurisdiction match exists, the default variant is used and a non-blocking notice is shown
End-to-End Use in E‑Sign Retainer and First‑Draft Assembly
Given mapped clauses are included in retainer and pleading templates When generating an e‑sign retainer or first‑draft document Then the system applies mappings, conditions, prompts, and validations without reconfiguration And the generated output contains zero unresolved placeholders or template tokens And the package assembles without merge-field errors and is ready for e‑signature And server-side assembly for these steps completes in under 30 seconds per matter

Redline Sync

Round-trip templates with Word: export for tracked changes, then re-import to apply edits without breaking merge fields or logic. Keeps attorneys in their comfort zone while locking improvements back into automation.

Requirements

DOCX Export with Track Changes Ready
"As a solo attorney, I want to export my draft to Word configured for tracked changes so that I can review and redline in my normal workflow without breaking automation."
Description

Generate a court‑ready first draft as a .docx that is preconfigured for Microsoft Word’s Track Changes workflow while preserving Briefly’s automation anchors. The exporter wraps merge fields, conditional blocks, and repeaters in uniquely identified Structured Document Tags (content controls) and embeds a manifest in custom document properties to map document ranges back to the originating template components. It applies style and numbering normalization for legal formatting, sets recommended Word review settings, and allows editable text around protected tokens so attorneys can freely redline without accidentally deleting automation markers. This integrates into Briefly’s document assembly step and becomes the default download path for Word users, ensuring smooth round‑trips and minimal formatting drift.

Acceptance Criteria
Export wraps automation anchors in uniquely identified content controls
Given a template containing merge fields, conditional blocks, and repeaters When the user exports the assembled document to DOCX via the default Word download path Then each automation anchor is encapsulated in a Structured Document Tag with a globally unique control ID And each control’s tag/alias references the originating template component ID And protected controls cannot be deleted or renamed via standard Word UI actions And text outside the controls remains fully editable with Track Changes enabled
Embedded manifest maps exported DOCX ranges back to template
Given a DOCX produced by the exporter When inspecting custom document properties Then a property named "BrieflyManifest" exists and contains valid UTF-8 JSON under 1 MB And the manifest includes exportVersion, templateId, documentId, createdAt, and a controls[] array of {controlId, templateComponentId, path, rangeStart, rangeEnd, checksum} And every controlId in the manifest is present in the document 1:1 And checksum validation for each mapped range passes
Word Track Changes and review settings are preconfigured on export
Given the exported DOCX is opened in Microsoft Word (desktop and web) Then Track Changes (track revisions) is enabled by default And the markup view defaults to Simple Markup And insertions and deletions are tracked; comments are enabled And formatting change tracking is disabled And balloons show comments and deletions; insertions display inline And Accept/Reject controls are available and functional
Legal styles and numbering normalization applied in export
Given a template with headings, paragraphs, and ordered lists When the document is exported to DOCX Then headings use built-in Heading 1–3 linked to a multilevel outline numbering scheme And body text uses Normal style with 1.15 line spacing and 6pt after And ordered lists use a single multi-level list template with correct restarts per section And no direct formatting is applied to content controls or numbering And a style audit reports zero undefined styles and zero orphan list templates And a save/reopen round-trip in Word yields zero differences in numbering compared to the original export
Export is the default Word download path in assembly flow
Given a user completes document assembly When the user selects Download > Word Then the Track-Changes-Ready DOCX exporter is used by default And the file name matches {clientLast}_{matterId}_{docName}_v{exportVersion}.docx And a 20-page document exports in ≤3 seconds on a cold run and ≤1.5 seconds warm And any legacy exporter, if present, is accessible only via an explicit "Legacy" option
Round-trip re-import preserves anchors and applies redlines safely
Given an exported DOCX is edited in Word with Track Changes and returned to Briefly When the document is re-imported Then all content control IDs are recognized and mapped via the embedded manifest And merge fields, conditional markers, and repeaters remain intact And accepted textual edits within mapped ranges are applied to the corresponding template components And attempted deletions of protected tokens are skipped and reported to the user And the re-import summary lists counts of applied, skipped, and conflicted changes
Redline Re‑import Parser
"As an attorney, I want to re‑import my redlined Word file so that my edits update the automated template without breaking fields or logic."
Description

Accept an edited .docx and parse Open XML tracked revisions, comments, and formatting changes to compute a semantic patch that can be safely applied to the source template. The parser resolves insertions, deletions, and moves relative to the embedded manifest IDs, distinguishes content edits from style‑only changes, and maps attorney edits to either template text blocks, variable default values, or conditional logic labels. It supports partial acceptance (e.g., content but not style), attaches comments to the corresponding template nodes, and yields a structured diff used by the review UI. This enables round‑trip synchronization that locks attorney improvements back into automation with fidelity.

Acceptance Criteria
Content Edits Re-import Preserves Merge Fields
Given a source template with manifest IDs and merge fields and a Word export with tracked insertions/deletions limited to content inside a text block When the edited .docx is re-imported Then the parser identifies the target node by manifest ID And computes a semantic patch with exactly the inserted/deleted text ranges And preserves all merge field codes/placeholders unchanged (0 field-code diffs) And marks each change as type=content with character offsets relative to the node And the patch applies without unresolved references or merge conflicts (0 errors)
Style-only Changes Are Separable and Optionally Rejected
Given an export where only style attributes (font, weight, italics, color, paragraph style, spacing, alignment) were modified with tracked changes And the user selects "accept content only" When the .docx is re-imported Then the parser classifies all detected changes as type=style (content change count=0) And produces a structured diff with style-only flags and no content patch operations And applying the patch updates no template content or metadata (0 content ops applied) And the regenerated template text matches the pre-edit version exactly (string-equal)
Variable Default Value Edits Map to Metadata
Given a template variable with a default value displayed in the exported document and a tracked edit changes that displayed value When the .docx is re-imported Then the parser maps the edit to the variable's default value via manifest ID And produces a patch op type=variable-default-update with old/new values captured And does not alter literal template text where the variable is inserted And regenerating the template shows the new default value wherever the variable appears
Conditional Label Rename Updates Logic Without Breaking Branching
Given a conditional block with a labeled option and a tracked edit changes only the option label text When the .docx is re-imported Then the parser maps the edit to conditional metadata (label), not the branch body And produces a patch op type=logic-label-rename with old/new label values And preserves the branch/condition IDs and expressions unchanged And regeneration routes decisions identically but displays the new label
Tracked Moves Recognized as Moves, Not Insert/Delete
Given a clause with an existing manifest ID is moved using Word tracked move (move-out/move-in) When the .docx is re-imported Then the parser emits a single patch op type=move with source/destination indices relative to the parent node And does not emit separate insert and delete for the same content (0 dup ops) And the clause appears exactly once at the destination in the updated template And all merge fields and internal IDs within the moved content remain intact
Word Comments Attach to Correct Template Nodes
Given one or more Word comments anchored to ranges that map to specific template nodes (including tables and headers/footers) When the .docx is re-imported Then each comment is attached to the corresponding node by manifest ID with start/end offsets And the structured diff includes author, timestamp, text, and resolved status for each comment And no comment is orphaned or misattributed (0 mismatches) And the count and text of comments in the diff equals the count and text in the .docx
Fallback Matching and Conflict Reporting for Unmapped Changes
Given edits occur in content lacking valid manifest IDs or with corrupted IDs When the .docx is re-imported Then the parser attempts text-similarity matching to locate the target node with threshold >= 0.85 And if below threshold, flags the change as conflict=true and does not apply it by default And the structured diff records reason (unmapped-id or low-similarity) and location context (paragraph index, snippet) And the import summary lists all conflicts with counts by reason and provides review actions
Merge Field and Logic Preservation
"As a template maintainer, I want fields and conditions preserved through Word round‑trips so that generated documents remain accurate and automated."
Description

Ensure that merge fields, conditional clauses, loops, and cross‑references survive export, attorney redlining, and re‑import without corruption. The system uses immutable IDs, boundary checksums, and guard rails (soft locks and auto‑repair of common breakages) to maintain template graph integrity even when tokens are moved or partially edited. On import, it validates referential integrity, auto‑rebinds displaced markers when unambiguous, and flags ambiguous cases for human review. Success criteria include zero loss of data bindings and accurate regeneration of the document post‑sync.

Acceptance Criteria
Clean Round-Trip Preserves Merge Bindings
Given a template containing at least 50 merge fields, 10 conditional blocks, 3 loop blocks, and 8 cross-references When the template is exported to Word with tracked changes enabled, no content edits are made beyond formatting, and it is re-imported Then import validation reports 0 broken bindings, 0 checksum mismatches, and 0 ambiguous items And all merge fields, conditionals, loops, and cross-references retain their immutable IDs And regenerating the document with the same dataset produces a normalized text diff of 0 differences compared to pre-export generation
Auto-Rebind After Token Move
Given a merge field token is cut-and-pasted to a different paragraph with tracked changes enabled When the document is re-imported Then the system rebinds the field to its original data source using the immutable ID And the field renders the correct value in its new location upon regeneration And import validation reports 0 warnings for unambiguous moves
Conditional Boundary Auto-Repair
Given a conditional block where the closing marker text is partially deleted or altered via tracked changes When the document is re-imported Then the system detects a boundary checksum mismatch And if a single unambiguous repair is possible, the marker is auto-repaired and the block remains valid And if multiple repairs are possible, the import flags the block as ambiguous, requires human review, and makes no destructive changes to the template And in either case, no data binding is lost and other unaffected parts of the template validate successfully
Loop Block Move and Partial Edit Handling
Given a loop block is moved as a whole to a new location (start and end markers moved together) When the document is re-imported Then the loop block is re-bound by immutable IDs, and regeneration iterates correctly over the dataset in the new location And import validation reports 0 errors Given only the loop start marker is moved or edited without its matching end When the document is re-imported Then the system detects the imbalance, attempts auto-repair if unambiguous, otherwise flags for human review with precise locations, and prevents committing a broken loop
Cross-Reference Preservation After Heading Edits
Given clause and section headings targeted by cross-references are renamed or renumbered via tracked changes When the document is re-imported Then cross-references remain bound to their targets by immutable IDs And displayed reference text updates to reflect the new numbering or title And import validation reports 0 orphaned or broken references
Ambiguity Detection, Review, and Audit Log
Given edits result in multiple possible targets for a displaced token or mismatched block boundaries When the document is re-imported Then the system halts auto-apply for the ambiguous items and presents a review queue enumerating each item with location, reason, and candidate resolutions And upon user selection, the system applies the chosen resolution, re-validates to Pass, and records an audit log entry capturing before/after, user, timestamp, and IDs And without user resolution, the template remains unchanged with a clear failure status for those items
Conflict Resolution & Review UI
"As a paralegal, I want a clear review interface for conflicts so that I can decide how each change should apply to the template before saving."
Description

Provide an interactive review screen that visualizes the Word redlines alongside the template structure. It highlights conflicts where edits intersect protected fields or logic, allows accept/reject per change, supports bulk decisions for style‑only updates, and offers mappings for ambiguous cases (e.g., "apply to text block" vs. "update variable default"). Users can preview the regenerated output with proposed changes, download a conflict report, and finalize to create a new template version. This UI integrates with Briefly’s template editor and permissions model.

Acceptance Criteria
Side-by-Side Redline & Structure Display
Given a Word document with tracked changes has been re-imported via Redline Sync When the review UI loads Then the left pane displays the document redlines exactly as in Word (insertions, deletions, moves, and format changes) And the right pane displays the template structure tree with the selected change’s path highlighted (e.g., Section > Clause > Paragraph) And selecting a change highlights the corresponding text in both panes and scrolls into view And each change is assigned a unique Change ID and shows type, author, and timestamp
Protected Elements Conflict Highlighting
Given the re-imported changes intersect merge fields or conditional logic blocks When the UI renders the change list Then those changes are flagged as Conflicts with a badge and reason (e.g., "Overlaps merge field", "Alters IF condition") And protected tokens are visually distinct and cannot be modified directly in the redline pane And clicking a conflict opens a details panel listing impacted fields/logic and available resolution options
Per-Change Accept/Reject Application
Given a change is selected in the list When the user clicks Accept Then the change is applied to the underlying template content while preserving all merge field tokens and logic semantics And the change status updates to Accepted and persists until Finalize or Undo When the user clicks Reject Then the template content remains as in the current version and the change is marked Rejected And accepting a deletion overlapping a merge field removes only surrounding text and keeps the field intact
Bulk Accept/Reject for Style-Only Changes
Given the change list includes style-only edits (formatting changes that do not alter textual content or field/logic tokens) When the user filters by Style-Only and clicks Accept All Then all style-only changes are applied to the template formatting and marked Accepted And merge fields and logic tokens remain unchanged And a summary shows count applied and any exceptions, with exceptions left for manual review And the user can Undo the bulk action in a single step
Ambiguous Change Mapping and Scope
Given a change ambiguously maps to either a variable’s default value or a local text block When the user opens the mapping prompt Then the options "Apply to text block only" and "Update variable default <varName>" are presented with an impact preview (scope and affected instances) And the user must confirm the selection before proceeding And the chosen mapping is applied, recorded in the audit trail, and becomes the default for similar ambiguous changes during this session (with ability to change later)
Preview Regenerated Output Reflecting Decisions
Given there are accepted, rejected, and undecided changes in the review When the user clicks Preview Output Then the system generates a merged preview using the template’s saved test data set without compile errors And the preview reflects accepted changes and excludes rejected ones; undecided conflicts are highlighted as pending And the user can toggle before/after views and navigate to each Change ID from the preview
Conflict Report Export and Version Finalization with Permissions
Given the review contains changes and the user has Template:Edit permission When the user clicks Download Conflict Report Then a report (CSV and PDF) is generated containing Change ID, type, location path, conflict status, decision, mapping choice, impacted protected elements, user, and timestamp And when all conflicts are decided and the user has Publish permission Then clicking Finalize creates a new template version with an incremented version number, a changelog of applied decisions, and a link to the source Word file And if permissions are insufficient or conflicts remain, Finalize is disabled with an explanatory tooltip and a list of blockers
Template Versioning & Audit Trail
"As a managing attorney, I want version history and an audit trail so that I can track who changed templates and revert when needed."
Description

Automatically create a new immutable template version on each successful re‑import, linking the version to the source .docx, change summary, and user identity. Maintain a complete audit log of accepted and rejected changes, with timestamps and before/after diffs. Provide compare, rollback, and release tagging to push updated templates into production. Exportable audit artifacts support compliance and supervision requirements common in consumer‑law practices.

Acceptance Criteria
Immutable Version Creation on Successful Re‑Import
Given a user with Template Editor permission uploads a .docx for re‑import When the import validation completes without mapping or syntax errors Then the system creates a new immutable template version with an incremented version number And links the version to the exact uploaded .docx via stored binary and SHA‑256 hash And records importer user ID, UTC timestamp, and a mandatory change summary And prevents any edits to the saved version payload after creation
Block Version Creation on Failed Validation
Given the uploaded .docx contains unresolved tracked changes or invalid merge fields/logic When the user attempts to finalize the re‑import Then the system blocks version creation And displays all blocking errors with references to section/paragraph/field And no new version appears in version history And the attempt is logged as a failed import with user ID and UTC timestamp
Change Resolution Audit Log
Given a .docx with tracked changes is re‑imported When the user accepts or rejects each change in the review UI Then each change is recorded with a unique ID, author (from docx if available), resolver user ID, resolution (accepted/rejected), UTC timestamp, location, and before/after text snippets And the full change log is linked to the resulting template version And the change log is read‑only and exportable
Version Compare Between Any Two Versions
Given two template versions are selected for comparison When the user initiates Compare Then the system displays a human‑readable diff highlighting insertions, deletions, and modifications, including merge fields and conditional logic changes And provides counts of changes by type And allows export of the comparison as PDF and JSON And records the compare action with user ID and UTC timestamp
Rollback Creates New Version From Prior
Given a user with appropriate permission selects a prior template version When the user confirms Rollback Then the system creates a new version identical in content and logic to the selected prior version And records source version ID, new version ID, user ID, and UTC timestamp in the audit trail And does not alter or delete any existing versions or logs And sets the new version as the active draft
Release Tagging and Push to Production
Given a user with Release Manager permission views a specific version When the user applies a unique release tag and confirms push to production Then the system marks that tagged version as the production version used by new documents And records tag name, user ID, UTC timestamp, and environment in the audit trail And requires non‑empty release notes/change summary And prevents reuse or deletion of a release tag once assigned
Exportable Audit Artifact Package
Given a template and a version or date range are selected for export When the user exports audit artifacts Then the system generates a package containing version metadata, full change audit log with before/after diffs, compare reports (if selected), release tags, and the source .docx And includes cryptographic hashes for all included files And provides the package as a downloadable ZIP containing PDF and JSON files And records the export event with user ID and UTC timestamp
Office 365/OneDrive & SharePoint Round‑Trip
"As an attorney, I want to open and save Word drafts directly from my OneDrive matter folders so that I can avoid manual file handling during redline sync."
Description

Enable direct open and save to OneDrive and SharePoint libraries commonly used by law firms, with deep links from matters in Briefly. Support file locks, check‑in/check‑out, and automatic Track Changes activation when opening. Provide drag‑and‑drop and picker‑based import, plus local filesystem support, across Windows and macOS Office builds. This reduces manual download/upload friction and aligns with attorneys’ existing Word storage workflows.

Acceptance Criteria
Deep Link Open in Word with Track Changes On
Given a Briefly matter document stored in OneDrive or SharePoint When the user clicks "Open in Word" in Briefly on Windows or macOS Then Word Desktop opens the document from its cloud URL (not a local temp copy) And Track Changes is automatically turned on before the document becomes editable And the document title and location shown in Word match the OneDrive/SharePoint path
OneDrive/SharePoint Locking and Checkout Compliance
Given a SharePoint library with "Require Check Out" enabled When a user opens the document via Briefly Then the document is automatically checked out to that user before edits are allowed And upon close or explicit check-in from Word, the document is checked in with any provided comments Given a OneDrive or SharePoint library without required check-out When a user opens the document via Briefly Then Word acquires an edit lock for the current user and other users see the file as locked or enter co-authoring per library settings And the lock is released when the user closes the document and no longer blocks other users from editing
Save Back to Original Cloud Path with Versioning
Given a document opened via Briefly from OneDrive/SharePoint When the user presses Save in Word Then the file is saved to the same cloud path without prompting for a new location And a new version is recorded in the document’s Version History And the saved timestamp visible in OneDrive/SharePoint updates to the current time
Microsoft 365 Picker-Based Import (OneDrive and SharePoint)
Given a Briefly user selects Import and chooses the Microsoft 365 file picker When the picker opens Then the user can browse and select .docx files from both OneDrive and SharePoint document libraries in their tenant And selecting an item the user lacks permission to access displays a clear permission error without closing the picker When the user selects one or more .docx files and confirms Then Briefly imports the files and displays progress and completion status for each file And non-.docx files are rejected with the message "Only .docx files are supported"
Drag-and-Drop Import from Desktop and OneDrive Sync
Given the user drags one or more .docx files from Windows Explorer or macOS Finder (including OneDrive synced folders) When the files are dropped onto a Briefly matter’s upload target Then the upload starts immediately and completes successfully, preserving original filenames And if a file with the same name already exists in the matter, the user is prompted to overwrite, keep both, or cancel And non-.docx files are rejected with the message "Only .docx files are supported"
Local Filesystem Open/Save Support with Track Changes
Given a .docx is selected from the local filesystem via Briefly on Windows or macOS When the user chooses "Open in Word" Then Word Desktop opens the local document and automatically turns on Track Changes When the user saves the document Then changes are written back to the same local file path without errors
Re-Import from Cloud Applies Tracked Changes without Breaking Merge Fields
Given a document exported by Briefly, edited in Word with Track Changes enabled, and saved back to its OneDrive/SharePoint path When the user chooses Re-Import for that document in Briefly Then Briefly retrieves the latest version from the original cloud path And applies the edits recorded by Track Changes into the automated template without altering merge field tags or conditional logic And the regenerated document text matches Word’s result with all changes accepted And any remaining unresolved tracked changes are surfaced to the user for resolution

Offline Sync Queue

Capture full intakes, uploads, and signatures even when clinic Wi‑Fi drops. Data is encrypted and queued locally, then auto‑syncs in the background the moment connectivity returns—with clear status badges and zero re‑entry. Conflict‑safe merge rules prevent duplicates and preserve who did what, so clinics keep moving without technical interruptions.

Requirements

Local Encrypted Offline Queue
"As a clinic attorney or intake staff, I want intakes, uploads, and signatures to save offline so that I can complete engagements without losing work when Wi‑Fi drops."
Description

Securely capture and store full intake answers, document scans, and signature payloads on-device when connectivity is unavailable. All queued records are encrypted at rest using platform keychain/keystore with per-tenant keys; data is partitioned by matter and signer, supports record-level encryption and selective purge. The queue persists across app restarts, enforces storage quotas and automatic aging policies, and guarantees no data loss or duplicate prompts. Integrates with existing intake flows and document assembly so users can proceed end-to-end without network access.

Acceptance Criteria
End-to-end offline intake capture
Given the device has no connectivity (airplane mode enabled) When the user completes an intake, scans 2 document pages, captures a signature, and taps Finish Then all answers, scans, and the signature payload are written to the local offline queue with a unique client record ID And the UI shows "Queued (offline)" badges on the intake and each asset within 1 second And the user can generate the retainer and first‑draft document offline using locally cached templates And no network error banners or retry prompts are shown
At-rest encryption with per-tenant keys and partitioning
Given tenant A is logged in and creates queued records for matter M1/signer S1 and M2/S2 while offline When the app is killed and the device is rebooted Then the queued records persist and are unreadable without the tenant A key (decryption fails if keys are cleared) And each record is encrypted independently (record-level) and tagged with matter_id and signer_id for partitioned access When the user logs out or switches to tenant B Then tenant A’s queued data is inaccessible in-app and cannot be decrypted; it is purged or locked per policy
Queue persistence across app restarts
Given 3 items are queued offline When the app is force-quit and reopened while still offline Then the queue displays the same 3 items with identical client IDs, attachments, and timestamps; no duplicates or missing items
Auto background sync with idempotency on reconnect
Given 4 queued items exist and the device regains connectivity When connectivity is detected Then background sync starts within 10 seconds without user action And each item is transmitted exactly once using its idempotency key; the server responds with canonical IDs And the UI updates each item to "Synced" with server ID and timestamp And transient failures are retried with exponential backoff up to 5 attempts; permanent failures show "Needs attention" without blocking other items And the user is not prompted to re-enter any previously captured data
Storage quota enforcement and aging policy
Given offline storage is at 95% of a 250 MB per-tenant quota (configurable) When a new 20 MB scan is attempted Then the system auto‑purges only previously synced items older than 14 days until usage is below 80% or no such items remain And if space remains insufficient, capture is blocked with a clear message and an action to purge synced items by matter; unsynced items are never deleted
Selective purge by matter and signer
Given there are synced local records for matters M1 and M2 across multiple signers When the user selects "Purge local data" for matter M1 Then only the encrypted blobs, indexes, and thumbnails for M1 are deleted; M2 remains intact And unsynced items are not purged; the UI lists items that could not be purged and why
Conflict-safe merge with audit preservation
Given the same matter is edited offline on Device A and edited online on Device B before Device A syncs When Device A reconnects and syncs Then no duplicate matters, signers, or documents are created on the server And updates are merged per defined rules; conflicting fields resolve deterministically And the server audit log attributes each field change to the correct user/device and timestamp
Background Auto‑Sync with Intelligent Retry
"As a user moving between rooms with spotty signal, I want the app to sync everything automatically when service returns so that I never have to re‑submit or wait on a spinner."
Description

Automatically sync queued items in correct dependency order (intake → documents → e‑sign events) as soon as connectivity is detected, without blocking the user. Implements connectivity monitoring, exponential backoff, jitter, and resumable transfers to minimize battery and bandwidth impact. Observes OS background execution limits, supports partial sync windows, and continues seamlessly when the app returns to foreground. Ensures idempotent server APIs and per-tenant rate limiting to prevent spikes during high-volume clinics.

Acceptance Criteria
Auto-Sync on Connectivity Return with Dependency Order
Given the device is offline with queued items including an intake A, two documents for A, and an e‑sign event for A When connectivity is detected Then the sync starts automatically in the background And intake A is created on the server first and returns a server_id And both documents are uploaded next referencing intake A’s server_id And the e‑sign event is posted only after both documents succeed And the user can continue using the app without blocked navigation or input during the sync
Exponential Backoff and Jitter for Transient Failures
Given a queued upload receives transient 5xx responses When the client retries Then delays follow exponential backoff of approximately 1s, 2s, 4s, 8s, 16s capped at 60s with ±20% jitter And after 5 consecutive failures the item remains queued with a retriable status and no user re‑entry required And upon the next successful attempt the backoff state resets for that item And if the device goes offline during backoff, retries pause and resume only when connectivity returns
Respect Server Rate Limiting Per Tenant
Given 100 queued items for the same tenant and connectivity returns When background sync begins Then no more than 3 concurrent requests are in flight for that tenant And if the server returns HTTP 429 with a Retry-After header, the client waits at least the indicated duration before retrying those endpoints And the client does not exceed the configured per-tenant request rate limit over any 60‑second window And items from other tenants may proceed in parallel within their own limits
Resumable Transfers for Large Document Uploads
Given a 50 MB document upload reaches 40% and connectivity drops When connectivity is restored Then the upload resumes from the last confirmed byte without restarting from 0 And total bytes sent do not exceed the file size by more than 2 MB of protocol overhead And the server-side checksum matches the local checksum And only a single document record exists on the server after completion
Background Execution Window and Foreground Continuation
Given the app starts syncing in the background with an OS-imposed 30s execution window When the window expires mid-transfer Then the client persists item checkpoints and pauses cleanly without data loss And when the app returns to foreground, sync resumes automatically within 2 seconds And partially completed items do not dispatch duplicate requests upon resumption
Idempotent API Calls and Duplicate Prevention
Given an intake submission is retried due to client timeout while the server processes the first request When the same request (with the same idempotency key) is retried Then the server returns the original resource ID without creating a duplicate record And only a single e‑sign event is recorded and sent And audit metadata (who/when) is preserved exactly once in the merged record
Conflict‑Safe Merge & Deduplication
"As an attorney at a pop‑up clinic, I want duplicates and conflicting answers to be resolved safely so that client records stay accurate without losing who entered what."
Description

Apply deterministic, conflict-safe merge rules when the same client or matter is captured multiple times on or offline. Use content addressing and field-level provenance to deduplicate uploads, reconcile questionnaire answers by timestamp and author, and preserve both values when conflicts cannot be auto-resolved. Never drop data silently; surface review flags on the server with links back to source events. Guarantees idempotent upserts and stable server-generated IDs to prevent duplicates across devices.

Acceptance Criteria
Idempotent Upsert Across Devices
Given identical client/matter payloads with the same client_local_uuid are captured on two devices (one offline) When both devices sync and upsert the payload, possibly retrying multiple times Then the server returns the same stable server_id for both requests And only one server record exists for the client/matter And duplicate retries with identical content do not change updated_at And provenance aggregates both source events (device_id, user_id, timestamps) on the single record
Content-Addressed File Deduplication With Provenance
Given the same binary file (identical content hash) is uploaded from multiple devices or sessions with different filenames When the offline queue syncs to the server Then only one stored blob exists with a single storage_id And each upload appears as a separate provenance event linked to that blob And any assembled documents reference the single blob And total stored bytes do not increase with duplicate uploads
Field-Level Merge by Timestamp and Author
Given two or more questionnaire answers exist for the same field with differing values and metadata (authored_at, author_id) When the merge engine reconciles the field Then the value with the latest authored_at is selected as canonical And all submissions are retained in field-level provenance And if authored_at is identical or values are incompatible, both values are preserved as a conflict set and the record is flagged Needs Review
Deterministic Merge Under Concurrency
Given overlapping intake events for the same client/matter are processed in varying orders across repeated replays When the merge is executed multiple times with the same inputs Then the resulting merged snapshot (fields, provenance, conflict flags) is identical across runs (hash-equal) And the server_id remains stable And no duplicate client/matter records are created regardless of processing order
No Silent Data Loss on Merge Failures
Given an incoming event contains an unknown field, schema mismatch, or fails validation When the merge engine processes the event Then the original payload is retained and retrievable in the audit log And an error event is emitted and a review flag is created referencing the source event And non-failing fields from the same event continue to merge And no data is dropped without a logged error and surfaced flag
Server Review Flags With Deep Links to Source Events
Given a merge results in preserved conflicting values for any field When the record syncs to the server Then a visible review flag appears for the client/matter in the dashboard And the flag includes deep links to each source event (intake session ID, device ID, timestamps) And resolving the flag via the UI lets the reviewer pick a canonical value, updates the record, closes the flag, and writes an audit entry
Offline E‑Sign Capture
"As a client signing in a dead zone, I want to complete e‑sign safely offline so that my engagement doesn’t stall due to connectivity."
Description

Enable legally compliant signature capture offline for retainers and first-draft filings, including signer consent prompts, signature images, typed names, and intent/event metadata (timestamp, device ID, user ID). Package signatures with document hashes and template versions to bind the signature to content. Queue the full signing event for sync and verification; on connect, validate document integrity, apply final certificates, and deliver signed PDFs to the matter without re-signing.

Acceptance Criteria
Offline Consent and Signature Capture — Single Signer
Given the device has no internet connectivity and a retainer is ready for signature When the signer opens the e‑sign screen for the retainer Then the signer is presented with a legally compliant consent prompt and must explicitly accept before any signature input is enabled And the signer can enter a typed full legal name and draw a signature image; both inputs are required to proceed And attempting to complete without consent or required inputs is blocked with a clear, inline error message And upon completion, the signing event is saved locally, encrypted at rest, and marked as Queued for sync And the UI displays an Offline — Queued badge for the document within 1 second of save
Offline Signature Event Metadata and Attribution
Given the device is offline and a signing event is completed When the event is saved locally Then the following metadata fields are captured and stored: device timestamp in UTC, timezone offset, device ID, app user ID, signer role, signature method (typed/drawn), consent accepted (boolean), and geolocation coordinates if permission is granted And an immutable local audit record is appended containing event ID, event type = SIGN_COMPLETED, and a cryptographic checksum of the record And the saved event cannot be edited; only a subsequent CANCEL or INVALIDATE action can supersede it, creating a new audit record And local validation shows all required metadata fields are present and non-empty (or explicitly null where permission denied)
Bind Signature to Document Content via Hash and Template Version
Given a signer is completing an offline signature for a specific document version When the pre-sign PDF render (or canonical content) is generated locally Then a SHA-256 document hash is computed and stored with the signing event along with template ID and template version And the signing coordinates/field anchors and page indices are recorded to ensure placement reproducibility And if any change is made to the document after hash computation, the app requires the hash to be recomputed and prior signature inputs are invalidated And on later sync, the server recomputes the hash for the canonical document; if it matches, the event proceeds; if it mismatches, the event is marked Conflict — Re-sign Required and is not applied
Auto-Queue and Background Sync on Reconnect
Given one or more offline signing events are queued on the device When stable connectivity is detected for at least 10 seconds or the user taps Sync Now Then the app attempts background upload of the queued signing events without interrupting user flow And each event transitions through statuses: Queued → Syncing → Synced or Error, with visible badges on the matter within 1 second of state change And retries use exponential backoff up to 5 attempts, then surface a resolvable Error status with a Retry action And uploads are idempotent using a unique event ID so repeated submissions do not create duplicates
Integrity Validation, Certificate Application, and Delivery Without Re‑sign
Given a queued offline signing event has been uploaded and its document hash matches the server’s canonical document and template version When the server processes the event Then a final PDF is generated with the signature image, typed name, UTC timestamp, and signer attribution placed at the recorded anchors And a final certificate (including audit trail, document hash, template ID/version, and signer metadata) is applied to the PDF And the signed PDF and certificate are attached to the correct matter and document record without requiring the signer to re‑sign And the matter timeline/audit log is updated with a SIGN_APPLIED entry and a delivery confirmation is visible to the user within 60 seconds
Conflict‑Safe Merge for Duplicate Offline Submissions
Given two offline signing events for the same matter and same document are uploaded from one or more devices before either is processed When the server receives both events Then if both events reference the same document hash, same signer, and same template version, only the earliest successfully processed event is applied and later events are marked Superseded with cross‑references in the audit log And if events differ in document hash or template version, neither is auto‑applied; both are marked Conflict — Re‑sign Required with a single user‑visible resolution task And no duplicate signed PDFs are created in the matter, and the audit trail preserves who did what and when for all events
Offline Data Protection and Lifecycle
Given signing data is stored offline on the device When the device is locked or the app is terminated/restarted or the device battery is depleted Then all queued signing data remains intact and decryptable only after a successful user authentication And signing payloads are encrypted at rest using the platform keystore; after 5 consecutive failed app unlock attempts, local access to payloads is blocked until successful authentication And upon successful sync and server confirmation, local copies of signing payloads are purged within 5 minutes while retaining non-sensitive status markers And if unsynced, signing data persists for at least 30 days (unless explicitly deleted by the user or org policy)
Chunked Uploads with Resume & Compression
"As intake staff scanning a multi-page packet, I want uploads to continue from where they left off so that I don’t have to re-scan or re-upload when the network blips."
Description

Support large photo and PDF uploads offline by chunking files, compressing images, normalizing orientation, and generating lightweight previews and OCR text where feasible. Store chunks locally with checksums for integrity; resume transfers exactly where they left off on reconnect. Deduplicate using content hashes, enforce file-type/size constraints, and perform server-side antivirus and OCR when synced. Integrates with camera and scanner flows with clear limits and progress feedback.

Acceptance Criteria
Resume Upload After Connectivity Loss
Given a user has uploaded some chunks of a file while offline When the device reconnects to the network Then the client requests the server's acknowledged chunk map and resumes uploading starting from the first missing chunk without re-sending acknowledged chunks And then the final assembled file on the server byte-for-byte matches the original local file (verified by SHA-256 hash equality) And then no additional user input is required to resume (zero re-entry), and the UI status transitions from "Queued (Offline)" to "Syncing" within 5 seconds of connectivity restoration And then total redundant data re-sent does not exceed one chunk And then per-file progress and time-remaining estimates continue from the prior state
Local Chunk Storage with Checksums
Given a large file is queued offline When it is chunked client-side Then the client creates fixed-size chunks per configuration and calculates a checksum (SHA-256) for each chunk and the whole file And then chunks and metadata are stored encrypted at rest on the device using OS-provided secure storage And when reading back chunks for upload Then each chunk checksum matches its stored value; otherwise the corrupted chunk is regenerated from source or the file is re-queued with an error state And then local chunks are deleted within the configured retention window after the server confirms receipt of all chunks and whole-file hash match And then total temporary storage consumed stays within the configured cache limit; if exceeded, the oldest pending uploads are paused with a clear UI warning
Image Compression and Orientation Normalization
Given a user captures a document photo via the in-app camera or imports an image When the item is queued for upload Then the image is normalized to upright orientation using EXIF data And then the client compresses the image to meet configured maximum dimensions and size budget while maintaining legibility, producing the configured output format (JPEG/PNG/HEIC) And then the post-compression file size respects the max per-file limit; if still above the limit, the user is prompted to retake or split, and the file is not queued And then a content hash is computed on the post-compression bytes for deduplication consistency
Lightweight Previews and Client OCR (Opportunistic)
Given a supported image or PDF is added while offline When device resources permit Then the client generates a lightweight preview thumbnail not exceeding the configured preview size and stores it with the upload metadata And then if on-device OCR is available and permitted, the client extracts text into a UTF-8 blob, marks it as "client_ocr", and associates language and confidence metadata And then if on-device OCR is not available or fails, the item is marked "Pending server OCR" without blocking the upload And then preview and client OCR artifacts are synced with the file on reconnect
Content-Hash Deduplication Across Queue
Given a new file is selected or captured When its whole-file content hash is computed Then if an identical hash exists in the local offline queue, the client prevents a duplicate entry and reuses the existing upload reference And then upon reconnect, the server compares whole-file hashes; if a matching artifact already exists server-side for the same matter, the server links instead of storing a duplicate, and the client marks the item as "Linked (Deduplicated)" And then audit logs record the user's action and linkage without losing attribution And then deduplication never suppresses files that differ by even one byte (hash mismatch)
File-Type and Size Constraints with User Feedback
Given a user attempts to add a file via camera, scanner, or file picker When the file type or size violates configured constraints Then the client blocks queuing, surfaces a clear message describing allowed types and size limits, and offers corrective actions (compress, rescan, split) And then for compliant files, the client displays per-file and per-chunk progress bars, current upload state (Queued, Syncing, Paused, Error, Complete), and remaining size/time estimates And then limits (max per-file size, total queue size, supported types) are visible within the capture/scan UI before selection And then errors include actionable codes retriable by the user without data re-entry
Server-Side Antivirus and OCR on Sync
Given an upload completes server-side assembly When antivirus scanning runs Then if malware is detected the file is quarantined, not attached to the matter, and the client is notified with a "Failed - Virus detected" status and remediation guidance And then if clean, server-side OCR runs for PDFs and images; the resulting text is attached to the document with language metadata And then when both scans complete, the client receives final statuses and updates badges to "Complete" or "Complete (OCR pending/failed)" as applicable And then server-side OCR supersedes client OCR if present, preserving the client OCR as a fallback with provenance metadata
Sync Status Badges & Queue Management
"As a paralegal working multiple matters, I want visible sync status and easy retries so that I can keep clinics moving without guessing what’s done."
Description

Provide clear, non-blocking UI indicators for each matter and artifact: Offline, Queued, Syncing, Needs Attention, or Synced. Show per-item progress, last attempted time, and error reasons with one-tap retry or cancel. Include a global offline banner and a queue screen with filters, capacity usage, and estimated time to sync. All messages are plain-language and actionable to reduce support burdens in busy clinic environments.

Acceptance Criteria
Per-Item Status Badges and Transitions
Given an attorney is viewing matters and artifacts with intermittent connectivity When the device is offline Then each unsynced item displays an "Offline" badge within 1 second and the UI remains fully navigable Given an item is saved locally and awaiting sync When the app detects any network connectivity Then the item's badge changes to "Queued" within 1 second Given a queued item When background sync begins Then the item's badge changes to "Syncing" and shows an animated indicator Given an item finishes syncing successfully When the server confirms receipt Then the item's badge changes to "Synced" within 1 second and persists across app relaunch Given a sync attempt fails for an item When an error is returned Then the item's badge changes to "Needs Attention" and no other status is shown concurrently Given a status badge is shown When viewing the item in list and detail screens Then the same status text is shown and remains consistent within 500 ms across views
Progress, Last Attempted, and One-Tap Retry/Cancel
Given an item is in Syncing When data transfer is in progress Then a progress indicator shows percent 0–100% based on bytes sent/total and updates at least every 500 ms Given any item has attempted sync When the attempt completes or fails Then "Last attempted" shows a timestamp in the user's local time zone with HH:MM and date Given an item is in Needs Attention When the user taps Retry Then a new sync attempt starts within 2 seconds and the progress indicator appears Given an item is Syncing or Needs Attention When the user taps Cancel and confirms Then the current attempt stops within 3 seconds and the item returns to "Offline" state with pending data retained Given an item is in Synced When the user views actions Then Retry and Cancel are not shown
Global Offline Banner
Given the device loses internet access When any screen is visible Then a non-blocking global banner appears within 2 seconds indicating "You're offline" and navigation remains usable Given the banner is shown When connectivity returns Then the banner auto-hides within 2 seconds and a brief "Sync resuming…" toast appears Given the banner is shown When the user expands details Then it shows the time of the last attempted sync in local time and a link to the Queue screen
Queue Screen with Filters, Capacity, and ETA
Given the user opens the Queue screen When items exist Then items are grouped by status (Offline, Queued, Syncing, Needs Attention) with counts for each Given the Queue screen is visible When the user applies a filter by status or artifact type Then the list updates immediately and results reflect the filter selection Given queued items are stored locally When the queue size exceeds 80% of the configured local storage limit Then a warning chip shows "Storage 80% full" and capacity usage in MB and % Given any item has a known size and recent throughput When calculating ETA Then an "Estimated time to sync" is displayed per item and for the total queue Given the app is terminated and relaunched When the user returns to the Queue screen Then previously visible items and their statuses rehydrate within 3 seconds
Background Auto-Sync on Connectivity Restore
Given items are Queued and the device is offline When connectivity returns Then background sync starts automatically within 2 seconds without blocking the UI Given background sync is running When the app is backgrounded or the device is locked Then sync continues and resumes on app foreground without data loss Given items were captured offline When sync runs Then no forms require re-entry and no duplicate artifacts are created
Plain-Language Actionable Messages
Given an item is in Needs Attention When an error message is shown Then the text states the problem and a next step in plain language (≤ 8th-grade reading level) and includes a Retry or Fix action Given a known error type occurs (e.g., file too large, expired token, conflict) When the message is shown Then the specific reason is included and the action maps to the remedy (e.g., "Reduce file size", "Re-authenticate", "Review conflict") Given a status badge or banner is shown When accessed by a screen reader Then it has an accessible label that includes the status text and item name
Audit Trail & Attribution Preservation
"As a supervising attorney, I want a complete audit of who did what offline so that I can defend the record and meet compliance obligations."
Description

Capture an append-only local event log for every offline action, including actor (user ID or kiosk device), timestamps, geotime where permitted, and before/after values for form fields. On sync, transmit events in order and attach them to the server audit trail to preserve chain of custody and authorship for compliance and court readiness. Ensure time drift handling and cryptographic signing of event bundles to detect tampering.

Acceptance Criteria
Append-Only Local Event Logging for Offline Actions
Given the device is offline and a user edits fields, uploads a file, or captures an e-signature When the app records the action Then it appends a new immutable event with fields: event_id (UUIDv4), actor_type (user|kiosk), actor_id, device_id, event_type, entity_id, field_name, before_value, after_value, device_timestamp (ISO8601 with ms), local_sequence (int), geotime (optional), and previous_event_hash (SHA-256) And Then local storage enforces append-only behavior; API calls to alter or delete prior events are rejected with an error And Then attempts to modify the local log file out of band are detected by hash mismatch on next sync and flagged for review
Ordered Sync and Server Audit Trail Attachment
Given N offline events exist with local_sequence values 1..N When connectivity is restored and sync begins Then the client transmits events strictly in ascending local_sequence order within a bundle_id and bundle_sequence And Then the server persists the events to the matter’s audit trail in that order, assigning server_event_id and linking prior_server_event_id to preserve chain of custody And Then duplicate transmission of the same bundle_id is idempotent and does not create duplicate audit entries And Then the UI displays Synced status and server receipt timestamp for each event
Time Drift Detection and Normalization
Given the device clock differs from server time by more than 2 minutes When an event bundle is synced Then the server computes clock_offset = server_received_time - device_timestamp_first_event and stores it on the bundle And Then each event is recorded with both device_timestamp and server_canonical_timestamp = device_timestamp + clock_offset And Then audit trail ordering uses server_canonical_timestamp and sets clock_skew_applied = true for affected events
Cryptographic Signing and Tamper Detection of Event Bundles
Given a bundle of offline events is ready to sync When the client signs the bundle hash (SHA-256 of canonical payload) with its device private key (Ed25519) and includes signature and key_fingerprint Then the server verifies the signature before accepting any events And Then if the bundle is altered, signature verification fails and the server rejects with HTTP 400 and code invalid_signature; no audit entries are written And Then valid bundles are acknowledged with bundle_id and signature_verified = true
Geolocation Permission and Capture Policy
Given org policy geotime_capture is enabled and OS location permission is granted When an offline event is recorded Then geotime fields (latitude, longitude, accuracy_m, device_timestamp) are included in the event And Given policy is disabled or permission is denied When an offline event is recorded Then geotime fields are omitted and reason = not_permitted is recorded; sync succeeds without geodata
Conflict-Safe Merge Preserving Authorship and Avoiding Duplicates
Given two actors make changes to different fields of the same intake, one offline and one online When offline events sync Then per-field last-writer-wins is applied using server_canonical_timestamp, retaining both changes in the final record And Then each field-change audit entry records correct actor_id and source (device|user) And Given a bundle retry occurs due to connectivity issues When the same bundle_id is processed again Then no duplicate field updates or audit entries are created
Signature and Upload Attribution in Audit Trail
Given a client completes an e-signature offline and uploads two files When the device reconnects and sync completes Then the audit trail contains entries for signature_started, signature_completed, and file_uploaded for each file with: actor_id, signer_id (for signature), file_hash (SHA-256), mime_type, file_size, device_timestamp, server_canonical_timestamp And Then stored file hashes match uploaded content; any mismatch causes rejection of the affected upload and a retry is queued And Then re-upload of identical content (same file_hash) within 24 hours links to the prior audit entry instead of creating a duplicate

Instant Language Swap

Switch the entire kiosk flow—questions, help text, receipts, and printed packets—into the client’s preferred language in one tap. Detect preference from device locale or a quick chooser, and allow staff to view an English helper overlay for rapid assistance. Improves comprehension, shortens explanations, and keeps multilingual lines moving.

Requirements

Auto Locale Detect & Quick Language Chooser
"As a client using the kiosk, I want my preferred language detected and easy to choose so that I can immediately understand the intake without extra assistance."
Description

Detect the client’s preferred language from device/browser locale and present a lightweight language chooser at first touch with sensible defaults and fallback to English. The chooser must be accessible, mobile‑friendly, and available throughout the kiosk flow via a persistent control. Integrate with existing session management to store the selected language, apply it across questions, help text, receipts, and printed packets, and respect clinic-level default language configurations. Log chosen and detected languages for analytics and operational reporting without storing PII.

Acceptance Criteria
Auto‑detects language from device/browser locale
Given a new kiosk session and a browser with primary locale "es-MX" When the welcome screen loads for the first time Then the system detects the locale and maps it to "es" And the language chooser preselects "es" And if the detected locale is not supported by the clinic, the preselection defaults to the clinic default language And if the clinic default language is unset, the preselection defaults to "en"
First‑touch lightweight language chooser is accessible and mobile‑friendly
Given the first user interaction on the welcome screen When the language chooser is presented Then the chooser shows all clinic-supported languages with their autonyms And the currently preselected language is clearly indicated And all options have minimum 44x44 px touch targets and are fully keyboard navigable And the chooser and controls have proper labels and roles for screen readers And closing or confirming the chooser returns focus to a predictable element
Persistent in‑flow language switcher control
Given any step of the kiosk flow When the user opens the persistent language control and selects "vi" Then the current screen content updates to "vi" without a full page reload And the selected language persists across navigation and refresh within the session And the persistent control remains visible and operable on every screen of the flow
Session storage and propagation across questions, help, receipts, and printed packets
Given a selected language "es" When the user views questions and help text and completes the flow to generate a receipt and printed packet Then questions and help text render in "es" And the receipt renders in "es" And the printed packet renders in "es" And if a translation key is missing in "es", the English string is used for that key
Clinic‑level default and allowed languages respected
Given a clinic default language "vi" and allowed languages ["en","vi"] And a device/browser primary locale "fr-FR" When the kiosk initializes Then the language chooser defaults to "vi" And only "en" and "vi" are offered as choices And if neither the detected locale nor the clinic default are supported, the chooser defaults to "en"
Language selection analytics logging without PII
Given a new session where the detected language is "es" and the user selects "vi" When the user proceeds past the first question Then an analytics event is recorded with fields: sessionId (non-PII), clinicId, detectedLanguage "es", chosenLanguage "vi", selectionSource "manual", timestamp And no PII (names, emails, phone numbers, typed answers) is stored in the event And events are recorded for both detection and final selection
Resilient fallback when translations fail to load
Given the selected language is "es" and the "es" translation bundle fails to load When the next screen renders Then the UI renders using English strings instead of failing And a single non-PII error event is logged for the session And the persistent language control remains available for the user to retry or choose another language
One‑Tap Session‑Wide Language Swap
"As a client, I want to switch the entire flow into my language in one tap without losing progress so that I can complete intake faster and with confidence."
Description

Provide a single control that instantly switches all UI copy, dynamic questions, validation messages, contextual help, receipt text, and assembled document templates into the selected language without page reload and without losing user-entered data or validation state. Ensure branching logic and conditional content re-render correctly in the new language. Persist the choice in session storage and audit logs, and expose an API to trigger swaps programmatically. Include graceful fallback for untranslated strings and a banner indicating active language with a quick revert option.

Acceptance Criteria
One‑Tap Swap Preserves Inputs and Validation
Given an in‑progress intake with user‑entered values and visible validation messages When the user taps the language switcher to change from English to Spanish Then all visible UI copy (labels, questions, help, buttons, progress, validation text) updates to Spanish without a full page reload within 500 ms And all entered values remain unchanged And all validation states (field errors, error summary, field focus, scroll position) remain intact
Dynamic Branching Re‑renders Correctly After Swap
Given conditional questions are shown/hidden based on prior answers When the language is switched Then the set of visible/hidden questions remains identical to before the switch And option lists, computed labels, and conditional text re‑render in the new language And hidden fields remain hidden and retain their values
Session Persistence and Audit Logging of Language Choice
Given a new kiosk session When the user selects French from the switcher Then the selection is stored in session storage as the active locale And subsequent steps in the flow default to French for the remainder of the session And an audit event is recorded with fields: timestamp, sessionId, fromLocale, toLocale, trigger=ui And on session end, the stored locale is cleared
Programmatic API Trigger for Language Swap
Given a valid session identifier and an authenticated client When a programmatic request to change locale to "es" is made via the language‑swap API Then the session's active locale changes to "es" And the kiosk client updates UI to Spanish within 1 second without page reload And an audit event is recorded with trigger=api and the requesting principal And the API responds with success and the applied locale
Graceful Fallback for Untranslated Strings
Given Spanish is active and a string key lacks a Spanish translation When the UI renders that key Then the user sees the English text for that key (no raw keys or placeholders) And a telemetry record of the missing translation (locale, key) is logged once per session And the absence of translation does not block progression or submission
Banner Indicator and Quick Revert
Given the user switches from English to Vietnamese When the UI refresh completes Then a persistent, accessible banner or chip displays the active language and a "Switch to English" control And activating the revert control returns all copy to English without page reload, preserving inputs and validation state And the banner is reachable by keyboard and announced by screen readers with the active language name
Localized Receipts and Assembled Documents
Given the user completes intake with Spanish as the active language When the system generates the receipt and assembled retainer/court draft Then the generated documents use the Spanish templates and localized variables (dates, numbers, currency labels) And document filenames and receipt headers are localized to Spanish And any untranslated template section falls back to English while preserving formatting And e‑sign prompts and receipt text reflect Spanish
English Helper Overlay for Staff
"As a staff member assisting at the kiosk, I want an English helper view of the current screen so that I can guide clients accurately without taking over or changing their language settings."
Description

Enable staff to activate an English helper overlay that displays the current screen’s labels, prompts, and validation in English on a secondary view or overlay while the client’s device remains in their chosen language. Include role-based access, privacy safeguards (no sensitive answers shown on the overlay), and tethering to the client session for real-time screen parity. Provide quick toggle controls, hotkeys, and kiosk mode compatibility to speed assistance and reduce interruptions. Log usage for training and support metrics.

Acceptance Criteria
Staff Activates English Overlay for Active Client Session
Given a logged-in staff user with overlay permission and an active client session selected, When the staff toggles the English Helper Overlay, Then an overlay opens on the staff view showing the current screen’s titles, field labels, help text, and validation message placeholders in English, and the client device remains unchanged in its chosen language. Given the client navigates to a new screen, When the client screen changes, Then the overlay updates to the matching screen within 200 ms and reflects the new labels/prompts in English. Given the client triggers a validation error, When the error appears on the client device, Then the corresponding validation message appears in English on the overlay within 200 ms.
Role-Based Access Control for Overlay
Given a user without the Staff:Assist permission, When they attempt to open the English Helper Overlay, Then access is denied with an inline notice and no overlay content is rendered. Given a user with the Staff:Assist permission, When they open the English Helper Overlay, Then the overlay opens successfully and an audit event is recorded with user ID, role, timestamp, and session ID.
Privacy Safeguards and Data Redaction
Given any overlay state, Then no client-entered answers, uploaded files, signatures, or PII are displayed; only labels, prompts, and validation messages are shown in English. Given a field contains a value on the client device, When that field is visible, Then the overlay displays a masked placeholder (e.g., ••••) or explicitly indicates “Client answer hidden,” and copy/select actions on overlay content are disabled. Given overlay content is visible, When a screenshot/capture protection layer is supported by the platform, Then a visible watermark "Staff Aid – No Client Data" appears on the overlay area.
Session Tethering, Sync, and Recovery
Given multiple kiosks are active, When staff scans a kiosk QR code or enters a session code, Then the overlay tethers to that client session and displays the exact current screen in English. Given a brief network interruption up to 5 seconds, When connectivity resumes, Then the overlay resynchronizes to the client’s current screen within 1 second and records a recovery event. Given the client session ends or times out, When the session is no longer active, Then the overlay auto-detethers, hides screen content, and prompts staff to select a new session.
Quick Toggle Controls, Hotkeys, and Kiosk Mode Compatibility
Given the staff view has focus, When Ctrl+Shift+E (or a configured hotkey) is pressed, Then the overlay opens or closes within 500 ms. Given the on-screen toggle is used, When the staff taps the overlay toggle, Then the toggle state is reflected immediately and the overlay opens/closes without disrupting the client device. Given the kiosk is in locked mode, When the overlay is toggled from the staff view, Then the client flow remains uninterrupted and input focus stays on the client device.
Usage Logging and Metrics
Given any overlay lifecycle event (open, close, tether, detether, permission denied), When the event occurs, Then an audit record is stored with timestamp, staff user ID, role, session/kiosk ID, event type, and duration (where applicable), excluding client answers/PII. Given an admin requests usage metrics for a date range, When the report is generated, Then a CSV is available containing counts by staff user and kiosk, total overlay durations, and event breakdowns, with all entries free of client answers/PII.
Multilingual PDF & E‑Sign Output
"As an attorney, I want PDFs and e‑sign packets generated in the client’s language with correct formatting so that documents are professional, compliant, and court‑ready."
Description

Localize all assembled outputs—retainers, disclosures, and first-draft filings—into the client’s selected language, including clause libraries, headings, captions, dates, and numeric formats. Embed Unicode-capable fonts and glyphs, handle hyphenation and line breaks for target scripts, and ensure right fonts are subset into PDFs for print fidelity. Integrate locale-aware e‑sign flows (emails, SMS, signing UI) and map language to the correct document templates per jurisdiction. Provide attorney-view bilingual versions where required and watermark machine-assisted translations when applicable.

Acceptance Criteria
Spanish Retainer PDF with Locale Formatting
Given a client completes intake and selects Spanish (es-ES) And the attorney’s jurisdiction is set to California When the system assembles the retainer PDF Then all static and dynamic text (headings, clause library, captions, answers) render in Spanish And all dates render in dd/MM/yyyy per es-ES And numbers render with decimal comma and period as thousands separator per es-ES And hyphenation and line breaks follow Spanish rules with no improper syllable breaks And required Unicode glyphs (ñ, ¿, ¡, á, é, í, ó, ú) display without missing-glyph boxes And all fonts used are embedded and subset; the PDF contains no references to external fonts
Arabic Filing PDF with RTL and Ligatures
Given a client selects Arabic (ar-SA) When the system generates the first-draft filing PDF Then paragraph and inline text direction is right-to-left with correct bidirectional reordering And Arabic shaping and ligatures render correctly with no character separation And line wrapping does not break inside ligature clusters or before/after Arabic diacritics And numerals follow ar-SA locale (Arabic-Indic digits) unless a field is explicitly configured to Latin digits And all Arabic glyphs are present with embedded, subset Unicode fonts; no font substitution occurs
Localized E‑Sign Invitations and Signing UI
Given a client selects Korean (ko-KR) and provides an email and mobile number When the system issues e‑sign invitations Then the email subject and body, SMS text, and signing UI labels appear in Korean And the e‑sign link opens with Accept-Language=ko and renders the signing UI in Korean And OTP/SMS verification screens are localized in Korean And if the e‑sign provider lacks Korean for any label, the system falls back to English for that label and logs a localization gap with severity "Low" And the audit trail and signed certificate retain the signer display name and timestamps formatted per ko-KR locale
Jurisdiction Template Mapping by Language
Given jurisdiction = Texas JP Court, case type = Debt, and client language = Simplified Chinese (zh-CN) When assembling disclosures and filing drafts Then the system selects the zh-CN variants of the Texas JP templates where available And if a zh-CN template is not available, the system selects the approved bilingual (en + zh-CN) template for that document type And if neither zh-CN nor bilingual exists, the system applies machine-assisted translation per policy to produce a zh-CN version from the English template and flags the document "Needs Language Review" And all template selections are recorded in assembly logs with template IDs, language codes, and rationale
Attorney Bilingual Retainer View
Given a matter is flagged "Bilingual Output Required" with languages English and Vietnamese (vi-VN) When the attorney opens the assembled retainer Then a bilingual PDF is produced with English and Vietnamese sections aligned clause-for-clause And each clause shares a stable identifier across both languages to enable side-by-side review And the attorney can toggle single-language or bilingual view in the viewer without regenerating the document And bookmarks and table of contents list both language headings with appropriate language tags
Machine-Assisted Translation Watermarking
Given a document includes machine-assisted translations (MT flag = true) When the PDF is generated and sent to e‑sign Then each page displays a visible "Machine-assisted translation" watermark in the target language at 10%–15% opacity within the footer margin And the watermark persists in the final signed PDF and in any downloaded or printed copies And if MT flag = false (human-verified), no watermark appears And the audit log records watermark presence/absence, timestamp, and the user or process that set the MT flag
RTL & Complex Script Support
"As a multilingual client, I want Arabic, Hebrew, and other scripts to display and input correctly so that the intake feels trustworthy and easy to read."
Description

Add full bidirectional and complex script support, including UI mirroring for right‑to‑left languages, correct caret movement, punctuation handling, and text alignment. Ensure inputs, masks, and validators accept non‑Latin characters; localize numbers, dates, and currency formats per locale; and verify readability across Arabic, Hebrew, CJK, and diacritics-heavy languages. Update style system (tokens, spacing, icons) to mirror appropriately and run cross‑browser/mobile rendering tests. Provide per-language typography presets and fallback font stacks.

Acceptance Criteria
RTL UI Mirroring and Iconography in Kiosk Flow
Given the kiosk locale is set to an RTL language (e.g., ar, he) When the questionnaire, help, and navigation screens render Then the root direction is rtl, layout grids and spacing tokens mirror, and reading order flows right-to-left Given an RTL locale When viewing navigation and progression controls Then directional icons (chevrons/arrows) are horizontally mirrored and step progression flows right-to-left; non-directional icons remain unflipped Given an RTL locale When displaying form fields and validation messages Then labels, inputs, helper text, and errors are right-aligned with correct tab order and no overlap or truncation Given the user switches back to an LTR locale When the UI re-renders Then all mirroring reverts to LTR with original icon orientation and alignment
Bidirectional Caret and Selection Behavior
Given a single-line RTL text input containing mixed Arabic and English text When pressing Left/Right arrow keys Then the caret moves in visual order appropriate to RTL and across script runs without skipping or reversing unexpectedly Given an RTL input with mixed-direction content When pressing Backspace or Delete at a script boundary Then the character visually adjacent to the caret is removed and grapheme clusters are not split Given an RTL textarea When performing Shift+Arrow selection and mouse/touch drag selection Then selection expands in visual order and highlights complete grapheme clusters Given an RTL input on iOS and Android When moving the caret with touch handles Then handles appear on correct sides and movement respects RTL visual order
Punctuation, Numerals, and Mixed-Direction Text Rendering
Given a sentence in Arabic containing neutral punctuation, parentheses, and embedded Latin terms (e.g., "إجمالي (USD) 123") When rendered in the UI Then punctuation binds to the correct run, parentheses are mirrored, and visual order matches reading expectations Given an RTL locale that prefers native digits When rendering numbers inside RTL text Then native digits are displayed and do not cause ordering issues around currency symbols or percent signs Given concatenated labels and dynamic values of differing directionality When displayed together Then appropriate Unicode bidi isolation/marks are applied to prevent garbling and ensure correct visual order
Unicode Input, Masks, and Validation for Non‑Latin Scripts
Given name and address fields When the user inputs Arabic, Hebrew, or CJK characters including diacritics and full-width forms Then the inputs accept, display, and submit the characters without loss, normalization issues, or substitution Given masked inputs (e.g., phone, ID) in an RTL locale When the user types native numerals Then the mask accepts native digits, displays them correctly, and normalizes to a canonical numeric value for storage Given validation rules for text fields When evaluating user input Then regex/pattern validators use Unicode-aware classes and do not reject valid non‑Latin characters; IDN domains are accepted in URL/email domain parts Given IME composition on desktop and mobile When entering CJK text into masked or validated fields Then composition events do not break the mask or prematurely validate
Locale-Specific Number, Date, and Currency Formatting
Given a selected locale When rendering numbers, dates, and currency in the UI and receipts Then CLDR-backed formats are applied (digit shapes, grouping, decimal separators, symbol placement) appropriate to that locale Given numeric and date inputs When users enter values using native digits in their locale Then inputs parse correctly, store canonical representations, and re-display in localized format Given currency amounts in RTL text When rendered alongside codes/symbols Then bidi isolation prevents symbol/value reordering and negative signs appear in the correct visual position
Per‑Language Typography Presets and Fallbacks
Given language presets for Arabic, Hebrew, Simplified Chinese, Traditional Chinese, Japanese, and Korean When text renders across headings, body, buttons, and captions Then the configured font stacks load with appropriate weight/line-height and provide complete glyph coverage without tofu Given diacritics-heavy Arabic text and Hebrew with niqqud When rendered at minimum supported sizes Then diacritics are legible and do not collide with adjacent glyphs or clipping bounds Given dynamic content with truncation When text overflows Then truncation/ellipsis behaves correctly for the script and does not cut combining marks or break grapheme clusters
Cross‑Browser, Mobile, and Print Rendering Validation for RTL & CJK
Given the supported environment matrix (iOS Safari, Android Chrome, macOS Safari/Chrome, Windows Chrome/Edge — latest 2 versions) When executing visual regression tests on 10 representative screens in RTL (ar, he) and CJK (zh-Hans, ja, ko) Then no text clipping/overlap occurs, directional UI elements are correctly mirrored, and font fallback renders without missing glyphs Given font loading When pages render Then layout shift due to font swap remains under 0.1 CLS and there are no reflows that disrupt reading order in RTL Given receipts and printed packets generation When exporting to PDF and printing from supported browsers in RTL and CJK locales Then text direction, glyph shaping, punctuation order, and page numbering are correct; fonts are embedded to preserve glyphs; no mirrored artifacts are lost
Offline Language Packs & Caching
"As an office admin, I want language packs to work offline and update safely so that kiosks remain usable even when the internet is unreliable."
Description

Bundle translation catalogs, fonts, and document template fragments as versioned language packs that can be preloaded to kiosks and cached for offline use. Implement background updates with integrity checks, delta downloads, and safe rollback. Provide a configurable fallback chain (e.g., es‑MX → es → en) and telemetry for pack version and cache hit rates. Ensure packs cover UI strings, help content, and PDF resources to keep multilingual flows functional during network outages.

Acceptance Criteria
Offline Flow With Preloaded Pack
Given the kiosk has language pack es-MX v1.4 preloaded and network connectivity is unavailable And the device locale is es-MX and the user selects Español (México) When the user completes the full intake-to-engagement flow including receipt and packet generation Then 100% of UI strings, help content, and PDF resources are served from local cache with 0 network requests And no missing translation keys or resource fallbacks occur for es-MX And receipt and packet PDFs generate and print successfully with correct glyph rendering And end-to-end flow time does not exceed 30 minutes
Fallback Chain Resolution
Given the kiosk has packs es-MX v1.4 and es v1.9 installed and network connectivity is unavailable And some es-MX translation keys and PDF template fragments are intentionally absent When the user runs a session in Español (México) Then missing resources resolve via es first and then en per configured chain es-MX -> es -> en And after fallback resolution, the count of unresolved keys/fragments is 0 And UI displays no placeholder text, and PDFs render without missing text or layout breaks And a session-scoped log records the number of fallbacks by resource type and language
Background Delta Update With Integrity Check
Given the kiosk is idle with es-MX v1.4 installed and online And the server offers es-MX v1.5 with a delta package and signed manifest When the update process runs in the background Then only the delta payload is downloaded and applied atomically to a staging location And package signature and checksum validation succeed before activation And no active session is interrupted; activation occurs between sessions And on success the active version switches to v1.5 and the previous version remains retained
Automatic Rollback On Post-Update Error
Given es-MX v1.5 is active and v1.4 is retained And runtime validation detects missing template fragments or repeated render errors exceeding 3 occurrences in a session When rollback conditions are met Then the system reverts to v1.4 within 60 seconds without user intervention And the failed version is quarantined and not reactivated automatically And telemetry records rollback reason, from/to versions, and error signatures
Telemetry: Pack Version And Cache Hit Rates
Given telemetry is enabled and the kiosk runs sessions online and offline When sessions complete Then the kiosk records for each session: selected language, active pack version, fallback counts, cache hits/misses for UI/help/PDF resources, and update status And telemetry is buffered locally while offline and transmitted within 2 minutes of reconnect And PII is excluded; payload size per session does not exceed 32 KB And daily retention of buffered telemetry does not exceed 7 days or 10 MB, whichever comes first
PDF Resources And Fonts Offline
Given the selected language requires non-Latin glyphs and the kiosk is offline When receipt and packet PDFs are generated Then font files are loaded from the language pack, embedded or subset as required And no tofu/missing glyphs appear; text is selectable and copyable And PDF generation success rate is 99.5%+ across 200 consecutive offline attempts And generated files remain under 5 MB each unless images exceed this limit
Admin Preload And Cache Persistence
Given an admin preloads language packs es-MX v1.5 and es v1.9 via MDM or console When the kiosk receives and installs the packs Then packs are stored under versioned directories with integrity hashes verified And packs persist across reboot and app updates And at least the two most recent versions per language are retained for rollback within a 2 GB cache budget And an admin view displays installed languages, versions, and hash statuses matching the device state
Translation Management & Legal Glossary QA
"As a legal operations manager, I want a controlled translation workflow with glossaries and approvals so that legal terms stay consistent and compliant across languages."
Description

Introduce a translation management workflow with term glossary, string keys, context notes, and versioning to ensure consistency of legal terminology. Support import/export to common localization formats, machine‑seeded drafts with human review, placeholders and pluralization rules, and flags for high‑risk clauses requiring legal sign‑off. Add coverage reports for untranslated/changed strings, staging previews for each language, and automated checks to prevent missing keys in production.

Acceptance Criteria
Glossary Term Enforcement and Versioning
Given a maintained legal glossary with term entries per language and a published glossary version, When a translator edits a string containing a glossary term marked as Locked, Then the suggested translation auto-inserts the locked term and the system blocks submission if the locked term is altered, requiring an override reason and raising a policy warning. Given a new glossary version is published, When language bundles are rebuilt, Then all strings containing glossary terms are revalidated and updated to the latest mappings and a changelog lists impacted keys and languages. Given a string includes context notes and domain tags, When viewed in the translation UI, Then the notes and domain tags are displayed alongside the string for all target languages.
Localization Import/Export Compatibility
Given a project, When exporting translation resources, Then the system produces XLIFF 2.0, JSON (ICU MessageFormat), and CSV files including key, source, target, status, glossary hits, and context fields. Given a valid exported file is edited and re-imported, Then the import validates schema, merges changes without data loss, preserves statuses, and reports counts for added/updated/skipped entries. Given an invalid file (schema or encoding errors), Then the import is rejected with a non-zero error code and a line-specific error report. Given an export→import→export round-trip on unchanged data, Then the second export is content-equivalent to the first (ignoring ordering/whitespace).
Machine-Seeded Drafts and Human Review Workflow
Given machine seeding is enabled for a language, When a new source key is added or modified, Then a machine translation draft is created and marked Needs Review with source/engine metadata. Given a translation is Needs Review, When generating production bundles, Then the string is excluded from production unless an approved fallback language is configured; the build fails for Production languages with any Needs Review items. Given a reviewer approves or rejects a string, Then the system records reviewer ID, timestamp, previous value, and comment in an immutable audit trail.
Placeholder and Pluralization Integrity
Given strings contain placeholders like {clientName} and ICU plural/select forms, When importing, editing, or exporting, Then placeholders and ICU syntax are preserved exactly and validated for balance and compatibility per locale. Given a translation modifies, drops, or duplicates placeholders, Then the UI blocks save with a precise validation error listing the offending placeholders. Given sample variables are provided, When rendering previews, Then outputs match expected plural categories for at least English, Spanish, and French test locales.
High-Risk Clause Legal Sign-Off Gate
Given a key is flagged High Risk, When a translator attempts to approve it, Then the system prevents approval and requires assignment to a user with Legal Approver role. Given a language has any High Risk keys without legal approval, When attempting to mark the language Ready for Production or build production bundles, Then the action fails and lists the pending keys. Given a Legal Approver approves a High Risk key, Then an approval record with approver ID, timestamp, and linked key/version is stored and visible in audit logs.
Coverage and Missing-Key Guardrails
Given translation coverage reports are generated nightly and on demand, When viewing a language, Then the report shows total keys, translated, needs review, outdated, missing, and high-risk pending counts with percentages. Given the source text changes for a key, When the change is merged to main, Then all existing target translations for that key are marked Outdated and reflected in coverage within 5 minutes. Given a language is marked Production, When CI runs, Then the build fails if translated < 100%, needs review > 0, outdated > 0, or high-risk pending > 0, and the artifact includes the JSON coverage report. Given a missing key is referenced at runtime due to misconfiguration, Then the system surfaces a fallback string in English, logs an error with key and language, and raises an alert within 5 minutes.
Per-Language Staging Preview and QA Signoff
Given a staging environment and selected target language, When previewing the kiosk flow, receipts, and generated packets, Then all UI strings and document content render in the target language with in-context key and note access. Given QA identifies issues, When they annotate in context, Then comments are linked to string keys and appear in the translation UI task queue. Given all coverage and legal gates are satisfied for a language, When a QA Lead marks Language Ready, Then the language state changes to Production-Ready and is eligible for inclusion in the next production build.

Queue Tickets

Issue scannable, QR‑based tickets that show place‑in‑line on the client’s phone and on a staff triage board. Route attendees to the right station (intake, review, e‑sign, print) and prioritize vulnerable clients with one drag‑and‑drop action. Reduces crowd confusion, prevents skipped steps, and increases clinic throughput.

Requirements

QR Ticket Generation
"As a clinic intake coordinator, I want to issue QR tickets that uniquely identify each attendee so that we can track and manage their place in line without duplications or lost paper slips."
Description

Generate unique, scannable tickets linked to a Briefly matter or prospect, encoding a short URL and tokenized QR code that can be printed or displayed on a client’s device. On creation, assign a queue ID, initial station, and SLA window. Ensure collision-free IDs, offline-safe QR payloads, and automatic expiration/cleanup after engagement or no‑show. Provide server endpoints to validate and redeem tickets upon scan, with role-based access controls for staff devices.

Acceptance Criteria
Generate Ticket with Queue Assignment and SLA
Given a POST /tickets request with a valid matterId or prospectId, initialStation, and slaMinutes When the request is processed Then the API responds 201 with ticketId, queueId, initialStation, slaExpiresAt (now + slaMinutes), shortUrl, and qrImage (PNG or SVG) And the ticket is persisted with the same values retrievable via GET /tickets/{ticketId} And slaExpiresAt is in UTC ISO-8601 and not earlier than now + slaMinutes - 1s And queueId is assigned per clinic context and is non-null
Collision-Free Ticket IDs
Given concurrent creation of 100,000 tickets across 10 threads When creation completes Then there are 0 collisions across ticketId, token, and shortUrl code spaces And database unique constraints exist on ticketId and shortUrl code And retry-on-conflict logic ensures successful creation without user-visible errors
QR Payload Offline-Safe Format
Given a generated ticket Then the QR encodes a compact payload <= 400 bytes containing a shortUrl and a signed token with ticketId, initialStation, and slaExpiresAt And the token signature is verifiable offline using the platform public key And scanning without network still yields ticketId and initialStation locally And no PII (client name, phone, email) is present in the QR payload
Validate Ticket Endpoint
Given an authenticated staff device with role scope ticket:validate When it calls GET /tickets/{token}?action=validate on an active ticket Then the API responds 200 with status=active, currentStation, queuePosition, slaExpiresAt, and ticketId When the token is invalid or tampered Then the API responds 401 with no ticket details When the ticket is expired Then the API responds 410 Gone And an audit event is recorded with actorId, deviceId, ticketId, action=validate, and timestamp
Redeem Ticket Endpoint (Idempotent)
Given an authenticated staff device with role scope ticket:redeem and Idempotency-Key header When it POSTs /tickets/{token}/redeem with station=currentStation Then the API responds 200 with updated status and nextStation (or completed=true) and does not create duplicates When the same Idempotency-Key is retried within 24h Then the API returns the original 200 response and no additional side effects occur When redeem is attempted for a station that does not match currentStation Then the API responds 409 Conflict and no state change occurs
Automatic Expiration and Cleanup
Given a ticket whose matter is engaged OR now > slaExpiresAt + 30 minutes When the hourly cleanup job runs Then the ticket status becomes expired and its token is invalidated And GET by token returns 410 and by ticketId shows status=expired And PII fields are cleared or anonymized while audit logs remain intact for 90 days And expired tickets are no longer shown on the triage board
Scan Reliability (Print and On-Device)
Given a generated QR image (PNG 512x512 and SVG) When displayed on a mobile device at ≥375px width or printed at 2x2 inches at 300 dpi Then default iOS and Android camera apps can scan successfully within 1 second at ~30 cm in typical indoor lighting When up to 7% module damage is introduced Then the QR remains decodable (error correction level M or higher) And a human-readable short code is present for manual entry via shortUrl if scanning fails
Real-time Queue Sync & Displays
"As a staff triage lead, I want all devices to see the same up-to-the-second queue order so that we can coordinate efficiently and avoid calling the wrong client."
Description

Maintain a real-time, multi-user synchronized queue that updates positions and statuses across the staff triage board and client mobile views. Implement WebSocket or SSE channels with fallbacks, optimistic UI updates, and conflict resolution. Show wait position, estimated wait time, and next step. Persist state to the Briefly backend with event sourcing to support recovery after network disruptions.

Acceptance Criteria
Cross-Device Real-Time Position Updates
Given a staff user moves a ticket on the triage board When the ticket is dropped into a new position or station Then all connected staff boards and the ticket owner’s mobile view reflect the new position and station within 750 ms p95 (2 s p99) And position numbers are contiguous and unique across all views (no gaps or duplicates) And the change is persisted so a page/app refresh shows the same state And a client device that was offline applies missed events upon reconnection and renders the latest state within 3 s
WebSocket/SSE Transport With Fallbacks
Given a client connects to the queue service When WebSocket is available Then the client establishes a WebSocket channel; else use SSE; else fall back to long-polling at 5 s intervals And the client sends/receives heartbeats every 15 s; missing 2 consecutive heartbeats triggers reconnect And on disconnect, the client auto-reconnects with exponential backoff (max 30 s) and jitter And upon reconnect, the client resumes from the last acknowledged event ID without losing or duplicating updates
Optimistic Drag-and-Drop With Server Reconciliation
Given a staff user drags a ticket to a new position or station When the drop occurs Then the UI updates optimistically immediately and shows a syncing indicator And if the server accepts the change, the syncing indicator clears within 500 ms of the response And if the server rejects due to conflict/validation, the UI reverts to the server-authoritative state within 1 s and shows a non-blocking toast with the resolution reason And during reconciliation no ticket disappears or duplicates on any client
Deterministic Conflict Resolution for Concurrent Moves
Given two staff users attempt to move the same ticket or reorder the same segment within a 2 s window When the server processes the events Then a deterministic rule resolves the conflict (e.g., server-authoritative last-write-wins with queue versioning) And all clients converge to the same order within 1 s of the winning event broadcast And the losing client receives a correction event including winning version and actor And the event log records both attempts with timestamps and user IDs
Accurate Wait Position, ETA, and Next Step Display
Given a client opens their ticket view When the queue changes Then the client’s position, estimated wait time (ETA), and next step are displayed and updated within 1 s And ETA uses configured inputs (throughput per station, ticket type) and is within ±2 minutes or 20% of actual wait (whichever is greater) for at least 80% of tickets measured weekly And Next Step updates immediately upon station reassignment And if ETA cannot be computed within 2 s, show “Calculating…”, and after 10 s show a fallback message without blocking other updates
Event-Sourced Persistence and State Recovery
Given queue actions occur (create, route, reorder, status change) When events are appended Then each event is immutable, uniquely identified, and ordered within the queue stream to support idempotent processing And snapshots occur at least every 200 events (configurable) And the system can rebuild the exact queue state from events (and snapshots) and passes a consistency check after backend restart/deploy And connected clients resubscribe and reconcile to the restored state within 5 s without manual intervention And an audit export includes event type, actor, timestamp, and prior/new values
QR Ticket Linking and Mobile Synchronization
Given a client scans their QR ticket When the code is validated Then their device links to the corresponding queue ticket and subscribes to real-time updates immediately And invalid or expired QR codes are rejected with no data leakage and guidance to request a new ticket And switching to a different device re-establishes the same subscription and state within 3 s of scanning And the QR link does not expose PII and is scoped to the ticket with time-bound, signed tokens
Station Routing & Step Enforcement
"As an operations manager, I want tickets to move through required stations in order so that no step is skipped and compliance is maintained."
Description

Define configurable stations (intake, review, e‑sign, print) with prerequisites, timeouts, and completion criteria. Route each ticket through the required steps, blocking advancement if prerequisites are unmet (e.g., KYC or questionnaire completion). Provide APIs and UI hooks for station check-in/checkout via QR scan, and auto-advance when digital steps complete in Briefly (e.g., e‑sign finished).

Acceptance Criteria
Create and Configure Stations with Prerequisites
Given an admin with manage-stations permission When they create stations [intake, review, e-sign, print] with prerequisites (review: questionnaireComplete && KYCVerified, e-sign: retainerReady, print: eSignCompleted) Then the configuration is saved and retrievable via GET /stations in the defined order with exact prerequisite rules And invalid configurations (circular dependencies, unknown prerequisites) are rejected with HTTP 400 and a descriptive error And configuration changes apply to new tickets while not altering in-progress tickets’ currentStation And POST/PUT configuration operations complete in ≤2s at the 95th percentile
QR Check-In/Checkout Updates Current Station
Given ticket T is eligible for intake and is not checked in When T’s QR is scanned at the intake station via UI hook or POST /tickets/{id}/check-in with station=intake Then T.currentStation becomes intake, a checkInAt timestamp is recorded, and the triage board reflects the update within 3 seconds And re-scanning the same QR within 30 seconds is idempotent (no duplicate events) And when a checkout is submitted (scan at same station or POST /tickets/{id}/check-out with station=intake) Then a checkOutAt timestamp is recorded and T becomes eligible for the next station if prerequisites are met
Block Advancement on Unmet Prerequisites
Given ticket T has questionnaireComplete=true and KYCVerified=false When a user attempts to check in T to the review station Then the action is blocked with an inline message identifying missing prerequisites (e.g., “KYC not verified”) And the API responds HTTP 409 with unmetPrerequisites=["KYCVerified"] And T remains at its previous station and no triage board position changes And an audit event advance_blocked is recorded with reason and user context
Auto-Advance on Digital Completion (E-Sign)
Given station e-sign has completionCriteria eSignCompleted=true and next station=print When the signer completes e-sign in Briefly and a completion webhook/event is received Then ticket T auto-advances to print within 5 seconds of event receipt and appears at print on the triage board And an audit event auto_advanced is recorded with source=webhook And if print prerequisites are not satisfied, the advance is blocked with HTTP 409-equivalent state and T remains at e-sign-complete with unmetPrerequisites detailed
Station Timeout and Escalation Handling
Given station review has a configured timeout of 10 minutes When ticket T is checked in to review and remains without checkout for >10 minutes Then T is marked timed_out for review, highlighted on the triage board, and a notification is sent to the configured channel And advancement from review is blocked until a staff member acknowledges and re-checks in T And a timeout event is recorded with duration and user/station context, and is visible via GET /tickets/{id}/history
API Contracts, Concurrency Control, and Audit Trail
Given public API endpoints exist for station check-in and checkout When a request lacks valid authentication Then the API responds 401 Unauthorized with no state change When a request references a non-existent ticket or station Then the API responds 404 Not Found When two concurrent check-in requests target the same ticket and station Then exactly one succeeds and the other receives 409 Conflict with conflict details And all state transitions (manual, QR, auto) produce immutable audit records including ticketId, station, action, actor/source, and timestamp And GET /tickets/{id}/history returns events in chronological order with 95th percentile latency ≤500ms; POST check-in/checkout 95th percentile latency ≤1s
Priority Rules & Vulnerable Client Flagging
"As a volunteer lead, I want to prioritize vulnerable clients with a simple action so that those with greater need are served sooner without disrupting the entire queue."
Description

Allow staff to mark vulnerable clients and apply configurable prioritization rules (e.g., elderly, disability, language access) that adjust queue position within defined fairness constraints. Enable rule-based boosts, capped fast-track lanes, and audit logs of priority changes. Support intake form flags and manual overrides with reason codes.

Acceptance Criteria
Auto-Prioritization from Intake Flags
Given a client completes intake and selects one or more vulnerability flags (Elderly 65+, Disability, Language Access) When the queue ticket is issued Then the system computes a priority score using the active ruleset and reorders the queue within 3 seconds And Then the client’s phone and the staff triage board both reflect the updated place-in-line within 3 seconds and remain consistent And Then the boost respects configured caps (max advance delta and/or % of queue length) And Then an audit entry is recorded with actor=system, flags applied, ruleset version, prior position, new position, timestamp (UTC), and correlation ID
Manual Override with Reason Codes and Enforcement
Given a staff user with Edit Priority permission selects an existing ticket When they drag-and-drop the ticket to a higher position or click Boost Then the system requires a reason code from the configured list and allows an optional note (min 5 characters) And Then the move is limited to the nearest allowed position under fairness caps; if exceeded, an error explains the cap and shows the allowed maximum And Then the change commits atomically, updates client and triage views within 3 seconds, and writes an audit record (actor=user, reason code, before/after positions, timestamp, ruleset version) And Then the user can Undo within 2 minutes; the undo also creates a linked audit record And Then concurrent edits on the same ticket display a conflict notice and the latest saved change prevails with a corresponding audit entry
Configurable Prioritization Rules Admin
Given an admin opens Priority Rules settings When they create or edit a rule with name, eligibility predicate, weight (0.0–5.0), and optional caps Then required fields are validated and numeric ranges enforced; overlapping predicates are disallowed unless an explicit rule priority is set And Then saving creates a new immutable ruleset version that activates immediately And Then all open tickets are recalculated within 10 seconds; any ticket with a changed position gets an audit entry including old/new score, old/new position, and ruleset version And Then admins can preview projected queue impact before saving and the post-save results match the preview
Capped Fast-Track Lane Capacity
Given Fast-Track is enabled with capacity set as max count N or percentage P% per station When eligible priority tickets exceed capacity Then up to capacity are placed in Fast-Track and the remainder stay in the main queue with weighted scores And Then capacity is re-evaluated in real time as tickets enter/exit so that Fast-Track is never over capacity And Then the triage board shows Fast-Track used/total and blocks manual moves into Fast-Track if full And Then entering or exiting Fast-Track generates an audit record with reason, actor, and timestamp
Fairness Constraints and Interleaving
Given fairness is configured with max advance delta M and interleave ratio 1:K (at least one non-priority served after every K priority) When priority boosts are applied Then no ticket advances more than M positions in a single action and served order respects the 1:K interleave over any rolling window of K+1 served tickets And Then estimated wait times for non-priority tickets do not increase by more than 20% due to boosts over any 10-minute window And Then attempts to exceed fairness constraints are blocked with a descriptive error and no changes are committed
Deterministic Tie-Breaking and Stable Ordering
Given two or more tickets have equal computed priority score When ordering the queue Then tickets are sorted by creation timestamp ascending, then by ticket ID ascending to break ties deterministically And Then re-running prioritization with no input changes yields the identical order And Then manual reorders that leave equal scores maintain relative stability except where explicitly changed
Comprehensive Priority Audit Log and Export
Given audit logging is enabled When any priority-affecting change occurs (intake flag, rule change, manual override, fast-track enter/exit, fairness enforcement) Then a write-once audit record is created with fields: ticket ID, actor, action type, reason code (if any), before/after score, before/after position, ruleset version, timestamp (UTC), correlation ID And Then audit records are queryable by date range, client, actor, and action type; 95th percentile queries on 10k records complete within 2 seconds And Then selected audit records can be exported to CSV within 10 seconds and the file includes a header row and UTF-8 encoding
Drag-and-Drop Triage Board
"As a staff member on triage, I want to drag and drop tickets to the appropriate station so that I can quickly manage flow without navigating multiple screens."
Description

Provide a Kanban-style board for staff to drag tickets between stations and reorder within a station, with guardrails that respect routing rules and priorities. Include search, filters, bulk actions (pause, no‑show, cancel), and quick actions (message, print token). Support keyboard and touch interactions for tablets and kiosks.

Acceptance Criteria
Drag Between Stations With Routing Guardrails
Given a ticket eligible for the target station, when a staff member drags it to that station, then the move completes in under 500 ms and the ticket adopts the target station’s required steps and SLA. Given a ticket with unmet prerequisites, when a staff member attempts to drag it to an incompatible station, then the move is blocked, the card snaps back, and a tooltip lists the specific unmet rules. Given a successful move, when it completes, then an event is emitted and all connected triage boards reflect the change within 1 second. Given a ticket with priority higher than tickets in the target station, when moved, then it auto-positions above non-priority tickets unless an authorized user confirms an override.
Reorder Within Station by Priority and Wait Time
Given tickets within a station, when a staff member drags to reorder, then the new order persists across refresh and new sessions for that board. Given a vulnerable-flagged ticket and non-vulnerable tickets, when reordering, then the vulnerable ticket cannot be placed below non-vulnerable without an explicit override confirmation by an authorized user. Given tickets of equal priority, when reordering, then wait time acts as a tiebreaker and is displayed with minute-level freshness. Given a non-priority ticket, when dropped into a Priority lane or marked Vulnerable, then it is flagged accordingly and sorted per priority rules immediately. Given concurrent reordering by another user, when a drop occurs, then conflicts resolve with last-write-wins and a toast displays the final order source.
Search and Filter Tickets
Given a search query by client name, phone, or ticket ID, when entered, then matching tickets are returned and highlighted within 300 ms for datasets up to 10,000 active tickets. Given filters for station, status (Active, Paused, No-Show, Canceled), priority, tag, and wait-time buckets, when applied in any combination, then only matching tickets display and active filter chips are visible. Given a Clear Filters action, when invoked, then all filters reset, highlighting clears, and the full board view restores within 200 ms.
Bulk Actions: Pause, No-Show, Cancel
Given multiple selected tickets, when Pause is applied with a required reason, then their status changes to Paused, wait timers stop, and they move to a Paused view with timestamp. Given multiple selected tickets, when No-Show is applied, then a required attempt count and timestamp are recorded, tickets are removed from active lanes, and next-contact time is set per configuration. Given multiple selected tickets, when Cancel is applied with a required reason, then tickets are locked from further movement without admin override and are removed from active lanes. Given any bulk action completion, when it succeeds, then an audit log entry is created per ticket and an Undo option is available for 30 seconds.
Quick Actions: Message and Print Token
Given a ticket, when Message is invoked, then a composer opens prefilled with client name and ticket ID; on send, the message is dispatched via the default channel and a timeline entry is created. Given a ticket, when Print Token is invoked, then a QR token prints to the default printer containing ticket ID, current station, and position-in-line; if the printer is unavailable, a retry option and error state are shown. Given a user without messaging or printing permission, when viewing a ticket, then the corresponding quick action is disabled with an explanatory tooltip.
Accessible Keyboard Interaction
Given focus on a ticket card, when Space is pressed to pick up and Arrow keys move between positions and lanes, then valid drop targets are announced via ARIA and visual indicators, and movement occurs without a pointer device. Given a keyboard drop via Enter, when executed, then the same validations as pointer drag-and-drop apply and either the move completes or a reasoned error is announced. Given screen reader navigation, when traversing the board, then each card exposes name, status, station, priority, and wait time; all actionable controls are reachable in tab order with visible focus. Given keyboard shortcuts, when Shift+F is pressed, then Filters opens and focus lands in the first control; when Ctrl/Cmd+K is pressed, then Search opens with focus in the input.
Touch Interaction on Tablets and Kiosks
Given a tablet or kiosk, when a user drags a ticket with touch, then the card tracks the finger smoothly, valid targets highlight in green, invalid targets in red, and the card snaps to the nearest valid lane on drop. Given touch-only usage, when a user long-presses a ticket, then multi-select mode activates and additional tickets can be tapped to select for bulk actions; bulk actions execute on release confirmation. Given touch UI constraints, when interacting with any control, then primary touch targets are at least 48x48 px and all actions are reachable without a hardware keyboard. Given a touch drop on an invalid lane, when released, then the card returns to origin and a banner states the routing rule that blocked the move.
Client Mobile Ticket View & Notifications
"As a client waiting in the clinic, I want to see my place in line and get notified when it’s my turn so that I don’t miss my step and know what to do next."
Description

Offer a mobile-friendly ticket page showing current position, next station, map/directions within the clinic, and call-to-action buttons (check-in, upload ID, complete questionnaire). Send event-driven notifications (SMS/push/email) when position changes or a station is ready, with multilingual support and accessibility compliance (WCAG AA).

Acceptance Criteria
Mobile Ticket View: Position, Next Station, and Status
Given a client with a valid ticket and assigned next station When the client opens the mobile ticket URL on a device with a 3G Fast network profile Then above-the-fold content renders in <= 1.0 second and full ticket content in <= 2.0 seconds And the page displays ticket number, current place-in-line (ordinal), estimated wait time (in minutes), next station name and icon, and a last-updated timestamp in clinic local time And a “Live” badge is shown when data freshness < 30s; otherwise a visible manual Refresh control is shown And the ticket state matches the backend queue state within <= 5 seconds of the last backend change
Real-time Position Updates Without Refresh
Given a client’s ticket is open in a mobile browser session When the client’s position or next station changes in the backend Then the visible position, estimated wait time, and next station update in the UI within <= 5 seconds without a full page reload And no UI flicker or scroll position loss occurs during the update And the change is announced via an ARIA live region for screen readers within <= 1 second And a client-side event log records the update with timestamp and new values
Event-driven Notifications: Position Change and Station Ready
Given a client has opted in to one or more channels (SMS, push, email) and a preferred language is set When the client’s position decreases by >= 1 or the next station status transitions to Ready Then a notification is sent on each opted-in channel within <= 10 seconds of the triggering event And the notification content is localized to the client’s preferred language and includes a deep link to the ticket page And notifications are rate-limited to max 1 per 2 minutes per client; multiple events in the window are collapsed into the most recent state And delivery failures are retried up to 3 times with exponential backoff; final failure is logged with error code And an audit record is stored with event type, channel, locale, template version, delivery status, and timestamps
Call-To-Action Buttons: Check-in, Upload ID, Complete Questionnaire
Given a client has an active ticket When the client is not yet checked in Then a Check-in button is visible, tappable with a minimum 44x44pt target, and upon tap updates status to Checked in within <= 2 seconds and shows a confirmation state When ID is required by the flow Then an Upload ID button accepts camera capture or file upload (PNG/JPG/PDF), enforces a per-file size limit <= 10 MB, shows progress, and confirms success or provides actionable error messaging When the questionnaire is incomplete Then a Complete Questionnaire button deep-links to the guided form; upon submission success, the ticket reflects completion within <= 5 seconds and the CTA state changes to Completed And all CTA actions are idempotent; duplicate taps do not create duplicate submissions and show consistent final state And all CTAs are disabled with a visible busy indicator during in-flight requests and re-enabled on completion or error
In-clinic Map and Directions to Next Station
Given a clinic layout is configured with stations and paths When a client opens the ticket page with an assigned next station Then the page shows a mini-map highlighting the client’s current area and the next station with a clear path And a text-only step list is provided as an accessible fallback describing the route and station name And if the next station changes, the map and steps update within <= 5 seconds And if map tiles fail to load, the text directions remain available without blocking the page
Multilingual Support and Language Switching
Given the system supports English and Spanish at minimum When a client’s preferred language is derived (profile, prior choice, or device locale) or manually switched via a language selector Then 100% of visible UI strings on the ticket page and notification templates render in the selected language with correct date/time and number formats And the language choice persists across sessions for >= 30 days or until changed And no mixed-language strings appear on the same screen; missing translations fall back to English with a telemetry event logged
Mobile Accessibility Compliance (WCAG 2.1 AA)
Given a client uses assistive technologies (screen reader, keyboard or switch access) or has vision or motor impairments When interacting with the ticket page and CTAs Then all actionable targets are >= 44x44pt with sufficient spacing And color contrast for text and essential icons is >= 4.5:1; no essential information is conveyed by color alone And all interactive elements have descriptive, programmatic labels and a visible focus indicator; focus order follows visual order And dynamic updates (position, station ready) are announced via polite ARIA live regions without stealing focus And content reflows and remains functional at 200% zoom and in portrait/landscape without horizontal scrolling for text content And errors are described inline with text and programmatic association to the offending field

Privacy Reset

Protect PII on shared devices with an automatic session wipe and privacy screen between users. A visible countdown and one‑tap reset clear forms, files, and clipboard data, lock downloads, and hide notifications until the next intake starts. Builds trust in busy public spaces and satisfies strict confidentiality practices.

Requirements

Auto Session Wipe Engine
"As an intake coordinator using a shared tablet, I want the app to automatically wipe all data after an intake or timeout so that client PII cannot be accessed by the next person."
Description

Implements a secure, automated purge of client data at session end or after configurable inactivity. Clears in-app form state, local/session storage, in-memory caches, generated document previews, temporary files, and clipboard (via Clipboard API where supported). Invalidates auth tokens, revokes ephemeral document URLs, and removes any server-side draft artifacts tied to the session. Completes within three seconds without blocking final submission, is idempotent if triggered multiple times, and emits structured audit events (timestamp, trigger, scope) for compliance. Works across mobile and desktop browsers and the native wrapper (if present), with safe fallbacks when platform APIs are unavailable.

Acceptance Criteria
Auto Wipe on Inactivity Timeout
Given an active intake session with populated form state, storage, caches, previews, temp files, clipboard (where supported), valid auth token, and ephemeral document URLs And a configured inactivity timeout T (e.g., 120 seconds) When no user interaction (keyboard, touch/pointer, scroll, focus, file upload, or user‑initiated network call) occurs for T seconds Then the wipe engine triggers with trigger='inactivity' and completes within 3000 ms And it clears in‑app form state, localStorage, sessionStorage, in‑memory caches, generated document previews, temporary files, and clipboard (where Clipboard API is supported) And it invalidates auth tokens, revokes ephemeral document URLs, and deletes server‑side draft artifacts tied to the session And an audit event is emitted containing timestamp, trigger='inactivity', and scope detailing items cleared and any items skipped And if interaction occurs before T expires, the timer resets and no wipe occurs
Auto Wipe on Session End Event
Given an active intake session has just completed or the user selects Sign Out And the final submission request has been dispatched When a session_end event is raised Then the wipe engine executes with trigger='session_end' and completes within 3000 ms And it clears in‑app form state, localStorage, sessionStorage, in‑memory caches, generated document previews, temporary files, and clipboard (where Clipboard API is supported) And it invalidates auth tokens, revokes ephemeral document URLs, and deletes server‑side draft artifacts tied to the session And an audit event is emitted containing timestamp, trigger='session_end', and scope detailing items cleared and any items skipped
Wipe Completes Within 3 Seconds and Does Not Block Final Submission
Given a final submission network request is in‑flight When a wipe is triggered by session_end during that request Then the final submission request is not cancelled or interrupted and completes successfully (HTTP 2xx if the server is available) And the wipe defers any client‑side purge step that would affect the in‑flight request until transmission completes And the wipe completes within 3000 ms from trigger to completion callback And the user does not see an error attributable to the wipe process
Idempotent Wipe on Multiple Triggers
Given multiple wipe triggers occur in close succession (e.g., inactivity timeout followed by session_end) When the wipe engine processes these triggers Then only one purge is executed and subsequent triggers perform no additional destructive actions And the post‑wipe state is identical to a single execution (no residual data locally or server‑side) And at most one audit event is emitted for the wipe, indicating the trigger that initiated the executed purge
Cross‑Platform Fallbacks When APIs Are Unavailable
Given the app runs on devices/browsers with varying API support (e.g., Clipboard API unavailable on iOS Safari, limited file APIs in WebView/native wrapper) When a wipe is executed Then supported scopes are purged as specified and the operation completes within 3000 ms without throwing runtime errors And unsupported scopes are safely skipped without failure, and the audit event's scope indicates which items were skipped with reasons And token invalidation, ephemeral URL revocation, and server‑side draft deletion succeed across mobile browsers, desktop browsers, and the native wrapper (if present)
Structured Audit Events for Wipe Operations
Given any wipe (inactivity or session_end) completes When inspecting emitted audit telemetry Then exactly one audit event exists per wipe operation And the event includes at minimum: timestamp (UTC ISO‑8601), trigger ('inactivity' or 'session_end'), and scope (items cleared and any items skipped) And the event contains no PII (no form values, filenames, document contents, names, emails, or phone numbers) And the event is transmitted to the server successfully (HTTP 2xx), even when auth tokens are invalidated as part of the wipe
Privacy Screen Overlay
"As a client in a waiting room, I want to see a privacy screen between users so that I know my information isn’t visible to others."
Description

Displays a full-screen privacy interstitial between intakes that fully obscures the application UI and any previously entered data. The screen provides clear reassurance messaging, brandable visuals, and a prominent "Start New Intake" action that initializes a fresh session. Implements a focus trap and input lock to prevent accidental navigation back to prior screens, and blocks screenshots where platform support exists (with graceful degradation on the web). Meets accessibility standards (WCAG AA), supports dark mode, and localizes copy for multilingual environments.

Acceptance Criteria
Overlay Obscures Prior Session Between Intakes
Given an intake session ends or the user selects End Intake When the privacy screen overlay is displayed Then the overlay covers 100% of the viewport on all supported devices and orientations And the underlying UI is not visible at any opacity or through animations And pointer, keyboard, and touch events do not reach underlying elements And page scroll is disabled And underlying app root has aria-hidden=true while overlay is active And attempting to select or copy underlying text is not possible And the overlay appears within 500 ms of the end-intake trigger
Start New Intake Initializes Fresh Session
Given the privacy screen is visible When the user activates the "Start New Intake" primary action Then a new session ID is generated and stored And all client-side prior intake data (in-memory state, localStorage, sessionStorage, IndexedDB under app namespace) is cleared And any pending file object URLs from the prior session are revoked And the app navigates to the first intake step within 1 second And all intake fields render empty defaults with no prior values prefilled And the prior session cannot be reached via browser/OS back navigation
Focus Trap and Input Lock on Privacy Screen
Given the privacy screen is active When the user navigates via keyboard, screen reader, or system back/gestures Then focus is trapped within the overlay controls And Tab and Shift+Tab cycle through overlay focusable elements only And ESC, system back, and swipe gestures do not reveal underlying screens And no hidden focusable elements exist behind the overlay And only permitted actions are available: Start New Intake and allowed settings (e.g., language/theme)
Screenshot and App Switcher Protection
Given the privacy screen is active on Android (native app) When the user attempts a screenshot or views Recents Then FLAG_SECURE prevents capture and no app content is visible Given the privacy screen is active on iOS (native app) When the app snapshot is shown in App Switcher or screen recording occurs Then only the overlay visuals are present in snapshots and no prior intake data is visible Given the privacy screen is active on the web When a screenshot is taken Then the captured image shows only the overlay with no underlying content
Accessibility Compliance (WCAG 2.1 AA)
Given the privacy screen is active Then all functionality is operable by keyboard (WCAG 2.1.1) And focus order is logical and visible (2.4.3, 2.4.7) And text contrast ratio is >= 4.5:1; non-text UI components >= 3:1 (1.4.3, 1.4.11) And controls expose accessible names/roles/states (4.1.2) And labels/instructions clearly identify purpose (3.3.2) And the page/region has correct language attribute (3.1.1) And tests with NVDA/JAWS/VoiceOver/TalkBack on representative devices pass
Dark Mode, Branding, and Reassurance Messaging
Given system theme is light or dark or the user toggles theme When the privacy screen displays Then colors, surfaces, and typography follow the selected theme with WCAG AA contrast And brand logo and colors are applied from configurable theme tokens without violating contrast And reassurance messaging text is present and readable in both themes And imagery/icons have dark/light variants or are tinted appropriately And theme choice persists into the new intake after Start New Intake
Localization and RTL Support
Given device/browser locale is a supported language or the user selects a language When the privacy screen displays Then all user-visible and accessibility strings are localized via i18n keys And the "Start New Intake" label and reassurance message are localized And RTL locales render mirrored layout and correct text direction And truncation/wrapping is acceptable at 320 px viewport width and with text scaling up to 200% And fallback to English occurs when a translation key is missing, with no placeholder keys shown
Visible Countdown With Cancel
"As an attorney, I want a visible countdown before auto-wipe so that active users aren’t interrupted and we avoid accidental data loss."
Description

Provides a configurable countdown (e.g., 10–30 seconds) prior to automatic session wipe, shown after intake completion or when idle is detected. Displays a progress indicator, optional subtle sound/haptic cues, and accessible announcements. Any user interaction cancels the countdown, while completion triggers the wipe engine. Admins can set different timers for completion vs. inactivity and define business-hour overrides. Countdown state persists across navigation to prevent bypassing.

Acceptance Criteria
Completion-Triggered Countdown Timing and Display
Given an intake session transitions to Completed And the organization has completionCountdownSeconds set within [10,30] When the countdown is presented Then the visible label shows remaining seconds updating at 1 Hz And a proportional progress indicator is displayed And an ARIA live polite announcement states the remaining time at start And if sound/haptics are enabled, play a subtle cue at start and once per second for the final 3 seconds, respecting device mute/silent and capability
Idle-Triggered Countdown Uses Inactivity Timer
Given no user interaction for the configured idleThreshold and there are no blocking dialogs And the organization has inactivityCountdownSeconds set within [10,30] When idle is detected Then the countdown begins within 1 second And duration equals inactivityCountdownSeconds And display, announcements, and cue behaviors match the completion countdown
Any User Interaction Cancels Countdown
Given the countdown is visible When the user performs any in-app interaction (pointer tap/click, key press including Tab/Escape/Enter, scroll, focus change, or form input) Then the countdown stops within 150 ms And the wipe engine is not invoked And the UI returns to its prior state And a non-intrusive toast "Countdown canceled" is shown for 2 seconds And an audit event "privacy_countdown_canceled" is recorded with {source:(completion|idle), reason:"interaction"}
Countdown Completion Invokes Wipe Engine
Given the countdown is visible And no interaction occurs until it reaches 0 When the timer reaches 0 Then the wipe engine is invoked within 250 ms with {source:(completion|idle), seconds:configured} And the countdown overlay is dismissed And a banner "Resetting session…" displays until wipe completion And an audit event "privacy_countdown_completed" is recorded
Business-Hour Overrides Apply by Org Timezone
Given business-hour override windows are configured with an organization timezone When the current local time falls within an override window Then the countdown uses the override durations for completion and inactivity And outside the window, default durations apply And DST transitions honor the intended local hours And invalid/missing overrides fall back to defaults and emit an admin-visible warning
Countdown State Persists Across Navigation
Given the countdown has started When the user navigates within the app, opens a modal, or uses browser back/forward Or reloads the page in the same tab Then the countdown continues with correct remaining time (±200 ms) and cannot be bypassed by navigation And only qualifying interactions cancel it And opening a new tab does not inherit another tab's countdown state
Accessibility and Keyboard Support
Given the countdown is shown Then initial focus moves to the countdown container and focus is trapped within it And a visible Continue action and Escape key both cancel the countdown And all controls are keyboard-accessible and have accessible names And text/progress contrast meets WCAG AA And ARIA live announcements occur at start and at 3, 2, and 1 seconds remaining And prefers-reduced-motion disables animations; prefers-contrast is respected
One-Tap Manual Privacy Reset
"As staff, I want a one-tap reset button so that I can instantly clear the device when handing it to the next client."
Description

Adds a prominent, always-available control to immediately trigger a privacy reset. Supports single tap with confirm or configurable long-press to avoid accidental activation. Works offline and online, ensures pending writes are safely handled or discarded per policy, then invokes the wipe engine. The control is keyboard-accessible, screen-reader labeled, and available from any screen, including document preview. After reset, the user lands on the privacy screen overlay.

Acceptance Criteria
Global Availability and Accessibility
Given the application is on any screen, including Document Preview When the UI renders Then a prominent "Privacy Reset" control is visible and enabled And the control is reachable via keyboard focus order without requiring a pointer And it is operable via Enter and Space keys And it exposes the accessible name "Privacy Reset" with ARIA role "button" to screen readers
Confirm vs Long‑Press Activation
Given Activation Mode = Confirm When the user single-taps/clicks the Privacy Reset control or invokes it via keyboard/screen reader Then a blocking confirmation modal appears with primary action "Reset now" and secondary action "Cancel" And selecting "Reset now" initiates the privacy reset And selecting "Cancel" closes the modal with no changes Given Activation Mode = Long‑Press with configured duration D When the user presses and holds the control continuously for >= D Then the privacy reset initiates without an additional dialog And a hold shorter than D or loss of focus does not initiate reset
Pending Writes: Commit Policy (Online/Offline)
Given Pending Writes Policy = Commit and network connectivity is available When the reset is confirmed Then the app attempts to complete all pending writes before wiping And after completion or reaching the configured timeout, the wipe engine is invoked And writes that fail are marked as failed without exposing PII in the UI Given Pending Writes Policy = Commit and network connectivity is unavailable When the reset is confirmed Then pending writes are securely queued for background retry per policy And the wipe engine is invoked immediately thereafter
Pending Writes: Discard Policy
Given Pending Writes Policy = Discard When the reset is confirmed Then all pending writes and unsaved drafts are securely canceled and deleted prior to wiping And no network requests are made before the wipe engine is invoked
Wipe Scope and Effects
Given a manual privacy reset has been initiated When the wipe engine runs Then all in‑app form fields and session state are cleared And cached files and temporary exports created by the app are deleted And clipboard contents populated by the app are cleared And downloads are locked/disabled and in‑app notifications are hidden until the next intake starts And no residual PII is visible in recent views, previews, or thumbnails within the app
Post‑Reset Privacy Overlay
Given the wipe completes When the user returns to the app UI Then the user is shown the privacy screen overlay And underlying content is fully obscured and non‑interactive And back navigation does not restore pre‑reset screens or data And starting a new intake/session is the only available forward action
Resilience and Atomicity
Given any error occurs during reset or wipe When the process completes or aborts Then no partial state containing PII remains accessible And the UI ends in the privacy screen overlay state And the user sees a generic, non‑PII error notice if applicable, without revealing any sensitive details
Download and Export Lock
"As a compliance officer, I want downloads and exports locked in shared mode so that documents cannot be saved to the device or leaked."
Description

When Privacy Reset mode is active, disables downloads, printing, and file exports for generated documents and images. Renders documents in a viewer without native download UI, applies headers to discourage caching, watermarks previews with session ID and timestamp, and blocks print hotkeys/context menu where feasible. Revokes any share links after a short TTL and requires authenticated revalidation for access. Provides an admin override with audit logging. Communicates platform limitations (e.g., screenshots cannot be fully prevented on web) to set correct expectations.

Acceptance Criteria
Disable Downloads/Printing/Exports in Privacy Reset
Given Privacy Reset mode is active And a user opens a generated document or image in the in-app viewer When the viewer renders on Chrome, Edge, Safari, and Firefox (latest two versions) Then the viewer displays no native download, export, or print controls And pressing Ctrl+P/Cmd+P is intercepted and a modal states "Printing is disabled in Privacy Reset" And right-click context menu "Save image as…" and "Print…" entries are disabled where supported And attempting File > Print in the browser opens the same "Printing is disabled" modal on supported browsers And the document cannot be saved via the viewer UI
Anti-Caching and Inline Rendering Headers
Given Privacy Reset mode is active And a generated document is requested by the viewer When inspecting the network response Then Cache-Control is "no-store, no-cache, must-revalidate" And Pragma is "no-cache" And Expires is "0" And Content-Disposition is "inline; filename=\"document.pdf\"" And X-Content-Type-Options is "nosniff" And the response is not stored in memory or disk cache as reported by browser devtools And reloading the viewer results in a fresh network request (no 304)
Watermarked Previews with Session Metadata
Given Privacy Reset mode is active And a user opens a multi-page document preview When the document is displayed at 100%, 150%, and 200% zoom Then a diagonal watermark overlay appears on every page with the text "Session <SESSION_ID> • <UTC_TIMESTAMP>" And the watermark remains visible during zooming and scrolling And if a print dialog is forced open, the print preview still shows the watermark And removing client-side CSS does not remove the watermark because it is rendered in the page imagery/canvas
Short-Lived Share Links with Revalidation
Given Privacy Reset mode is active And an existing share link to a generated document exists When an unauthenticated user opens the link within 10 minutes of issuance Then the user is prompted to authenticate before access is granted When the link is opened after 10 minutes from issuance Then the API returns 410 Gone And the page displays "This link has expired" And any subsequent access requires fresh authentication and a newly issued link And a revocation event is recorded with timestamp and link ID
Admin Override With Timebox and Audit
Given a user with Admin role is viewing a document in Privacy Reset mode When the admin enables the "Download/Print Override" and provides a reason Then MFA is required if not satisfied within the last 12 hours And downloads and printing are enabled only for that session and resource for a maximum of 15 minutes And the override auto-expires after 15 minutes or when Privacy Reset ends, whichever comes first And an audit record is created capturing admin ID, timestamp, IP, reason, resource ID, and duration And the audit record is visible in the Admin > Audit Log within 1 minute
User Messaging on Platform Limitations
Given Privacy Reset mode is active and a document is open When the viewer loads Then a non-blocking banner is shown stating "Downloads and printing are disabled. Screenshots cannot be fully prevented on the web." And the banner is accessible via screen readers with aria-live polite And the banner can be dismissed and later reopened from an "Info" icon And the message is localized for en and es locales
Mobile and Kiosk Behavior
Given Privacy Reset mode is active on Android Chrome and iOS Safari When a user long-presses on an image or document page Then "Save image" and "Share" options are suppressed where supported And tapping the browser share button triggers a message "Sharing disabled in Privacy Reset" And attempting to print from the iOS share sheet is blocked with the same message And the watermark is visible on all pages at common mobile zoom levels
Notification Redaction and Quiet Mode
"As an attorney, I want notifications redacted while in public so that sensitive details don’t show on screen."
Description

Suppresses or redacts in-app notifications and push messages that could expose PII while in shared mode or between intakes. Replaces sensitive content with generic placeholders, queues actionable alerts until a private session resumes, and disables browser push permissions in shared mode. For native wrappers, hides notification previews on the lock screen. Includes per-event redaction rules and a visible quiet-mode indicator.

Acceptance Criteria
Quiet Mode On in Shared Mode and Between-Intake Countdown
Given Shared Mode is enabled or the Between-Intake countdown screen is active, When any in-app notification is triggered, Then no notification banners, toasts, badges, or sounds are emitted. Given Shared Mode is enabled or the Between-Intake countdown screen is active, When the in-app notification center is opened, Then each item shows the generic title "Hidden in Quiet Mode" with no body/preview text, avatar, or attachment thumbnail. Given Shared Mode is enabled or the Between-Intake countdown screen is active, When a push message arrives, Then the app suppresses the foreground banner and prevents message content from being displayed anywhere in the UI. Given Shared Mode is enabled or the Between-Intake countdown screen is active, Then suppression applies to 100% of notification events generated during this period.
Per-Event Redaction Rules Enforcement
Given a notification payload containing PII fields (client_name, email, phone, address, case_id), When rendered while Quiet Mode is active, Then the following redactions apply: client_name -> "[Client]", email -> "[Redacted Email]", phone -> "XXX-XXX-####", address -> "[Address Hidden]", case_id -> "****{last4}". Given a notification payload without PII fields, When rendered while Quiet Mode is active, Then the event type label remains visible and all body text is replaced with "[Hidden]". Given a notification type with a specific redaction configuration, When the event is processed, Then the configured rule is applied; if no rule matches, Then the default behavior is full suppression with no preview. Given redaction is applied, Then no original PII values are present in the DOM, accessibility tree, logs, analytics, or network responses used to render the notification.
Actionable Alert Queueing and Release on Private Resume
Given Quiet Mode is active, When an actionable alert (signature_completed, payment_failed, efile_status, task_assigned) arrives, Then it is added to a durable queue with event_id, event_type, created_at, and payload_hash, and it is not displayed to the user. Given Quiet Mode is active, Then the queue reliably persists across app reloads and device restarts and retains at least 500 alerts without loss. Given Quiet Mode turns Off and a private session resumes, When queued alerts are released, Then they are delivered in chronological order within 5 seconds, include original timestamps, and no duplicate deliveries occur. Given network connectivity is lost and restored during Quiet Mode, Then queued alerts remain intact and are delivered after Quiet Mode ends.
Browser Push Permissions Disabled in Shared Mode
Given the app runs in a browser context, When Quiet Mode is activated, Then calls to Notification.requestPermission are blocked or return "denied" without prompting the user. Given an existing web push subscription, When Quiet Mode is activated, Then Service Worker push events do not display any notifications and no banner or toast is shown to the user. Given Quiet Mode ends, Then the prior push permission state remains unchanged (no automatic opt-in), and push notifications behave according to the user's existing browser/OS settings.
Native Lock Screen Preview Redaction
Given iOS or Android native wrapper usage, When a push notification arrives while the device is locked and Quiet Mode is active, Then the lock-screen shows only the app name and the placeholder "Hidden for privacy" with no title/body content, media, or actions. Given Quiet Mode is active, Then no long-press, expanded view, or accessibility inspection reveals hidden content on the lock screen. Given Quiet Mode ends, Then lock-screen previews follow the user's OS preview settings without retaining placeholder content.
Quiet Mode Indicator Accessibility and State
Given Quiet Mode turns On, Then a visible indicator labeled "Quiet Mode" appears within 500 ms, persists while On, and disappears within 500 ms after Quiet Mode turns Off. Given the indicator is visible, Then it is keyboard focusable, has an aria-label "Quiet Mode active: notifications hidden", announces state changes via an aria-live region, and meets WCAG 2.1 AA contrast (>= 4.5:1). Given the user activates the indicator, Then a non-PII tooltip appears stating "Notifications hidden; alerts will queue" and can be dismissed via ESC or tapping outside.
Redaction Rule Configuration and Audit Logging
Given an admin updates the redaction rule for event_type = message_received to mask client_name and subject, When a new event arrives, Then the new rule is applied within 60 seconds without requiring an app restart. Given any notification is redacted or suppressed, Then an audit log entry is written containing event_id, event_type, timestamp, action (redacted|suppressed), and rule_id, and the entry contains no PII. Given a redaction rule evaluation error occurs, Then the notification is fully suppressed, an error is logged with rule_id and a PII-free stack trace, and a monitoring alert is emitted.
Admin Configuration and Audit Trail
"As an admin, I want to configure privacy reset parameters and see an audit trail so that we can meet confidentiality policies and prove compliance."
Description

Provides workspace-level settings to configure inactivity thresholds, countdown durations, wipe scope (storage, clipboard, tokens, server drafts), notification redaction, and download lock behavior. Captures an immutable audit trail for every reset event, including actor (user or system), trigger source, device fingerprint, IP, and outcomes. Supports CSV export, retention policies, and webhook delivery to compliance systems. Includes test utilities to simulate sessions and validate wipes for SOC 2/ABA confidentiality controls.

Acceptance Criteria
Workspace Inactivity Threshold and Countdown Configuration
Given a workspace admin opens Privacy Reset settings When they set inactivity threshold to 5 minutes and countdown to 20 seconds and save Then new sessions started after save enforce a 5-minute inactivity timer and a visible 20-second countdown on idle detection And settings are validated: threshold must be 1–30 minutes (integer), countdown 5–60 seconds (integer); invalid entries are blocked with inline errors And changes are applied within 60 seconds to new sessions and do not change timers already in countdown And the configuration change event is recorded in the audit log with admin ID, previous values, new values, timestamp, IP, and device fingerprint
Configurable Wipe Scope Enforcement
Given the admin selects wipe scope to include local storage, session storage, cached files, clipboard, access tokens, and ephemeral server drafts When a privacy reset is triggered by inactivity or manual one‑tap Then the client clears browser localStorage, sessionStorage, IndexedDB, and in‑app caches for the workspace origin And the device clipboard is overwritten with an empty value And access/refresh tokens for the workspace are revoked and removed from device storage And server‑side ephemeral drafts created in the session are securely deleted and no longer retrievable via API And a post‑wipe verification returns success indicators per asset type; any failure marks the outcome as partial‑wipe with details in audit trail
Notification Redaction and Download Lock Behavior
Given "Redact notifications" and "Lock downloads between users" are enabled When the session enters privacy screen state (countdown active or after reset) Then all in‑app notifications are suppressed and OS/web push notifications display sender as "Hidden" with no message body And file downloads initiated from the app are blocked with a user‑facing banner explaining download lock And disabling either setting re‑enables the respective behavior in the next session state transition And each blocked download attempt is logged with timestamp, user/session ID (if any), and device fingerprint
Immutable Audit Trail for Reset Events
Given any privacy reset event occurs (inactivity, manual tap, admin remote) When the event is recorded Then the audit record includes: event ID, workspace ID, actor (user/system), trigger source, device fingerprint, IP address, wipe scope applied, per‑asset outcome (success/fail), and timestamps (start, end) And the record is write‑once, append‑only, with content hashed and chained (prev_hash) to ensure tamper evidence And attempts to modify or delete individual audit records are rejected and logged as security events And audit timestamps are in ISO 8601 UTC with clock drift not exceeding ±2 seconds against server NTP
CSV Export and Retention Policy Enforcement
Given an admin selects a date range, filters (workspace, device, actor, trigger), and clicks Export CSV When the export job completes Then the downloaded CSV contains a header row and one row per event with the defined audit fields, using ISO 8601 UTC timestamps and comma separators, escaped per RFC 4180 And exports over 50,000 rows are delivered as a streamed download or multipart archive without timeouts And when a retention policy of 90 days is enabled Then audit records older than 90 days are purged daily at 02:00 UTC unless under legal hold And legal hold tags prevent purge until removed, with all holds and purges logged
Webhook Delivery to Compliance Systems
Given a webhook endpoint, secret, and retry policy are configured and verified via a test ping When a reset event is generated Then a JSON payload is POSTed within 5 seconds including the audit fields and an HMAC‑SHA256 signature in the Authorization header And 2xx responses mark the delivery as success; 4xx/5xx responses trigger exponential backoff retries for up to 24 hours And undelivered events after retry window are placed in a dead‑letter queue visible to admins with re‑drive controls And webhook delivery failures never block local audit persistence
Test Utilities for SOC 2/ABA Validation
Given an admin opens Test Utilities and selects a simulated session with specified settings (threshold, countdown, wipe scope) When they run the simulation for inactivity and manual reset paths Then the tool produces a downloadable report summarizing steps, timestamps, wipe verification per asset, and pass/fail results mapped to SOC 2 CC6.1/CC6.6 and ABA confidentiality controls And simulations run in an isolated sandbox that cannot access production data or tokens And failures provide reproducible steps and attach relevant audit event IDs

Batch Pack Print

Generate collated, barcoded print packets (retainer, disclosures, fee waivers, checklists) in one click for everyone currently queued. Group by matter or household, track what’s printed, and scan barcodes to auto‑file signed pages back to the right case. Cuts printer trips, prevents mix‑ups, and accelerates sign‑and‑go.

Requirements

One-Click Batch Packet Generation
"As an intake assistant, I want to generate all queued clients’ collated packets with one click so that I can minimize printer trips and prepare sign-and-go documents efficiently."
Description

Provide a single action to generate collated, print-ready packets for all matters or households currently in the Print Queue. Dynamically assemble the correct document set per matter type (retainer, disclosures, fee waivers, checklists) using the latest validated intake data from Briefly, enforce canonical document order, paginate, and produce a consolidated PDF per packet with a barcoded cover sheet. Support eligibility filters (e.g., Awaiting wet signature, Queued today), progress indicators, retry on transient failures, and an audit entry for each job. Expose both a UI button and an API endpoint for automation and integrate with existing template and data-merging services.

Acceptance Criteria
UI One-Click Batch Generation for Queued Matters
Given I am an authorized user with access to the Print Queue And the queue contains at least one item with validated intake data And required templates for each included matter type are active When I click "Generate Batch Packets" Then the system assembles the correct document set per matter type in the canonical order And merges the latest validated intake data snapshot taken at job start And paginates each packet with continuous page numbers and a "Page X of Y" footer And prepends a unique barcoded cover sheet containing group identifier(s) and a job ID And produces one consolidated PDF per packet And names each file using "<Group>-<Id>-<YYYYMMDD-HHMM>-<JobId>.pdf" And packets missing templates or required data are marked Failed without blocking others And a queue of up to 100 packets completes generation within 5 minutes under normal load
Group Packets by Household or Matter
Given the Print Queue contains matters across multiple households And I select the grouping mode When I choose "Group by Household" and generate Then one consolidated PDF packet is produced per household including all applicable documents for included matters And the packet order is canonical first by matter type, then by matter within the household And the cover sheet barcode encodes the household ID and included matter IDs And switching to "Group by Matter" produces one packet per matter with the correct document set and cover sheet encoding the matter ID And no duplicate documents appear across packets for the same group selection
Eligibility Filters Applied to Batch
Given the filters "Awaiting wet signature" and/or "Queued today" are available And matters in the queue both match and do not match these filters When I apply selected filters and generate Then only items matching all selected filters are included in the job And a pre-run summary displays counts for Included and Excluded by filter And the job detail lists each excluded item with the specific filter reason And changing filters changes the Included count accordingly before generation
Progress Indicators and Job Lifecycle
Given a batch generation job is initiated When I view the Batch Jobs panel Then I see a live progress indicator showing percent complete, packets completed/total, and estimated time remaining And job status transitions are reflected as Pending -> Running -> Completed, Completed with Errors, or Failed And each packet shows a status of Queued, Generating, Succeeded, or Failed with an error reason And upon completion, a single action is available to download all generated packets as a ZIP and to download the job log
Automatic Retry on Transient Failures
Given a transient error occurs during template rendering or data-merge (e.g., HTTP 5xx, timeout) When the job encounters the error Then the system retries the failed step up to 3 times with exponential backoff (1s, 2s, 4s) And if a retry succeeds, the packet is marked Succeeded and processing continues And if all retries fail, the packet is marked Failed with error type Transient and the job status is Completed with Errors And retry attempts and outcomes are recorded in the job log with timestamps And non-transient errors (e.g., missing template) are not retried and are classified accordingly
Audit Logging for Batch Jobs
Given a batch job is initiated via UI or API When the job completes in any terminal state Then an immutable audit entry is recorded with initiator (user ID or client ID), timestamp, source (UI/API), selected grouping, selected filters, counts (queued/included/succeeded/failed), duration, job ID, and file checksums for outputs And the audit entry is viewable in the Audit Log and searchable by job ID, initiator, date range, and status And audit entries cannot be edited or deleted by end users
API Endpoint for Batch Packet Generation
Given I have a valid API token with scope "batch_print:generate" When I POST to /api/v1/batch-print/jobs with an idempotency key, grouping mode, and optional filters Then the API responds 202 Accepted with a job ID and a status URL And duplicate requests with the same idempotency key within 24 hours return the original job and do not create a new job And invalid inputs yield 400 with machine-readable error details And unauthorized requests yield 401/403 as appropriate And generated packets and ordering match the UI for the same inputs
Matter/Household Grouping Controls
"As a case manager, I want to group print packets by household when clients are related so that shared documents print together and I avoid cross-file mix-ups."
Description

Enable configurable grouping of packets by individual matter or by household, with default rules based on shared address and relationship data captured during intake. Deduplicate shared documents within a household where appropriate, preserve per-matter documents when required, and allow manual overrides before printing. Persist grouping choices, show packet counts per group, and reflect grouping metadata in tracking and audit logs to prevent mix-ups within multi-client households.

Acceptance Criteria
Default Household Grouping by Shared Address and Relationship
Given matters A and B are queued with identical normalized postal address and an intake relationship indicating the same household And matter C is queued with a different address or no qualifying household relationship to A/B When the Batch Pack Print screen loads Then A and B appear under a single Household group with a unique Group ID And C appears as its own Matter group And the default Grouping control displays "Household" for the batch
Deduplication of Household-Shared vs Per-Matter Documents
Given a Household group with members A and B And document templates include items flagged household_shared and per_matter When the packet preview is generated Then exactly one copy of each household_shared document is included for the Household group And exactly one copy of each per_matter document is included for each member (A and B) And barcodes encode group_id for household_shared documents and matter_id for per_matter documents to ensure correct auto-filing
Manual Override of Grouping Before Print
Given default groups have been auto-created based on address and relationship When the user selects "Split from Household" on member A Then A is removed from the Household group and appears as its own Matter group And packet composition and counts update immediately to reflect the change And the affected groups display an "Override" indicator When the user selects two Matter groups and clicks "Merge to Household" Then the selected matters appear under one Household group with a new Group ID
Persistence of Grouping Choices Until Print or Reset
Given the user has applied grouping overrides to one or more groups When the user refreshes the page or signs out and back in Then the same grouping configuration is restored for the queued matters And the persisted configuration is visible to all users in the workspace And the configuration remains until all affected matters are printed or a user clicks "Reset Grouping"
Packet Counts Reflect Grouping and Deduplication
Given a Household group with two members and a set of household_shared and per_matter documents When packet counts are displayed in the Grouping panel Then the Household group shows 1 packet to print And each standalone Matter group shows 1 packet to print And the batch total equals the sum of all group packet counts And counts update within 1 second of any grouping change
Grouping Metadata Recorded in Tracking and Audit Logs
Given the user initiates a print job for the queued items When the job is created Then the print job record stores group_type (Household/Matter), group_id, member matter_ids, override_applied (true/false), actor_user_id, and timestamp And each document record stores its scope (household_shared/per_matter), associated group_id and/or matter_id, and barcode value And audit logs are queryable by group_id and matter_id to trace any printed or scanned page
Recalculation and Review on Intake Data Change
Given grouping overrides are persisted for a set of matters When the address or relationship data changes for any member prior to printing Then the system recalculates default grouping for the affected matters And flags the affected groups as Needs Review And disables printing for those groups until a user confirms or updates the grouping And all changes are logged with before/after values in the audit trail
Unique Packet and Page Barcoding
"As a solo attorney, I want every printed page to carry a unique, scan-ready barcode so that signed pages can be auto-filed back to the correct case without manual sorting."
Description

Embed machine-readable barcodes on each packet cover and each page to enable reliable post-signature routing. Encode environment, organization, matter ID, document type, packet ID, and page sequence with versioning and HMAC signing to prevent tampering. Use a robust symbology (Code 128 or QR) positioned in safe margins, optimized for 300 dpi monochrome printers and common MFP scanners. Store a mapping of all issued barcodes to documents and pages to support reprints and ingestion edge cases.

Acceptance Criteria
Cover Barcode Payload and Uniqueness
Given a batch print is generated for queued matters When a packet cover page is rendered Then the barcode on the cover shall encode: environment, organization ID, matter ID, packet ID, packet version, document type="packet_cover", and an HMAC signature over the canonical payload And the decoded values shall exactly match the packet metadata stored server-side And the tuple (environment, organization ID, packet ID, packet version) shall be globally unique across the system with zero collisions in the mapping store And decoding the cover barcode from a 300 dpi monochrome print-scan roundtrip shall succeed within 200 ms with ≥99.5% success over a 1,000-page test set
Per-Page Barcode Sequencing and Content
Given a packet contains one or more documents comprised of multiple pages When each page is rendered for print Then each page shall include a machine-readable barcode encoding: environment, organization ID, matter ID, packet ID, packet version, document type, page sequence number (starting at 1 and incrementing by 1 across the entire packet) And no two pages in the same packet version shall share the same (packet ID, packet version, page sequence) tuple And decoding any page barcode shall return values that match the server-side mapping for that page with zero mismatches in a 1,000-page test set
HMAC Signature Verification and Tamper Detection
Given the canonical payload fields are defined (environment, organization ID, matter ID, packet ID, packet version, document type, page sequence) When a barcode is generated Then an HMAC signature using the configured secret and algorithm shall be computed over the canonical payload and embedded And when any payload field or pixel-level barcode data is altered post-generation Then server-side verification shall fail and the page shall be quarantined from auto-filing with an audit log entry including reason="HMAC_INVALID" And when the payload and signature are unmodified, verification shall pass with 0 false negatives over 10,000 verifications and ≤0.1% false positives
Print/Scan Robustness at 300 dpi Monochrome
Given barcodes are printed on common 300 dpi monochrome laser printers and scanned by MFPs at 200–600 dpi with up to 10° skew and 20% salt-and-pepper noise When the ingestion service attempts to decode the barcode Then the selected symbology (Code 128 or QR) shall be decodable with a success rate ≥99.5% across a 1,000-page randomized test corpus And average decode time per page shall be ≤200 ms on the target ingestion hardware profile And for payloads exceeding Code 128 capacity at required module width, QR shall be automatically selected and remain decodable under the same conditions
Safe Margin Placement and Content Preservation
Given documents include headers, footers, and variable content When barcodes are positioned on the cover and each page Then barcodes shall be placed within designated safe margins with a minimum 6 mm quiet zone on all sides and no overlap with document content, headers, or footers And content reflow shall not exceed ±2% scaling or cause line wraps compared to the non-barcode rendition And placement shall respect duplex printing (front/back) without clipping, verified across letter and A4 sizes with 0 placement violations in 200 sample documents
Barcode Mapping, Reprints, and Versioning
Given a packet is generated When barcodes are issued Then a mapping record shall be persisted for every packet cover and page containing: environment, organization ID, matter ID, packet ID, packet version, document type, page sequence, symbology, generation timestamp, and HMAC And when a packet is reprinted without content changes, the packet version shall remain unchanged and barcodes shall be bit-for-bit identical to the original, confirmed by checksum match And when any document content changes, the packet version shall increment and new barcodes shall be generated; ingestion shall reject mixing pages across versions with reason="VERSION_MISMATCH" And mapping shall support lookup by any of (HMAC, packet ID+version+page sequence) with p95 lookup latency ≤50 ms
Post-Signature Ingestion and Auto-Filing
Given signed pages from multiple packets are scanned in arbitrary order into a single PDF When the ingestion service processes the file Then each page shall be routed to the correct environment, organization, matter, document type, and page position based on the decoded barcode And duplicate pages (same packet ID+version+page sequence) shall be detected and flagged without overwriting previously filed pages unless explicitly allowed by policy And pages with invalid or undecodable barcodes shall be quarantined with actionable error codes and linked back to the originating print job via the mapping store And end-to-end routing accuracy shall be ≥99.9% over a 1,000-page mixed-packet test set
Print Tracking and Reprint Controls
"As an office administrator, I want clear tracking and targeted reprint options so that I can quickly resolve printer issues and maintain an accurate audit trail."
Description

Track the lifecycle of each print job and packet, including who printed, when, packet composition, page counts, printer profile, and outcome. Mark statuses such as Queued, Printing, Printed, Partially Printed, Void, and Reprinted. Provide a dashboard to view history, filter by status, and trigger targeted reprints for specific packets or sections. Generate alerts for failed or partial jobs and ensure idempotent reprint behavior that updates audit trails without duplicating records.

Acceptance Criteria
Audit Log for Print Jobs and Packets
Given a user initiates Batch Pack Print for queued recipients When the system creates a print job and packets are generated Then a unique printJobId is created and a unique packetId is assigned per recipient And the audit record stores userId, userName, timestampStart, timestampEnd, matterId or householdId, printerProfileId and name, machine/queue, packetComposition (document names and templateVersionIds), pageCounts per document, and totalPages And the outcome field is initialized to Queued and updated as status changes And all changes are appended as immutable events (no in-place edits) And the job and packet audit entries are visible in the dashboard detail view
Status Lifecycle and Transitions
Given a print job is created Then the initial status is Queued with createdAt captured When the printer accepts the job Then the status updates to Printing with printingAt captured When all pages successfully print Then the status updates to Printed with printedAt captured When only some pages print Then the status updates to Partially Printed with missingPages recorded When a user cancels before completion Then the status updates to Void with cancelReason required When any reprint occurs Then a Reprinted event is appended referencing parentJobId while original job/packets retain their terminal status And all transitions are timestamped and preserved in the audit trail
Dashboard History, Filtering, and Drill-down
Given a user opens the Print History dashboard Then the grid lists jobs with columns: Job ID, Created At, User, Matter/Household, Printer Profile, Status, Packet Count, Total Pages, Outcome And results paginate at 50 rows per page When the user filters by Status (multi-select), Date Range, User, Matter/Household, or Printer Profile Then results update within 200 ms on datasets of 10,000 rows or fewer And clearing filters restores the full list When the user selects a row Then a detail view shows packet-level breakdown (documents, page counts, status timeline) and available actions based on role
Targeted Reprints for Packets or Sections
Given a user views a job detail with one or more packets When the user selects specific packets or sections (e.g., retainer, disclosures) and confirms Reprint Then a new print job is created with parentJobId referencing the original and scope limited to the selection And the user must enter a reprintReason before confirmation And reprintCount on affected packets increments by 1 And the original packet records are not duplicated; a Reprinted event is appended to their audit trail And default behavior uses the original document versions and barcodes unless the user selects "Use latest templates" And the new job starts in Queued status and appears on the dashboard
Alerts for Failed or Partial Prints
Given a print job is in Printing status When a printer error is returned or the job exceeds a 5-minute timeout without completion Then the job outcome is set to Partially Printed or Void based on pages confirmed printed And an in-app alert is generated within 5 seconds containing jobId, impacted packets, error code/message, and a Reprint Missing Pages action And, if email alerts are enabled for the user, an email is sent with the same payload When the user clicks the alert action Then the system opens the job detail with the missing sections preselected for reprint
Idempotent Reprints and Duplicate Submission Protection
Given a client supplies an idempotencyKey when requesting a reprint for the same job, packetIds, and sections When the same request is submitted multiple times within 60 seconds due to retries or double-clicks Then only one new print job is created and subsequent identical requests return the existing reprintJobId And the audit trail records a single Reprinted event and IgnoredDuplicate events for suppressed duplicates And only one physical print command is sent; printed page counts reflect a single issuance
Scan-to-File Auto Ingestion
"As a legal assistant, I want to scan signed packets and have them automatically filed to the right cases so that I eliminate manual sorting and reduce filing errors."
Description

Ingest scanned documents from monitored sources (email inbox, network folder, or scanner upload), decode barcodes, and auto-route pages to the correct matter and document records in Briefly. Support out-of-order pages, duplicate scans, partial packets, and mixed-packet scans by reconstructing documents using packet/page sequences and checksum validation. Queue exceptions to a review screen with suggested resolutions, allow human correction, and finalize filing with standardized naming, versioning, and comprehensive audit logging.

Acceptance Criteria
Ingest and Auto-Route from Monitored Email Inbox
Given a monitored inbox receives an email with one or more PDF or TIFF attachments generated by Batch Pack Print And attachments contain valid Briefly barcodes encoding MatterID, PacketID, DocType, PageSeq, TotalPages, and PageChecksum When the ingestion job polls the inbox Then the attachments are downloaded, virus scanned, and processed within 30 seconds And barcodes are decoded with >= 99.5% success rate on 200+ DPI scans And documents are split and routed to the correct matter and document records per DocType And the source email is moved to a "Processed" folder with the Briefly Ingestion ID appended to the subject And reprocessing the same email or attachment does not create duplicate documents (idempotent via content hash) And an audit log entry records source=email, Message-ID, attachment hash, decoded barcode payload, ingestion timestamps, and outcome=Filed
Ingest from Network Folder and Scanner Upload
Given a watched network folder and a scanner upload endpoint are configured When a file is placed in the folder or uploaded via the scanner endpoint Then ingestion begins within 15 seconds of file arrival And the file is virus scanned, barcodes decoded, and documents are auto-routed to the correct matter and DocType And the original file is moved to a Processed directory on success or a Failed directory on unrecoverable error And reintroducing the same file (identical checksum) does not create duplicates and is logged as deduplicated And an audit log entry records source path or uploader identifier, file hash, timestamps, and outcome
Reconstruct Out-of-Order Pages and Eliminate Duplicates
Given a scan of a single packet with pages saved out of order and with accidental duplicate pages When ingestion decodes PageSeq, TotalPages, and PageChecksum Then the document is reassembled in ascending PageSeq order And any page whose checksum matches a previously seen page in the same document is excluded from filing and logged as duplicate And if two different pages share the same PageSeq, the highest-quality image (resolution >= 300 DPI) is kept and others are discarded as duplicates with reason recorded And the final assembled document page count equals TotalPages; otherwise the scan is routed to the exception queue with reason=MissingPages
Split Mixed-Packet Scan Across Multiple Matters
Given a single PDF contains pages for multiple packets and matters (distinct PacketIDs or MatterIDs) When ingestion runs Then the file is split into subdocuments by PacketID and MatterID boundaries And each subdocument is filed to the correct matter and DocType with no page leakage across matters And cross-matter separation accuracy is 100% in test cases containing at least 3 matters and 25+ pages And a consolidated audit log links each output document back to the original source file and page ranges
Partial Packets Routed to Exception Review with Suggested Resolution
Given an ingested packet is missing one or more PageSeq values or contains unreadable barcodes When ingestion detects the anomaly Then the packet is queued to the Exception Review within 15 seconds with reason codes and missing ranges listed And the system suggests likely resolutions (e.g., request re-scan of missing pages, merge with a recent related scan, or assign to inferred matter) with a confidence score And a reviewer can reorder pages, remove or add pages, change matter, change DocType, and approve filing And on approval, documents are filed and the audit log records reviewer ID, actions taken, timestamps, and final outcome
Standardized Naming and Versioning on Finalization
Given a document is being filed into a matter as part of ingestion or after review When the system creates the file record Then the filename follows the pattern {MatterID}_{DocType}_{YYYY-MM-DD}_{vN}.pdf And if a document of the same DocType already exists for the matter, a new version is created with v incremented by 1, preserving prior versions read-only And version metadata includes SHA-256 content hash, source, ingest method, barcode payload, and user (system or reviewer) And replacing an existing version is prevented; only new versions can be added
End-to-End Performance, Idempotency, and Auditability
Given up to 10 concurrent ingestion events across sources totaling 500 pages When processing starts Then 95th percentile time from detection to filed for a 50-page packet is <= 120 seconds And the system is idempotent: re-ingesting the same file or email does not create additional documents or versions; events are recorded as deduplicated with reference to the original Ingestion ID And all actions generate immutable audit entries that are searchable by MatterID, PacketID, source, hash, and time; export to CSV is available And errors are retriable with exponential backoff (max 3 attempts) before routing to the exception queue
Printer Profiles and Document Print Settings
"As an admin, I want configurable printer profiles tied to document types so that packets print correctly on the first try without manual adjustments at the device."
Description

Provide admin-configurable printer profiles that map document types to print settings such as duplex/single-sided, tray selection (letterhead vs plain), color/BW, copies, and staple preference. Allow profile selection at batch runtime with per-packet overrides, insert separator sheets when required, and include a test-print utility. Persist profile metadata with print jobs for traceability and offer sensible fallbacks when a printer capability is unavailable.

Acceptance Criteria
Admin creates and saves printer profile with document-type mappings
Given I am an admin on Settings > Printer Profiles When I create a new profile with a unique name and target printer Then I can map each document type (retainer, disclosures, fee waivers, checklists, separator) to duplex/single-sided, tray (letterhead/plain), color/BW, copies (1–10), and staple on/off And values are validated (e.g., copies must be an integer 1–10) And the profile saves successfully Given a saved profile When I reopen it Then all mappings and settings persist and are editable Given I attempt to save with missing required fields or invalid values When I click Save Then inline validation errors are shown and the profile is not saved Given an existing profile name When I try to save another profile with the same name Then the system blocks duplicates and requires a unique name
Operator selects printer profile at batch runtime with per-packet overrides
Given a batch print queue is ready When I select a printer profile for the batch Then the batch adopts that profile’s settings for all packets and document types Given a specific packet needs different settings (e.g., retainer single-sided instead of duplex) When I apply a per-packet override Then only that packet/documents use the override without modifying the saved profile And the UI shows an "Effective settings" summary per packet before confirmation Given I remove the override When I confirm Then the profile defaults are restored for that packet
Fallback handling when printer lacks a requested capability
Given the selected profile requests duplex for some documents And the chosen printer does not support duplex When I print the batch Then those documents print single-sided And a non-blocking alert informs me of the duplex fallback before printing And the fallback is recorded in the job metadata Given the profile requests stapling but the printer cannot staple When I print Then the job proceeds without stapling and records the fallback Given the profile specifies a tray that is unavailable/offline When I print Then the job routes to the printer’s default tray and records the fallback Given no trays are available or the printer is offline When I attempt to print Then a blocking error is shown and the job is not started
Tray selection enforces letterhead vs plain by document type
Given a profile maps Retainer and Disclosures to the Letterhead tray and other documents to Plain When I print a batch using this profile Then print jobs request the mapped tray per document type And the printer receives distinct tray instructions for each document as configured Given the printer provides a different tray naming convention via driver When the tray mapping is configured in the profile Then the application applies the selected tray consistently across all subsequent jobs using that profile
Separator sheets are inserted between packets when required
Given the selected profile has "Insert separator sheets between packets" enabled When I print a batch with multiple packets Then exactly one separator sheet is inserted between each packet And no separator is inserted after the last packet And the separator uses the tray and simplex/duplex settings defined in the profile Given the setting is disabled When I print the same batch Then no separator sheets are inserted
Test-print utility validates profile configuration and connectivity
Given I am viewing a saved printer profile When I click "Test Print" Then one test page per configured document type is sent using that profile’s mapped settings And the UI displays job status (queued, printing, completed) or error within 10 seconds of request And any detected fallbacks are summarized upon completion Given the target printer is offline or unreachable When I click "Test Print" Then a clear error is shown and no job is queued
Persist and retrieve print job metadata for traceability and reprint
Given a batch is printed When I open the job details Then I can view: selected profile name, profile version timestamp, target printer ID/name, effective settings per packet and document type (including overrides), fallbacks with reasons, user who initiated, start/end time, and job status Given I select "Reprint with same settings" on a prior job When I confirm Then the system re-queues the job using the saved effective settings regardless of current profile changes Given a profile was modified or deleted after the job When I view the historical job details Then the original metadata remains intact and readable

Sign Station

Run a dedicated e‑sign lane that cycles through “next ready” clients. Attendees scan their ticket to pull only pending signatures; large‑type, ADA‑friendly screens and guided prompts finish each packet in under a minute. Staff see real‑time completion and can escalate edge cases to attorney review without blocking the line.

Requirements

Ticket Scan & Pending Packet Fetch
"As a walk-in client, I want to scan my ticket to instantly load only the documents I need to sign so that I can finish quickly without sharing personal information aloud."
Description

Enable clients to scan a QR/barcode or enter a short alphanumeric code to securely retrieve only their pending e-sign packets. Validate lookup with lightweight verification (e.g., last name + DOB last 4) without exposing PII on screen or aloud. Fetch and display signing context within 500 ms median latency, limiting payload to required signature artifacts. Support alternate manual lookup by staff with role-gated access. Use ephemeral device storage; purge on session end or 60 seconds of inactivity. Log lookups with anonymized identifiers for audit. Integrate with Briefly’s matter and document services to filter to signature-required fields only.

Acceptance Criteria
Ticket scan retrieves only pending e-sign packets
Given a valid QR/barcode ticket is associated with Client A and at least one packet has status "signature-required" When the ticket is scanned at the Sign Station kiosk Then only Client A’s packets with status "signature-required" are returned And packets with status in ["completed","voided","canceled","draft"] are excluded And no matters lacking signature-required fields are displayed And if no pending packets exist, the UI shows a generic "No signatures pending" message without revealing name, email, phone, DOB, address, or matter ID
Manual short-code entry fallback
Given the kiosk cannot read a barcode When the client enters a valid 6–10 character alphanumeric ticket code and submits Then the system performs the same pending-packet filter as ticket scan and proceeds to verification And if the code is invalid or expired, a generic error is shown without PII And repeated failures are rate-limited to 5 attempts per 5 minutes per device with exponential backoff and a minimum 2-second delay between prompts
Lightweight identity verification without PII exposure
Given a packet lookup has matched a client When prompted for verification Then the client must enter last name and DOB last 4 to proceed And the UI never renders full last name or DOB; inputs are masked after entry and hints are non-identifying (e.g., ****) And after 3 failed attempts, the session locks for 2 minutes and resets to the start screen And no raw last name or DOB are stored in logs; only a success/failure outcome is recorded
Performance and payload minimization
Given normal reference load (≥10 concurrent kiosks, ~50 ms RTT) When a valid scan or code submission occurs Then time from submit to rendering the signing context is ≤ 500 ms p50 and ≤ 1200 ms p95 over 200 requests And the API response for packet context is ≤ 200 KB per packet and contains only signature field metadata, document/page identifiers, and signing instructions And full matter records and non-required documents are excluded from the response And binary document pages are streamed on-demand during signing, not during lookup
Ephemeral device storage and inactivity purge
Given a lookup session starts on a kiosk When the session ends or 60 seconds pass without user interaction Then all locally stored session data (tokens, packet IDs, cached previews) are purged from memory and browser storage And using the browser back/forward buttons or refresh does not reveal prior session data And HTTP responses for packet context include Cache-Control: no-store, private and Pragma: no-cache And server-issued session tokens expire in ≤ 5 minutes and cannot be reused after purge
Role-gated staff manual lookup
Given a user is authenticated with role in ["Staff","Attorney"] on a non-kiosk device When they open the manual lookup tool Then they can search by client last name plus DOB last 4 or by matter ID and retrieve only pending signature packets And users without required roles receive HTTP 403 and no result UI And the manual lookup UI is blocked on kiosk origins/hostnames And all manual lookups are logged with anonymized identifiers and actor role
Audit logging with anonymized identifiers
Given any lookup attempt (scan, code entry, or staff lookup) When the attempt completes (success or failure) Then an audit record is written with timestamp, channel, anonymized ticket/client identifiers (salted SHA-256), outcome, latency, and actor role (if applicable) And the record stores no raw PII (no names, emails, phone, DOB, or matter titles) And logs are retained for ≥ 90 days and accessible to authorized admins for query/export And each record includes an HMAC-verifiable event ID to provide tamper-evidence
Next-Ready Queue Orchestrator
"As front-desk staff, I want kiosks to automatically pull the next ready client so that the line keeps moving without manual assignments."
Description

Provide a central queue service that maintains a FIFO list of clients whose packets are ready to sign, with priority rules (e.g., appointment time, ADA needs, rush matters). Each kiosk pulls the next ready client using token-based locking to prevent duplicate assignment, with 90-second lease renewal and auto-requeue on abandonment or error. Support load balancing across multiple kiosks and manual reordering by staff with audit. Expose queue metrics (wait time, throughput) and webhooks for events (assigned, started, completed). Ensure idempotent assignment and at-least-once delivery semantics.

Acceptance Criteria
Priority-Aware FIFO Assignment
Given the queue contains clients A(enqueued 10:00, appt 11:00, ADA=false, rush=false), B(enqueued 10:05, appt 10:30, ADA=true, rush=false), C(enqueued 10:07, appt 10:45, ADA=false, rush=true), and D(enqueued 09:55, appt 12:00, ADA=false, rush=false) and priority rules configured as: rush highest, then earlier appointment time, then ADA=true, then earlier enqueue_time And only clients in status "ready_to_sign" are eligible for enqueue and assignment When a kiosk requests the next client four times sequentially Then the assignment order is C, B, A, D And assigned clients are removed from the queue until completed or requeued
Token Locking and Idempotent Assignment
Given two kiosks K1 and K2 call AssignNext concurrently for the same queue when client X is at the head When the requests are processed Then exactly one assignment token T is issued for client X to a single kiosk And the other kiosk does not receive client X (it receives a different client or a no-available response) Given kiosk K1 repeats AssignNext with the same Idempotency-Key within the active lease window When the duplicate request is processed Then the same assignment token T and client X are returned And no duplicate assignment record is created
Lease Renewal and Auto-Requeue on Abandonment
Given kiosk K1 holds assignment token T for client X at time t0 with a 90-second lease When K1 sends a lease-renewal at t0+80s Then the lease expiry is extended by another 90 seconds from the renewal time Given no lease renewal or progress events occur by t0+90s+10s grace When the lease expires Then client X is automatically requeued according to current priorities And token T is invalidated And any attempt to complete with T after expiry is rejected with an error indicating lease_expired
Concurrent Kiosk Load Balancing
Given kiosks K1, K2, and K3 are pulling continuously for 5 minutes and 90 ready clients are enqueued at a steady rate When assignments are made during this interval Then the number of assignments per kiosk differs by no more than 15% from the average And no client is assigned to more than one kiosk
Staff Manual Reorder with Audit Trail
Given staff user S with Queue Manager permission moves client X from position 7 to position 2 When the change is saved Then the visible queue updates within 1 second and X appears at position 2 And subsequent AssignNext calls honor the new position unless superseded by higher-priority new arrivals per configured rules And an immutable audit record is created capturing client_id, previous_position=7, new_position=2, staff_id=S, timestamp, and reason
Real-Time Queue Metrics Accuracy
Given 20 clients are enqueued and processed with known enqueue and start times over a 10-minute window When GET /metrics is requested Then the response includes queue_length, avg_wait_seconds_60m, and throughput_per_hour And the values match ground-truth computed from events within ±5% And metrics reflect a Started or Completed transition within 2 seconds of the underlying state change
Webhook Events and At-Least-Once Delivery
Given a subscriber is configured for assigned, started, and completed events When a client transitions through Assigned → Started → Completed Then a webhook is emitted within 1 second of each transition with fields event_id, client_id, packet_id, event_type, and timestamp And each delivery includes a verifiable signature and an Idempotency-Key equal to event_id Given the subscriber returns HTTP 500 for two attempts and 200 on the third When the assigned event is emitted Then three deliveries are attempted with increasing delays And the same event_id is used across attempts And the subscriber may receive duplicates but never receives Started before Assigned nor Completed before Started for the same client
ADA-Friendly Guided Signing UI
"As a client with low vision, I want clear, large-text signing screens with voice and visual guidance so that I can complete signatures independently and accurately."
Description

Deliver a WCAG 2.2 AA-compliant signing experience with large-type presets (18–24 pt), high-contrast themes, screen-reader and keyboard navigation, clear focus states, and haptic/audio prompts. Provide simple, step-by-step guidance with one action per screen, oversized tappable targets, adjustable text size, and multilingual support (EN/ES at launch; extensible). Optimize for median completion under 60 seconds per packet via progressive loading and pre-validation. Include pause/resume within a session, error prevention for required fields, and clear confirmations. Support 10–27 inch displays in kiosk fullscreen mode.

Acceptance Criteria
Large-Type Presets and Adjustable Text Scaling
- Given the kiosk is in fullscreen on a 10–27" display, When the user opens Text Size settings, Then presets of 18 pt, 21 pt, and 24 pt are available and selectable. - Given any preset is applied, When navigating each step of the packet, Then all body text renders at or above the selected size with no truncation or overlap. - Given text is scaled, Then no horizontal scrolling is introduced and line length remains between 45–90 characters on 10–27" displays. - Given text is scaled, Then primary actions and input labels reflow within the viewport without obscuring focus outlines or CTA buttons. - Given a session ends (completion, timeout, or reset), Then text size reverts to default on the next session.
High-Contrast Theme and Focus Visibility
- Given the kiosk is at the start screen, When the user enables High Contrast, Then all UI meets WCAG 2.2 AA contrast: normal text >= 4.5:1, large text >= 3:1, non-text UI and focus indicators >= 3:1. - Given keyboard navigation, When focus moves, Then a visible focus indicator of at least 2 px width and 3:1 contrast appears on the focused element. - Given High Contrast is enabled, Then the setting persists across all steps in the current session and resets after session end. - Given the theme toggle, When using keyboard-only, Then the toggle is reachable within two Tab presses from the top actionable element and is operable with Space/Enter. - Given an action completes successfully or errors, When audio is unmuted and the device supports haptics, Then a success chime/error tone (<= 75 dB at 1 m) and a brief haptic pulse (<= 50 ms) play; a mute toggle is available within two taps.
Screen Reader and Keyboard Navigation Compliance
- Given a screen reader is active, When entering each step, Then the step title is announced first and the primary action is reachable within five Tab stops. - Given any interactive element, When announced by a screen reader, Then it exposes an accessible name, role, and state that match its visible label. - Given keyboard-only usage, When navigating the flow, Then the Tab order follows the visual order, no keyboard traps exist, and pressing Escape moves focus to the step’s top anchor. - Given a validation error occurs, When focus moves to the error summary, Then errors are listed with programmatically associated field-level messages and aria-describedby links. - Given assistive tech testing, When tested with NVDA (Windows) and VoiceOver (iPadOS), Then all steps are fully operable and announcements are accurate.
One Action Per Screen with Oversized Tappable Targets
- Given any step in the signing flow, When the screen renders, Then there is exactly one primary action and no more than two secondary actions visible. - Given any tappable control (buttons, radios, checkboxes, inputs), When measured, Then the touch target is at least 44x44 CSS pixels with 8 px minimum spacing between adjacent targets. - Given a required field is incomplete, When the user attempts to continue, Then the Continue action is disabled and an inline, plain-language prompt appears without advancing the step. - Given all required inputs are valid, When the user activates Continue, Then the next step loads without additional dialogs within 500 ms. - Given the kiosk app starts, Then it runs in fullscreen mode with no browser UI, and layouts render correctly on 10–27" displays with no clipping or distortion.
Multilingual EN/ES Toggle and Localization Coverage
- Given the language selector is shown on the welcome screen and header, When the user switches to Español, Then all visible text, helper copy, buttons, error messages, and aria-labels change to Spanish within 200 ms. - Given Spanish is active, When the user proceeds through all steps, Then 100% of translatable strings render from locale files with no fallback English strings. - Given language is switched mid-step, When validation errors exist, Then error messages update to the selected language and remain associated to their fields. - Given a new session starts, When no staff default language is set, Then the UI defaults to English; otherwise it respects the staff-configured default.
Performance and Progressive Loading
- Given a standard kiosk device (Chrome, 12" touch display, 2.0 GHz dual-core, 4 GB RAM, 20 Mbps, 50 ms RTT), When 100 representative packets are completed by test participants, Then the median time from first screen interactive to packet submission is <= 60 s and the 90th percentile is <= 90 s. - Given the first step, When the route is requested on a warm cache, Then Time to Interactive is <= 1.0 s and Interaction to Next Paint is <= 100 ms. - Given navigation between steps, When the user taps Continue, Then the next step becomes interactive within 500 ms 95% of the time via prefetch/progressive loading. - Given asset loading, When network speed degrades to 5 Mbps, Then the UI still renders a skeleton and primary controls within 1.5 s.
Pause/Resume Within Session with Privacy Safeguards
- Given an in-progress session, When Pause is activated or 60 s of inactivity elapse, Then the UI locks to a privacy screen within 1 s and obscures any PII. - Given a paused session, When the attendee scans their ticket within 10 minutes, Then the session resumes at the last completed step with all previously entered data intact. - Given a paused session exceeds 10 minutes or the packet is completed, When the ticket is scanned, Then a new session starts and prior data is purged from the device. - Given packet submission succeeds, Then a confirmation screen with large-type checkmark and summary appears within 1 s and includes a Back to Start button. - Given confirmation is dismissed, When the session ends, Then all cached form data and files are cleared from local storage and memory within 2 s.
Signature-Only Packet Slicing & Autofill
"As a client, I want to see only the fields I must sign with my information already filled so that I finish faster and avoid mistakes."
Description

Assemble a signing-only view that surfaces required signature, initial, checkbox, and date fields while locking non-editable content. Prefill fields from Briefly’s validated intake data and enforce field-level validations (e.g., name match, date formats). Support single and multi-signer packets with per-signer routing and on-device signature capture (draw/type/stamp) compliant with E-SIGN/UETA. Generate a tamper-evident final PDF with embedded audit trail and certificate. On completion, mark signatures as done in the matter, trigger downstream automations (retainer countersign, filing prep), and provide an optional printed or SMS/email receipt.

Acceptance Criteria
Signature-Only View Shows Required Fields and Locks Others
Given a matter has a prepared signing packet And a signer initiates a session in Sign Station When the packet opens in signature-only mode Then only required signature, initial, checkbox, and date fields are visible and focusable And all other document content is rendered read-only and cannot be edited, selected, or altered And non-required fields are hidden from navigation And the signer cannot proceed to submission until all required fields are completed
Autofill From Validated Intake and Field-Level Validation Enforcement
Given validated intake data exists and field mappings are configured When the signing-only view loads Then mapped fields are prefilled with intake values where allowed by template rules And required checkboxes default per mapping and remain editable only if allowed And name fields must exactly match the signer’s legal name from intake or trigger an inline error and block submission And date fields enforce the configured format and min/max constraints and reject invalid entries with inline errors And unresolved validation errors prevent packet submission And if identity mismatch persists after two attempts, the session offers “Escalate to Attorney Review” and saves progress
Single-Signer On-Device Signature Capture (Draw/Type/Stamp) With Consent
Given a single signer has scanned their ticket and accepted the electronic consent disclosure When the signer completes all required fields using draw, type, or stamp input Then each applied signature/initial captures method, timestamp, user ID, device ID/IP, and page/field coordinates in the audit trail And the visual appearance of signatures matches template settings and is embedded into the document And the session cannot proceed without explicit consent acknowledgment And the consent text and acceptance event are included in the final certificate
Multi-Signer Routing and Field Isolation
Given a packet configured for multiple signers with a defined routing order When signer A authenticates and opens the packet Then only signer A’s assigned fields are visible and editable; all other signers’ fields are hidden and locked And upon submission by signer A, the packet state updates to Awaiting signer B and sends the appropriate routing notification And if signer B attempts to open the packet before signer A completes, access is blocked with a message respecting routing rules And per-signer completion timestamps are recorded in the audit trail
Tamper-Evident Final PDF and Embedded Audit Certificate
Given all required signatures for the packet are complete When the packet is finalized Then the system generates a single PDF that is cryptographically sealed to be tamper-evident And the PDF embeds a detailed audit trail and a verifiable certificate including signer identities, timestamps, IP/device data, and document hash And standard PDF viewers indicate the document as valid and unaltered And any post-finalization change invalidates the seal and is detectable
Completion Updates and Automation Triggers
Given a packet has been finalized When finalization succeeds Then the matter record marks all signatures as Done with timestamps and user attribution And downstream automations fire, including retainer countersign (if applicable) and filing preparation workflows And events are emitted to the internal bus/webhooks for observability with success/failure status And failures are retried up to three times and surfaced to staff without blocking kiosk flow
Receipt Generation and Delivery
Given finalization succeeds When staff selects a receipt option or a default receipt channel is configured Then the system produces an on-screen confirmation and offers Print, SMS, and Email receipt options And SMS/email receipts include a secure link to the final PDF, certificate ID, signer name, and completion timestamp And printed receipts include a scannable code or short URL to the document and certificate ID And delivery outcomes (success/failure) are logged on the matter
Real-Time Line Monitor & Completion Dashboard
"As intake staff, I want real-time visibility into signing progress so that I can intervene early and keep the line moving."
Description

Provide staff with a live dashboard showing per-kiosk status (idle, assigned, in progress, stalled, error), client initials or ticket IDs, elapsed time, and completion events. Surface alerts for stalls (>90 seconds inactivity), verification failures, or declined consent, with one-click actions to assist, requeue, or cancel. Display throughput metrics (signs/hour, median time), wait-time estimates, and kiosk health (network, device). Offer exportable logs and role-based views that minimize PII exposure. Integrate with queue events and write back completion to the matter timeline.

Acceptance Criteria
Per-Kiosk Live Status Panel
Given the dashboard is open and connected to the event stream When a kiosk has no assigned client Then its status badge shows "Idle" Given the dashboard is open and connected to the event stream When a client is assigned to a kiosk but has not started signing Then the kiosk status shows "Assigned" and displays the client initials or ticket ID masked per role Given a signer opens the packet on the kiosk When input events are received Then the kiosk status shows "In Progress" and the elapsed time counter updates every second with ±1s accuracy Given a kiosk is in an active session When no heartbeat or input activity is received for more than 90 seconds Then the kiosk status shows "Stalled" Given the kiosk app reports a runtime error or heartbeat loss exceeds 10 seconds When the dashboard receives the error event Then the kiosk status shows "Error" Given completion events are emitted by the signing flow When the dashboard receives a completion event Then the kiosk card appends a timestamped completion entry (ISO 8601 UTC) within 2 seconds of event receipt
Stall Detection and Alerts
Given a kiosk session is "In Progress" When no input or heartbeat events are received for 90 consecutive seconds Then mark the kiosk as "Stalled" and display a red alert banner on its card within 2 seconds And send a visible toast notification to all connected staff sessions within 2 seconds Given a kiosk is marked "Stalled" When user input resumes on the kiosk before staff action Then clear the stall state, remove the alert within 2 seconds, and record a "stall_cleared" event Given a kiosk remains stalled When 3 minutes of inactivity elapse Then escalate by pinning the card to the top of the list and adding an "Escalated" label until acknowledged
One-Click Assist/Requeue/Cancel
Given a kiosk card is visible to a staff user When the user clicks "Assist" Then open the assist panel within 1 second, pause new assignments to that kiosk, and log an "assist_initiated" event with staff_user_id and kiosk_id Given a kiosk has an active signer When the user clicks "Requeue" Then end the current session, return the signer to the queue head, reset the kiosk status to "Idle" within 2 seconds, and log a "requeued" event with a required reason Given a kiosk has an active signer When the user clicks "Cancel" Then terminate the session, mark the packet as "Cancelled by Staff" (or equivalent), update the matter to reflect cancellation, reset the kiosk to "Idle" within 2 seconds, and log a "cancelled_by_staff" event with a required reason Given any of the above actions are taken When the snackbar "Undo" is clicked within 10 seconds Then restore the prior session state and log an "undo" event referencing the original action
Throughput Metrics and Wait-Time Estimates
Given the metrics panel is visible When at least one completion has occurred in the last 60 minutes Then display Signs/Hour (rolling 60 minutes) and Today-to-Date signs/hour and counts And display Median Time to Complete computed over the last 50 completions (or all if <50) And refresh metrics at least once per minute and within 5 seconds after each new completion Given an active queue of waiting signers and at least one active kiosk When computing wait-time estimates Then estimate per-signer wait = ceil(queue_length / active_kiosks) × median_time_to_complete and display in minutes with an uncertainty band And over any window of 20 completed signers, the observed average wait falls within ±20% of the displayed estimate
Role-Based Views & PII Minimization
Given role = Admin or Staff When viewing any kiosk card or event row Then show client initials and ticket ID only; never show full names, addresses, DOB, SSN, or document contents Given role = Volunteer When viewing the dashboard Then show ticket ID masked (e.g., TKT-1234) and no initials; hide actions that expose PII; API requests for restricted fields return 403 Given a user’s role changes When the dashboard refresh tick occurs (≤5 seconds) Then the visible fields update to match the new role without a full page reload Given any export or API response When the user is Volunteer Then PII fields are omitted or masked consistently with the UI policy
Queue Integration & Timeline Writeback
Given the queue service emits an assignment event for ticket_id X to kiosk K When the dashboard receives the event Then kiosk K shows status "Assigned" with ticket_id X within 2 seconds Given kiosk K begins signing for ticket_id X When the start event is emitted Then kiosk K shows status "In Progress" within 2 seconds and start time is recorded Given the signer completes e-sign on kiosk K When the completion event is emitted Then the dashboard records a completion entry, resets kiosk K to "Idle" within 2 seconds, and writes a "signing_completed" entry to the matter timeline containing kiosk_id, ticket_id, started_at, completed_at, duration_seconds, and staff_user_id if assisted Given a verification failure or consent decline occurs When the error/decline event is emitted Then the dashboard surfaces an alert and writes the corresponding event to the matter timeline within 2 seconds
Exportable Audit Logs
Given a user with Admin or Staff role selects an export for a date range ≤ 31 days and ≤ 10,000 events When the user requests CSV or NDJSON Then the file is generated within 10 seconds and the download begins Given an export is generated When inspecting the output Then each record contains event_id, timestamp_utc (ISO 8601), kiosk_id, ticket_id_masked, status_before, status_after, action_type, actor_user_id (nullable), duration_ms (nullable), error_code (nullable) And the file encoding is UTF-8 without BOM and numeric fields use dot decimal Given a Volunteer user attempts to export When the export button would be shown or the API is called Then the UI control is hidden and the API responds 403 Given any export completes When auditing system events Then an "export_generated" audit event exists with requesting user id, filters, format, and record count
Edge-Case Escalation to Attorney Review
"As staff, I want to escalate tricky signings to an attorney without stopping the station so that other clients can continue signing."
Description

Enable kiosks and staff to flag sessions for attorney review without blocking the lane, with structured reasons (legal question, data mismatch, name variance, ID issue, document ambiguity) and optional notes or photos. Park the packet in an attorney queue with full context and a session snapshot. Notify the assigned attorney and staff, allowing approve-as-is, edit-and-resend, or request follow-up. Preserve partial progress, redact sensitive fields on kiosk upon escalation, and automatically requeue the next client at the station.

Acceptance Criteria
Kiosk Escalates Without Blocking Lane
Given a client is mid-signing on a Sign Station kiosk and an edge case is detected When the client or kiosk flow triggers "Escalate to Attorney" and a reason is selected Then the escalation record is created and queued within 1 second And the kiosk session is terminated, the screen is cleared, and prior client data is no longer accessible And the station returns to the "Scan next ticket" screen within 2 seconds And an audit log entry is recorded with session ID, kiosk ID, timestamp, triggering user (client/kiosk), and selected reason
Staff-Initiated Escalation From Console
Given staff is viewing a live session in the Staff Console When the staff member clicks "Escalate to Attorney", selects a structured reason, and confirms Then the session immediately moves to the Attorney Review queue with status "Escalated" And the associated kiosk lane is marked free for next client within 2 seconds And an audit log captures staff ID, timestamp, reason, and optional notes presence And the Staff Console reflects the session state as "Escalated" without requiring a page refresh
Structured Reason, Notes, and Photo Capture
Given an escalation is being created from kiosk or Staff Console When the user selects one or more reasons from {Legal question, Data mismatch, Name variance, ID issue, Document ambiguity} Then at least one reason is required to proceed And optional notes up to 1000 characters can be added And up to 3 photo attachments (JPEG/PNG, each ≤ 5 MB) can be captured or uploaded And if an attachment fails validation, a clear error is shown and escalation can proceed without the invalid file And all captured reasons, notes, and photos are stored and linked to the escalation record
Attorney Queue Packet With Full Context & Session Snapshot
Given an escalation has been created When the assigned attorney opens the item in the Attorney Review queue Then they can view: client identifier, ticket number, kiosk/station ID, staff ID (if applicable), timestamp, selected reasons, notes, photos, current document state, fields modified in this session, outstanding signature statuses, and validation errors And a read-only session snapshot is available, including screen captures or structured step log And all items load within 3 seconds on a broadband connection And the queue item contains a unique escalation ID for cross-referencing in audit logs
Notifications to Assigned Attorney and Staff
Given an escalation has been created When routing rules determine the assigned attorney (fallback to Attorney-on-Call if none) Then the assigned attorney receives an in-app notification immediately and an email within 60 seconds containing client/ticket, reasons summary, and a deep link to the queue item And the originating staff console updates within 5 seconds to show "Escalated → Awaiting Attorney" And if delivery to the assigned attorney fails, the system retries twice and then escalates to the backup attorney and alerts staff
Attorney Decisions: Approve-As-Is, Edit-And-Resend, Request Follow-Up
Given an attorney is viewing an escalated packet When the attorney selects Approve-As-Is Then the packet status changes to "Approved", audit log records decision with timestamp, and staff are notified to proceed with signing When the attorney selects Edit-And-Resend and saves changes Then redlined changes are captured, documents are regenerated, packet status becomes "Updated → Ready to Sign", and staff are notified to re-invite the client When the attorney selects Request Follow-Up and provides a note Then a follow-up task is created with due date and assignee, the packet is put on hold, and staff and the client’s preferred contact channel are notified as configured
Preserve Progress, Redact Sensitive Fields, and Auto-Requeue
Given a session is escalated from kiosk or staff console When the escalation completes Then all completed answers, validations, and collected signatures are preserved for later resumption without re-entry And sensitive fields (SSN, full DOB, ID images, signature panels) are immediately cleared from the kiosk UI and device cache And the kiosk shows no residual PII and returns to the "Scan next ticket" screen within 2 seconds And the next client can scan and begin a new session with no dependency on the escalated packet’s resolution
Kiosk Security & Privacy Controls
"As a compliance officer, I want kiosk sessions to protect client data and produce a defensible audit trail so that we meet legal and ethical obligations."
Description

Harden kiosks with session isolation, auto-lock and data purge after completion or 60 seconds of inactivity, masked PII on shared screens, and consent capture before signing. Enforce fullscreen/app-mode with navigation controls disabled, blocked downloads/printing, and no clipboard access. Use TLS 1.3, device fingerprinting, CSRF protection, rate limiting, and short-lived tokens. Store only ephemeral artifacts on device; persist signed packets and audits server-side with encryption at rest. Produce a detailed audit trail (timestamps, IP/device, field changes) and configurable retention policies to satisfy E-SIGN/UETA and law office confidentiality obligations.

Acceptance Criteria
Session Isolation per Attendee
Given the kiosk is in Sign Station mode When Attendee A completes their signing flow or the session ends Then a new session for Attendee B cannot access any of Attendee A’s data via browser back/forward, direct URL, autocomplete, or cached state And all client-side storage (localStorage, sessionStorage, IndexedDB, CacheStorage/service worker caches) is cleared within 1 second of session end And the next screen rendered is the kiosk welcome screen with no prefilled fields And protected endpoints from the prior session return 401/403 when accessed with stale identifiers And each new session is assigned a unique server-side session ID and token not reused across attendees
Auto-Lock and Data Purge on Inactivity
Given a signing session is active When there is no user input (keyboard, touch, mouse, or scroll) for 60 seconds ±1s Then the kiosk auto-locks to a non-PII lock screen and terminates the session And all ephemeral data on the device (memory and any web storage/cache) is purged immediately And resuming requires the attendee to rescan their ticket; no prior form data is restored And an audit event "auto_lock" with timestamp, IP, and device fingerprint is recorded When a signing flow completes successfully Then the same purge and return-to-welcome behavior occurs within 1 second
Masked PII on Shared and Kiosk Screens
Given any screen visible to bystanders during Sign Station use When PII fields are displayed Then the following masking rules apply: SSN/Tax ID/DL/Account numbers show only last 4; DOB shows MM/XXXX; email shows f****@domain.tld; phone shows (XXX) XXX-####; address shows city/state/ZIP only unless full line is strictly required for signature validation And copy/paste and text selection are disabled for displayed PII values And no PII appears on idle, error, or lock screens And input fields for PII have browser autofill/autocomplete disabled
E-SIGN/UETA Consent Gate Before Signing
Given an attendee attempts to begin signing When the consent screen is shown Then the attendee must affirmatively agree (checkbox + Continue) to firm-approved E-SIGN/UETA consent text (versioned) And proceeding without checking consent is blocked with a clear prompt And choosing Decline ends the session, purges local data, and records a "consent_declined" audit event And an immutable consent record (timestamp, IP, device fingerprint, consent text version, attendee ID) is stored server-side and linked to the packet before any signature event is accepted
Kiosk App-Mode: Navigation, Download/Print, and Clipboard Restrictions
Given the kiosk is running in enforced app/fullscreen mode When a user attempts navigation actions (back, forward, reload, open new tab/window, address bar entry, external links) Then navigation is blocked or contained to the kiosk webview and the app remains on approved routes only When a user or script attempts to download files or invoke printing Then no files are written to disk, no print dialog appears, and a "blocked_download_or_print" audit event is recorded When clipboard operations (copy/cut/paste, programmatic read/write) are attempted on kiosk pages Then the operations are blocked and yield empty/no-op results And right-click/context menu and common shortcuts (Ctrl/Cmd+P, S, C, V, X, N, T, L) are disabled within the kiosk
Transport, Session, and Abuse Protections
Given any connection to the kiosk backend When a client attempts to negotiate TLS 1.2 or lower Then the handshake is rejected; TLS 1.3 is required for success When a state-changing request (POST/PUT/PATCH/DELETE) is made without a valid CSRF token Then the request is rejected with 403 When scan or sign endpoints are hit more than the configured rate (e.g., >10 requests/min/IP or >5 sign attempts/min/device) Then responses return 429 with no state change And access tokens are HttpOnly, Secure, SameSite=Strict, bound to device fingerprint, and expire after 10 minutes of inactivity (max 30 minutes absolute); expired or fingerprint-mismatched tokens are rejected with 401 and the kiosk resets to welcome with purge And each request includes a device fingerprint; the fingerprint is captured in the audit log
Server-Side Persistence, Encryption, Audit Trail, and Retention
Given a packet is signed in the kiosk When records are saved Then only server-side storage persists the packet and audit trail; no artifacts remain on the device beyond runtime And persisted data is encrypted at rest; attempting to read storage without keys is infeasible and key access is restricted to the service And an audit trail is created for each event with: event type, UTC timestamp (ISO-8601), IP, device fingerprint, actor, and field-level changes (old/new values with masking for sensitive fields), plus signature event hashes And audit entries are append-only; attempts to alter or delete existing entries are rejected and logged When firm retention is configured (e.g., packets=Y days, audits=Z days, with legal hold overrides) Then a scheduled job deletes expired items, logs a "retention_delete" event, and items are no longer retrievable (404) after the retention window And the full audit trail and packet can be exported server-side by authorized staff without enabling client downloads on the kiosk

Boundary Snap

Automatically resolves the correct county and venue from a client’s address or live GPS during intake, even across split ZIP codes, PO boxes, and rural routes. Flags conflicts (mailing vs. physical address), prompts for a service address when needed, and logs a confidence score with a mini‑map. Prevents bounced filings and venue corrections that waste time and erode client trust.

Requirements

Address Normalization & Geocoding
"As a client completing intake on mobile, I want my address validated and recognized automatically so that I don’t have to retype it or fix errors and my attorney files in the right place."
Description

Implement robust address parsing, USPS-style normalization, and high-precision geocoding to determine latitude/longitude with precision metadata (rooftop, interpolated, centroid). Support secondary unit designators, rural routes, and non-standard formats. Validate during intake with inline suggestions and error handling, store standardized forms, geocode results, and provenance. Provide retry/backoff and fallback to a secondary provider for resiliency. Expose normalized address and geocode metadata to downstream Boundary Snap components, document assembly variables, and audit logs.

Acceptance Criteria
Inline Address Normalization During Intake
Given a user enters an address with mixed casing, extra whitespace, or common misspellings, When the field loses focus or after 500 ms of inactivity, Then the system displays a USPS Publication 28–formatted suggestion with standardized casing, abbreviations, ZIP+4, and removed extraneous punctuation. Given a suggested normalized address is presented, When the user accepts it, Then the form fields update atomically without losing secondary unit data, and both original and normalized addresses are stored. Given a suggested normalized address changes city or ZIP, When the user declines it, Then the original input is retained, a decline reason is recorded, and submission remains allowed if required fields are complete. Given the address cannot be validated by the primary provider, When the user attempts to continue, Then an inline error is shown with corrective guidance and a manual override option that must be explicitly confirmed before submission.
Secondary Unit Parsing and Validation
Given an address string containing secondary unit text (e.g., "Apartment 5B", "Ste#200", "#12"), When parsed, Then the system normalizes the unit to USPS abbreviations (APT, STE, UNIT) and formats examples as "APT 5B", "STE 200", and "UNIT 12". Given the primary address corresponds to a multi-unit location per reference data, When no unit is provided, Then the system prompts for the unit and blocks submission until provided or "No Unit" is explicitly confirmed. Given the user enters a unit within the street line, When normalized, Then the unit is split into a dedicated field and preserved in storage and downstream variables. Given a unit range is entered (e.g., "Unit 3-5"), When validating, Then the system rejects ranges and instructs the user to select a single unit.
Rural Route and PO Box Handling
Given an address is identified as a PO Box or Rural Route, When geocoding, Then the system sets precision to postal or route centroid (not rooftop) and sets rooftop confidence to 0. Given only a PO Box is provided for a matter requiring a physical service address, When proceeding, Then the system prompts for a physical service address and blocks completion until provided or a documented exception is recorded. Given a rural route address includes a box number, When normalizing, Then the system formats it per USPS (e.g., "RR 2 BOX 152") and retains the original input for provenance. Given both mailing (PO Box) and physical addresses are supplied and resolve to different counties, When saving, Then both are stored with explicit type labels and a conflict flag is set for Boundary Snap.
High-Precision Geocoding with Metadata
Given a normalized address is eligible for rooftop geocoding, When geocoded via the primary provider, Then the result includes latitude and longitude in WGS84 with at least 6 decimal places, a precision category (rooftop, interpolated, parcel, postal centroid), accuracy radius in meters, and a provider confidence score. Given multiple geocoding candidates are returned, When selecting, Then the system chooses the highest precision category, then highest confidence, and records the selection rationale. Given the precision category is interpolated or lower, When persisting, Then the system marks the result as low-precision and exposes a flag for downstream venue verification. Given geocoding completes, When storing, Then provider name, API/version, request/response IDs, timestamp, and the normalized input used are persisted as provenance.
Provider Resiliency with Retry and Fallback
Given a primary geocoding request times out or returns a retriable error (HTTP 5xx or network failure), When invoked, Then the system applies exponential backoff starting at 250 ms with factor 2, up to 3 retries with jitter, respecting a total geocoding budget under 3 seconds. Given primary retries are exhausted, When fallback is enabled, Then the system calls a secondary provider and maps its outputs to the internal schema without losing required metadata fields. Given both providers fail within the budget, When the user saves the intake, Then the system allows save with status "geocode_pending", surfaces a non-blocking warning, and enqueues a background retry. Given a fallback provider result is used, When persisting, Then the record includes provider priority, reason for fallback, and provenance markers indicating the source.
Data Exposure to Downstream Components
Given an intake is saved, When Boundary Snap requests location data, Then normalized address, latitude/longitude, precision category, confidence score, and county/census codes (if available) are exposed via a typed interface and event payload within 200 ms. Given document assembly is initiated, When variables are resolved, Then street, city, state, ZIP+4, secondary unit, and geocode metadata variables are available and correctly populated in documents. Given audit logs are queried, When retrieved, Then entries include before/after address values, geocode metadata, provider provenance, timestamps, and user IDs, immutable and filterable by case ID.
Inline Error Handling and Accessibility
Given validation errors occur, When presented, Then error messages meet WCAG 2.1 AA, are announced via ARIA live regions, and are programmatically associated with their fields. Given the address suggestion list is displayed, When navigating by keyboard, Then the user can move through options with Arrow keys, accept with Enter, and dismiss with Escape, with focus managed correctly. Given a screen reader user receives suggestions, When they appear, Then suggestions are announced succinctly without repeating the entire address and remain available until user action or explicit dismissal.
Live GPS Venue Resolution
"As a field client with an unreliable mailing address, I want my live location used to determine my county and court so that filings start correctly without guesswork."
Description

Use user-consented device location to resolve the current physical location to county and probable venue in real time. Handle accuracy radius, permission states, intermittently offline scenarios, and background updates during a session. Compare GPS-derived results to entered address and select the higher-confidence source. Cache results locally with timestamps for deferred sync, and record accuracy and source metrics. Integrate outputs with the venue rules engine and surface results to the intake review screen.

Acceptance Criteria
GPS Permission States and Fallback
Given a first-time user on the intake location step, When the OS prompt for location appears and the user selects Allow While Using the App, Then the app records permission_state=granted_while_in_use and acquires a location fix without blocking progression. Given the user selects Don’t Allow, When the intake continues, Then the app records permission_state=denied, does not call geolocation APIs, disables GPS auto-venue, and requires manual address entry before venue can be resolved. Given the user selects Allow Once, When the user navigates back to a location-dependent step within the same session, Then the app re-prompts for permission and proceeds only if granted. Given Precise Location is off (coarse only), When a location fix is received with accuracy_radius>500m, Then the app logs accuracy_m>500, sets gps_confidence=low, does not auto-select a venue, and displays a prompt to enter/confirm address.
Real-Time County and Venue Resolution with Accuracy Radius
Given a GPS fix with lat/lng inside a single county polygon and accuracy_radius<=100m, When the resolver runs, Then county_id equals the polygon containing the point, probable_venue_id is returned from the venue rules engine, a confidence_score>=0.90 is computed, and a mini-map preview centered on the fix is shown. Given a GPS fix with accuracy_radius between 101m and 500m and within 1km of a county boundary, When the resolver runs, Then confidence_score is between 0.50 and 0.89, county_id is still derived from the containing polygon, and the UI shows a “Verify venue” banner without auto-advancing. Given a GPS fix with accuracy_radius>500m or no fix within 5 seconds, When the resolver runs, Then no county/venue is auto-selected, confidence_score<0.50, and the user is prompted to confirm or enter an address. Given a resolved county and venue, When metrics are recorded, Then the system logs accuracy_m, confidence_score, resolution_time_ms, and resolver_version to analytics.
Source Selection: GPS vs Entered Address by Confidence
Given both GPS-derived and address-derived resolutions exist, When confidence_score_gps > confidence_score_address by >=0.05, Then source_selected=GPS and reason="higher_confidence" is stored. Given both sources exist, When confidence scores differ by <0.05 and the entered address is classified as PO Box or unknown street-level precision, Then source_selected=GPS and reason="address_low_precision" is stored. Given both sources exist, When confidence_score_address > confidence_score_gps by >=0.05, Then source_selected=ADDRESS and reason="higher_confidence" is stored. Given both sources exist and counties differ, When any source is selected, Then conflict_flag=true, conflict_type="county_mismatch", and both resolutions are persisted to the session audit log.
Offline Capture and Deferred Sync
Given the device is offline during intake, When a GPS fix is received from the OS, Then the app computes county/venue locally if possible, caches result with timestamp, accuracy_m, confidence_score, permission_state, and source=GPS in secure local storage with sync_status=pending. Given cached GPS-derived results exist with sync_status=pending, When connectivity is restored, Then results are synced to the server within 10 seconds, server_ack is recorded, and sync_status becomes=completed without data loss. Given the app is force-closed while offline, When it is reopened within 24 hours, Then pending GPS venue results remain available and are synced upon connectivity. Given local and server resolutions differ after sync, When reconciliation runs, Then the system retains both in the audit log and marks the higher-confidence resolution as active with reason="post_sync_reconcile".
Background Updates During Session
Given the intake session is open with permission_state allowing location, When the user moves >250 meters from the last resolved fix or accuracy improves by >=30%, Then the resolver re-runs, updates county/venue if changed, and logs an update event with prior and new values. Given frequent small movements, When updates are evaluated, Then re-resolution is throttled to a maximum of once every 15 seconds and debounced to avoid more than 1 update per 100 meters moved. Given the user manually locks venue selection on the review screen, When subsequent background updates occur, Then the venue is not auto-overwritten; instead, a non-blocking suggestion is shown with option to apply. Given the app goes to background for less than 2 minutes, When it returns to foreground, Then a fresh location check occurs and the resolver evaluates whether to update based on the same thresholds.
Conflict Detection and Service Address Prompt
Given GPS-derived county differs from the county resolved from the entered mailing address, When the discrepancy is detected, Then the UI flags a conflict, displays both counties, and requires the user to confirm a physical/service address before proceeding. Given the user provides a distinct service/physical address, When validation runs, Then the system re-resolves county/venue from that address and compares against GPS; if still mismatched across counties, conflict_flag remains true and user acknowledgment is required to continue. Given a conflict is resolved by user choice, When the selection is finalized, Then the selected source, reason_for_selection, and user_acknowledged_conflict=true are recorded in the audit log.
Integration with Venue Rules Engine and Intake Review Surface
Given a resolved location source (GPS or Address), When the venue rules engine is invoked, Then the returned probable_venue_id is stored alongside county_id, source, accuracy_m, confidence_score, and timestamp. Given a resolved venue, When the intake review screen is opened, Then it displays county name, venue name, source badge (GPS/Address), accuracy radius in meters, confidence score, timestamp, and a mini-map centered on the fix. Given the mini-map is displayed, When the user taps it, Then a larger map opens showing the pin within the correct county boundary polygon. Given any update changes the selected source or venue, When the review screen is visible, Then the UI updates within 1 second and writes a new audit entry with the delta.
Split ZIP & Rural Route Handling
"As an intake paralegal, I want the system to automatically handle tricky ZIP codes and rural routes so that I don’t have to research boundaries and risk misfiling."
Description

Correctly resolve counties and venues for addresses in split ZIP codes, unincorporated areas, and rural routes by prioritizing parcel-level geocoding over ZIP centroids and applying authoritative boundary datasets. Disambiguate cross-county municipalities with tie-breakers (parcel centroid, street ranges). Trigger minimal clarifying prompts only when ambiguity remains. Persist the disambiguation rationale and chosen boundaries, and ensure the selected county and court propagate to document headers and captions.

Acceptance Criteria
Split ZIP Street Address County Resolution
Given a user enters a street address within a ZIP code that spans multiple counties When Boundary Snap resolves jurisdiction Then the county must be determined using parcel-level geocoding against authoritative county boundary datasets (not ZIP centroids) And the selected trial court venue must be derived from the resolved county per configured jurisdiction mappings And no clarifying prompt is displayed if a single parcel match is found And if multiple parcel candidates remain after geocoding, tie-breakers are applied in order: (1) parcel centroid within boundary; (2) street number range tables; (3) municipality boundary overlay And only if ambiguity remains after tie-breakers, present a single clarifying prompt with targeted choices for the user to select the correct location
Rural Route/PO Box Requires Physical Service Address
Given the entered address is a PO Box or Rural Route designation without a physical street address When Boundary Snap attempts to resolve county and venue Then the system must not use ZIP centroid for resolution And the user is prompted once to supply a physical service address or confirm a mapped parcel location And progression is blocked until a physical address (or confirmed parcel) is provided And the reason for the prompt is recorded in the matter's boundary resolution log
Cross-County Municipality Tie-Breaker Disambiguation
Given a street address lies within a municipality that spans two or more counties When initial parcel-level geocoding yields multiple plausible counties Then tie-breakers must be applied in this order: (1) parcel centroid containment; (2) street segment and number range alignment; (3) nearest parcel boundary distance And if still ambiguous, present a single clarifying prompt listing only the candidate counties with distances And upon user selection, the chosen county and venue are finalized and the applied tie-breakers and user selection are logged
Persist Rationale and Chosen Boundaries
Given county and venue have been resolved (with or without a clarifying prompt) When the intake is saved or submitted Then the system must persist: final county, final court/venue identifier, parcel coordinates used, boundary dataset source and version, tie-breakers applied, and any user clarifications with timestamp And the persisted rationale must be retrievable in the matter audit log and intake summary And the persisted record must be immutable after client e-signature, with subsequent changes recorded as new versions
Propagate County and Court to Documents
Given county and venue are resolved for the matter When generating the retainer agreement and first-draft pleading documents Then the resolved county and court/venue must populate the document headers and captions via the appropriate merge fields And all generated documents in the session must reflect the same resolved values And if county or venue is changed prior to e-sign, the documents are automatically regenerated to reflect the new values, and the change is logged
Minimal Clarifying Prompts Policy
Given Boundary Snap encounters any ambiguity after applying parcel-level geocoding and tie-breakers When prompting the user for clarification Then no more than one additional question may be presented for the scenario And the prompt must present only the minimum targeted options necessary to disambiguate (e.g., candidate counties/venues) And if the user cancels the prompt, the matter cannot proceed past intake validation until a selection is made or a physical address is provided
Mailing vs Physical Conflict Detection
"As an attorney, I want to be alerted when a client’s mailing address differs from their physical location so that I can choose the correct venue and plan service appropriately."
Description

Detect and flag inconsistencies between mailing and physical addresses (e.g., PO Boxes, CMRAs, temporary lodging, business addresses). Display clear, actionable alerts with options to confirm, correct, or provide additional context. Track conflict status and prevent progression to e-sign if unresolved when venue or service depends on the physical location. Store both addresses with explicit labels for later use in service decisions, filings, and audit trails.

Acceptance Criteria
PO Box vs Residential Address Conflict Flagging
Given the client enters a mailing address containing "PO Box", "P.O. Box", or "PMB" (regex: (?i)\b(P\.?\s*O\.?\s*Box|PMB)\b) and a physical address that is a street address When the user attempts to continue past the Address step Then the system flags a conflict with type="PO_BOX_CONFLICT", displays an alert banner within 1 second, and creates a conflict record with status="Open" And the alert shows both addresses with explicit labels, a "Resolve now" action, and options: Confirm, Correct, Add context And a conflict badge appears on the intake progress header
CMRA/Business Mailing Address Conflict
Given the mailing address matches a known Commercial Mail Receiving Agency (CMRA) or business mailbox per the CMRA dataset and the physical address is different When the mailing address is saved Then the system flags a conflict with type="CMRA_MAILING", displays an actionable alert, and creates a conflict record with status="Open" And the alert presents options to Confirm, Correct, or Add context, and shows the labeled mailing and physical addresses
Conflict Resolution Workflow and Status Tracking
Given an open mailing vs physical address conflict exists When the user selects Confirm and enters a note (minimum 10 characters) Then the conflict status changes to "Resolved-Confirmed", the note and resolver userId are saved, and the alert is dismissed When the user selects Correct and saves updated address data that eliminates the inconsistency Then the conflict status changes to "Resolved-Corrected", with timestamp and change details recorded When the user marks the conflict as False Positive Then the status changes to "False Positive" and the banner is dismissed When the user selects Add context but cannot resolve Then the status changes to "Needs Info" and the conflict remains visible until resolved
Block E-Sign on Unresolved Address Conflict
Given an open address conflict exists and venue or service of process depends on the physical address When the user navigates to the e-sign step Then the "Send for e-sign" action is disabled and a tooltip explains it is blocked until the address conflict is resolved, with a link to "Resolve address conflict" When the conflict is resolved in the same session Then the e-sign action becomes enabled within 2 seconds without requiring a page reload When the matter does not depend on physical address for venue or service Then e-sign remains enabled despite the conflict
Prompt and Require Service Address When Physical Is Unserviceable
Given the physical address is identified as temporary lodging/shelter/hotel, a rural route without a street number, or otherwise unsuitable for service When the user attempts to proceed past the Address step Then the system prompts for a separate Service Address and explains why it is required And the Continue action remains disabled until a valid Service Address is entered or the user explicitly confirms using the physical address for service And the chosen Service Address and reason are stored and linked to the conflict record (if any)
Persist and Label Addresses for Downstream Use
Given mailing and physical addresses are captured during intake When the intake is saved Then both addresses are stored with explicit labels (mailingAddress, physicalAddress) and metadata: verifiedAt, verifiedSource, conflictId (nullable), resolutionStatus (nullable) And document assembly can reference both fields, and venue selection uses physicalAddress unless a Service Address override is present And the audit trail records all address edits and conflict lifecycle events with timestamp, actor, and old/new values
Service Address Prompt & Validation
"As a client, I want a simple prompt to provide my service address when needed so that my case can proceed without delays or rejected service."
Description

When a conflict or PO Box is detected, prompt for a valid service address and optional alternative service methods. Validate for deliverability and capture access instructions and preferred contact windows. Bind the confirmed service address into the retainer, initial pleadings, and service checklist, and flag matters where service information is provisional or missing. Provide a review step for staff to override with justification when necessary.

Acceptance Criteria
PO Box Detection Triggers Service Address Prompt
Given the client enters a mailing address containing a PO Box pattern When Boundary Snap validates the intake address Then the system must display a required Service Address prompt for a physical street address And the prompt includes Street, Unit, City, State, ZIP, and auto-resolved County fields And progression is blocked until a deliverable service address is confirmed or a staff override is recorded And the event "service_address_prompt_displayed" is logged with reason "PO_BOX_DETECTED"
Mailing–Physical Address Conflict Resolution Prompt
Given the mailing address and the detected physical/geolocation address do not match venue/county or street-level details beyond the defined threshold When the conflict is detected during intake Then the user is prompted to confirm which address to use for service or to enter a new service address And a conflict summary is displayed showing both addresses and the selected venue And progression is blocked until a service address is confirmed or a staff override is recorded And the event "service_address_prompt_displayed" is logged with reason "ADDRESS_CONFLICT"
Service Address Deliverability Validation and Confirmation
Given a service address is entered or selected When the system performs deliverability validation via the configured address verification service Then the address is normalized to postal standards when possible and a correction is shown And the user must accept or reject the suggested correction explicitly And the address is marked Deliverable or Undeliverable with a confidence score and reason code And Undeliverable status blocks progression unless an alternative service method is captured or a staff override is recorded And the validation response (timestamp, provider, codes) is stored in the matter audit log
Capture Access Instructions, Contact Windows, and Alternative Service Methods
Given the Service Address prompt is displayed When the user provides access instructions and preferred contact windows Then access instructions accept up to 500 characters and are stored with the service address And contact windows accept at least one day/time range and are stored with timezone And the user may optionally select alternative service methods (e.g., substitute service, consent to email) and attach supporting details or files And captured alternative methods are added to the service checklist with due dates derived from local rules configuration
Bind Confirmed Service Address into Documents and Checklist
Given a confirmed, deliverable service address exists When generating the retainer, initial pleadings, and service checklist Then the confirmed service address populates the designated fields in all generated documents And normalized formatting is preserved exactly as confirmed by the user And access instructions and contact windows appear only in the service checklist, not in client-facing pleadings or the retainer And document generation without a confirmed service address inserts a "TBD Service Address" placeholder and sets the matter flag to Provisional
Staff Override with Justification and Audit Trail
Given deliverability validation failed or an address conflict remains unresolved When a staff user selects Override in the review step Then a justification text field (minimum 15 characters) is required to proceed And the system records user ID, timestamp, pre/post address values, and justification in the audit log And the service address status is set to Overridden and progression is allowed And a follow-up checklist task "Confirm Service Details Before Filing" is automatically created and assigned
Provisional or Missing Service Information Flag and Guardrails
Given no confirmed, deliverable service address exists for the matter Or only alternative service methods are captured without an associated address When the matter advances to engagement or drafting Then the matter is flagged as "Service Info Provisional" with a visible banner and list badge And filing actions are blocked until the flag is cleared by confirmation or staff override And the flag status is filterable in matter lists and exported in reports
Confidence Scoring & Mini-Map Visualization
"As an attorney, I want to see a confidence score and mini-map for the resolved venue so that I can quickly verify or correct before e-sign and filing."
Description

Compute a venue confidence score using geocode precision, GPS accuracy, boundary overlap, and rule determinism. Display a compact map with a pin, county outline, and candidate court markers during intake review. Persist the score, contributing factors, and map snapshot to the matter for QA and audit. Use score thresholds to decide when to require user confirmation, escalate to manual review, or allow auto-advance to e-sign.

Acceptance Criteria
Auto-Advance on High Confidence
Given the venue confidence score for the intake is >= 0.85 and there are no address conflicts detected When the user reaches the intake review step Then the system preselects the derived county and primary venue and does not display a confirmation prompt And the "Continue to e-sign" action is enabled And the mini-map is displayed with a pin at the resolved coordinates, county outline, and the primary venue marker visible
Require Confirmation on Medium Confidence
Given the venue confidence score for the intake is between 0.60 and 0.84 inclusive When the user attempts to continue from the intake review step Then the system requires explicit confirmation of the venue selection via a confirm dialog or checkbox And the dialog lists the top contributing factors and their weights And selecting "Confirm" proceeds to e-sign; selecting "Review" routes the matter to Manual Review and blocks auto-advance
Escalate to Manual Review on Low Confidence or Conflicts
Given the venue confidence score is < 0.60 OR a conflict is detected (mailing vs physical mismatch, missing service address, or boundary overlap < 0.05) When the user reaches the intake review step Then the system blocks auto-advance and displays "Manual review required" And a Manual Review task is created and assigned with the computed score, contributing factors, and a map snapshot And the user is prompted to enter a service address if missing; if provided, the score is recomputed
Mini-Map Visualization Completeness
Given a derived venue has been computed for the intake When the mini-map is rendered on the review step Then the map shows a location pin at the resolved latitude/longitude And the county boundary outline for the resolved county is visible And 1 primary venue marker and up to 3 candidate court markers are shown with labels And the map viewport fits all markers and boundary within the compact map container
Persistence & Audit Trail
Given the intake review step is saved or submitted When the matter is created/updated Then the system persists the confidence score (0.00–1.00, rounded to 2 decimals), the four contributing factors (geocode_precision, gps_accuracy_m, boundary_overlap_pct, rule_determinism), and their raw inputs And a map snapshot image of the current mini-map is stored with timestamp and coordinate bounds And the persisted data is retrievable via the Matter API and visible in the matter QA timeline
Scoring Inputs and Determinism
Given geocode precision, GPS accuracy, boundary overlap, and rule determinism inputs are available When the venue confidence score is computed Then each factor is normalized to a 0–1 scale and included in the score calculation And the score computation is deterministic: the same inputs produce the same score value And if a factor is missing, it is marked as missing, contributes 0 to the score, and is noted in contributing factors
Split ZIP / PO Box / Rural Route Handling
Given the client's address is in a split ZIP, a PO Box, or a rural route When deriving the venue and computing confidence Then the system prioritizes the physical or service address over the mailing address And if only a PO Box is provided, the user is prompted to supply a physical/service address before proceeding And if GPS is available, it is used to disambiguate the county and is reflected in the contributing factors And any detected address conflict is flagged in the UI and included as a contributing factor
Jurisdiction Rules Engine & Court Directory Sync
"As an attorney practicing across counties, I want the system to apply the correct venue rules and up-to-date court information so that my filings are accepted the first time."
Description

Encode venue selection logic for common consumer matters, mapping locations to the correct court and division with parameterized rules (e.g., residence, transaction county, amount thresholds). Provide an API to evaluate candidates, return a ranked recommendation, and include rationale text suitable for audit notes. Nightly synchronize an authoritative court directory (names, addresses, divisions, e-filing eligibility, service requirements), with versioning, effective dates, and rollback. Expose rule and directory updates to the UI when changes could affect open matters.

Acceptance Criteria
API Venue Evaluation and Ranked Recommendation
Given a valid request with matter_type, amount_in_controversy, residence_county, transaction_county, and candidate_locations When POST /api/jurisdiction/evaluate is called Then respond 200 with a non-empty recommendations array sorted by rank ascending, each item including court_id, court_name, division, rank (>=1), rationale_text (<=500 chars), rule_version_id, and directory_version_id And Then the first item has rank=1 and represents the recommended venue And Then identical inputs produce identical outputs across repeated calls
Rule Engine Parameterized Logic and Division Mapping
Given rules configured with parameters including residence_county, transaction_county, incident_county, amount_in_controversy thresholds, and plaintiff_is_corporate When evaluating payloads that exercise each branch and boundary condition (below, at, above thresholds; conflicting counties) Then the selected court and division match the configured rule outcomes for every case And Then precedence rules (e.g., residence over transaction when specified) are honored consistently
Nightly Court Directory Synchronization and Versioning
Given the system time reaches 02:00 UTC and the upstream directory is reachable When the nightly sync job runs Then changes are detected via checksum/diff, and a new directory_version is created only if differences exist And Then each changed court record persists before/after snapshots, effective_start is set on the new version, and effective_end is set on the superseded version And Then the job completes within 15 minutes and records a success/failure log entry
Rollback to Prior Directory Version
Given at least one prior directory_version_id exists When a rollback to a specified directory_version_id is requested by an authorized actor Then that version becomes the current effective directory for all subsequent evaluations And Then an immutable audit log records who performed the rollback, timestamp, version_from, version_to, and reason And Then no court records are deleted during rollback, and a forward restore to the superseded version remains possible
UI Exposure of Impactful Rule/Directory Changes
Given a rules or directory update would alter the recommended court/division for one or more open matters When the change is detected post-sync Then within 60 minutes the UI displays an alert with count of impacted matters and a list showing previous vs new recommendation per matter with a link to review And Then no alert is shown if recommendations for open matters are unchanged And Then dismissed alerts persist their resolved state and only reappear for new changes
Rationale and Rule Traceability in API Response
Given an evaluation result is generated When the API responds Then each recommendation includes rationale_text of 1–3 sentences (50–300 characters) explaining the decision in human-readable language and referencing the applied rule by name or citation And Then rule_id, rule_version_id, directory_version_id, and effective_date_used fields are included for auditability And Then rationale_text contains no code, keys, or PII beyond counties and amounts provided in the request

Form Sync Live

Always pulls the latest court‑mandated forms for the detected venue and safely remaps fields when forms change. Get deprecation alerts, side‑by‑side diffs, and one‑click migration of your templates so drafts stay compliant without manual rework. Eliminates outdated packets and last‑minute scramble before filing.

Requirements

Venue-Aware Form Sync
"As a solo consumer-law attorney, I want Briefly to automatically fetch the latest forms for my case’s venue so that my drafts are always compliant without me searching court sites."
Description

Automatically detects the filing venue (jurisdiction, court, division) from matter intake data and continuously synchronizes the latest official, court-mandated form packets from authoritative sources. Implements connectors to court APIs and resilient scraping where APIs are unavailable, with scheduled pulls and on-demand refresh, caching, rate limiting, and checksum validation. Normalizes forms into a consistent metadata model (source, version/revision ID, effective/deprecation dates, language, file type) and maintains a local read-only mirror to ensure availability. Integrates with Briefly’s intake pipeline so assembled drafts always reference the most current form set for the detected venue without manual lookup.

Acceptance Criteria
Venue detection from intake resolves to authoritative venue ID
Given a matter intake with jurisdiction, court, and division fields (or a filing address) and an up-to-date court directory When the venue detection service runs on the intake Then it resolves a single authoritative venue_id within 300 ms And the match confidence is >= 0.95; otherwise the matter is flagged "Needs Venue Confirmation" and no form sync is attempted And the resolution persists required source identifiers (e.g., court_code) on the matter record And an audit log records inputs, resolved venue_id, confidence score, and timestamp
Nightly scheduled sync normalizes latest forms for a venue
Given a configured sync cadence of every 24 hours per venue When the scheduler triggers for a venue Then the system queries the authoritative source API using If-None-Match/If-Modified-Since headers and respects per-host limits And only forms changed since the last successful sync are downloaded; 304 responses are skipped And each downloaded form is normalized with fields: source, source_url, venue_id, form_id, version_id, revision_id, effective_from, deprecated_on, deprecates_version_id, language_code, file_type, file_size_bytes, checksum_sha256 And normalized records are stored and flagged "current" if effective_from <= now and (deprecated_on is null or > now) And a sync report is saved with counts (checked, downloaded, updated, unchanged, failed) and start/end timestamps
On-demand refresh respects cache freshness and rate limits
Given a user initiates an on-demand refresh for a venue via UI or API When the refresh request is processed Then if the last successful sync is within a 6-hour freshness window, the system serves from cache and skips network calls And if outside the freshness window, network calls proceed with a default 30 requests/minute per-host limit and exponential backoff on 429/503 (1s, 2s, 4s, ... up to 32s) And the user receives a result within 5 seconds indicating new/updated forms, counts, and any errors And repeated refresh requests for the same venue within 60 seconds are deduplicated to a single running job
Checksum integrity and version metadata enforcement
Given a form file is downloaded from a source When it is stored in the mirror Then a SHA-256 checksum is computed and compared to any source-provided hash; on mismatch, retry up to 3 times then mark failed and alert And mark the file available only if checksum verification passes and the file type matches declared metadata And capture version metadata: version_id, revision_id, effective_from, deprecated_on, deprecates_version_id And ensure exactly one version per form_id per venue is flagged as "current" at any time
Fallback scraping activates when API is unavailable
Given a venue with no API or an API returning 5xx/timeouts for 3 consecutive attempts When a scheduled or on-demand sync runs Then the scraper fetches from the configured court web pages using maintained selectors/sitemaps And scraping adheres to robots.txt and per-host throttling (max 10 requests/minute) with randomized jitter And if selector failures/DOM diffs are detected, halt updates for that venue, raise a deprecation/attention alert, and retain last known current forms And generate a side-by-side metadata diff (filenames, sizes, dates) between last and current crawl and attach it to the sync report
Local read-only mirror serves during source outages
Given the authoritative source is unreachable or returns errors When document assembly or preview requests a court form for the detected venue Then the request is served from the local read-only mirror with p95 fetch latency <= 200 ms And if the mirrored form set is older than 7 days, display a stale warning and prompt for refresh while serving last known current forms And mirror files are immutable; any modification attempt is blocked and logged And mirror availability is >= 99.9% monthly with outages logged and alerted
Intake-to-assembly uses current venue form set
Given a matter has a detected venue and the latest sync has completed (scheduled or on-demand) When Briefly assembles drafts for the matter Then the assembly references the "current" form versions for that venue at assembly time; if none are current, fail with a user-facing error including venue and form IDs And template mappings pointing to deprecated version_ids are auto-remapped when field names are unchanged; otherwise flag the draft for migration and prompt the user And the assembly log records venue_id, form_ids, version_ids used, and the sync timestamp used to resolve "current"
Form Versioning & Integrity Verification
"As a practitioner, I want each draft tied to a specific verified form version so that I can prove compliance if the court questions my filing."
Description

Maintains a complete, queryable version history for every synced form, including revision number, effective and deprecation dates, publisher source URL, and cryptographic checksums/signature verification where available. Supports concurrent availability of old and new versions during transition windows and enforces selection of the correct version based on filing date and venue rules. Provides deterministic rollback to previous versions if a new release is rescinded by the court. Exposes version metadata to assembly, preview, and export services, ensuring every generated document is traceable to a specific form version with integrity proof.

Acceptance Criteria
Persist Complete Version Metadata on Form Sync
Given a new or updated court form is detected for a venue When the sync job downloads the artifact and metadata Then a version record is created or updated with: form_id, revision_number, effective_date, deprecation_date (nullable), publisher_source_url, checksum_sha256, signature_verification_status, retrieved_at And the stored artifact’s computed SHA-256 equals checksum_sha256 And signature_verification_status is 'Verified' when a valid publisher signature is provided and trusted, else 'Not Available' when none is provided, or 'Failed' when verification fails And the version is queryable by form_id and revision_number within 1 second for 10k records
Block Promotion on Integrity Failure
Given an updated form artifact is downloaded When checksum validation fails or signature verification returns 'Failed' Then the version status is set to 'quarantined' and not marked 'available' And no assembly, preview, or export service can reference this version And an alert event 'integrity_failed' is emitted within 60 seconds with form_id, revision_number, and failure_cause
Concurrent Availability and Auto-Selection by Filing Date
Given an old version Vo has a deprecation_date in the future and a new version Vn has an effective_date on or before today When a user assembles a document with a specified filing_date Then both Vo and Vn are available until Vo.deprecation_date And the system auto-selects the version applicable to the filing_date per venue rules And attempts to select a non-applicable version are blocked with a validation error citing the rule
Deterministic Rollback of Rescinded Release
Given version Vn is marked 'rescinded' by the court When an administrator triggers rollback Then all templates and mappings referencing Vn are atomically switched to the prior stable version Vn-1 And subsequent assemblies immediately use Vn-1 without manual intervention And an immutable audit log entry is recorded with actor, timestamp, form_id, from_version, to_version, and affected_template_ids
Expose Version Metadata to Downstream Services
Given an assembly, preview, or export operation is requested When the operation completes Then the API and UI response include: form_id, revision_number, effective_date, deprecation_date, publisher_source_url, checksum_sha256, signature_verification_status And the generated file embeds the same metadata in a standard location (e.g., PDF XMP or file manifest) And GET /forms/{form_id}/versions/{revision_number} returns the same metadata and integrity status
Traceability of Generated Documents to Specific Form Version
Given a generated document is stored or shared When its embedded or attached metadata is inspected Then it resolves to a single form_id and revision_number And the recorded checksum matches the checksum of the archived form artifact And a provenance chain is available showing sync_run_id, source_url, and verification status
Reproducible Output With Fixed Version
Given identical intake data, template mapping, and a pinned form version When assembly runs twice in the same environment Then the binary outputs are byte-identical And any discrepancy results in a failed build with a diff report and build identifiers
Schema Diff & Auto-Remap Engine
"As a solo attorney, I want fields to be safely auto-remapped when forms change so that I don’t spend hours fixing templates after every revision."
Description

Parses each form release into a structured field schema (names, labels, types, constraints, positions) and computes diffs against prior versions to detect added, removed, and modified fields. Uses semantic matching, label normalization, synonyms (e.g., Petitioner/Plaintiff), layout heuristics, and Briefly’s field taxonomy to auto-remap existing template bindings with confidence scoring. Applies safe defaults for breaking changes, flags low-confidence mappings for review, and preserves conditional logic. Integrates with assembly to validate sample matters post-remap, reporting unmapped or invalid fields before migration is finalized.

Acceptance Criteria
Diff Computation for Sequential Form Releases
Given a prior form schema S0 and a new release schema S1 with known changes (2 fields added, 1 removed, 3 modified: label/type/constraint), When the engine parses both releases and computes the diff, Then the diff output lists exactly 2 added, 1 removed, and 3 modified fields with no false positives or negatives. And each modified field entry includes before/after for name, label, type, constraints, and position coordinates. And each diff entry includes a stable field identifier or matching rationale (e.g., semantic/positional) and the change reason code. And the diff is serialized to JSON conforming to the engine’s diff schema with mandatory keys [id, changeType, before, after, rationale, position]. And the diff computation completes in ≤2 seconds for forms with ≤500 fields on the reference environment.
Semantic Auto-Remap Using Synonyms and Label Normalization
Given a template bound to S0 and a new schema S1 where labels change via synonyms (e.g., Plaintiff→Petitioner, Defendant→Respondent, DOB→Date of Birth), When the auto-remap runs, Then existing bindings are reassigned to the correct S1 fields using semantic matching and normalized labels. And auto-applied mappings have confidence ≥0.90 and zero incorrect mappings above that threshold on the synonym fixture set. And where multiple candidates exist, the selected target maximizes confidence and is consistent with Briefly’s field taxonomy and layout heuristics (section proximity and page position). And the engine produces a mapping manifest including source field id, target field id, confidence score, and rationale components (semantic, label, taxonomy, layout) for each remapped binding.
Confidence Thresholds and Review Workflow
Given confidence thresholds of High ≥0.90, Medium 0.60–0.89, Low <0.60, When auto-remap completes, Then High-confidence mappings are auto-applied. And Medium-confidence mappings are not applied and are queued for human review with top-3 candidate targets and their scores. And Low-confidence mappings remain unmapped and are flagged as blocking until resolved. And the summary report lists counts by confidence bucket and provides a deterministic total equal to the number of changed or impacted bindings. And no mapping outside the High bucket is auto-applied.
Preservation of Conditional Logic and Dependencies
Given a template in S0 with conditional logic (visibility rules, derived fields, and cross-field validations) referencing S0 field identifiers, When the remap is applied to migrate to S1, Then all conditional expressions are updated to reference the correct S1 fields without altering logic semantics. And evaluation of a provided truth table covering all rule branches yields identical outcomes before vs. after remap. And no broken references remain (0 missing field references) and the rule graph remains acyclic. And a logic migration report enumerates each updated reference with old→new mapping and confidence, with 0 updates below 0.90 confidence applied automatically.
Post-Remap Assembly Validation and Reporting
Given a sample set of ≥10 representative matters with complete data for S0, When the engine assembles drafts against S1 using the remapped template, Then all assemblies complete with 0 critical errors (unmapped required fields, invalid types, or failed constraints). And any non-critical warnings (e.g., optional field unmapped) are listed per matter with field identifiers and suggested fixes. And if any critical errors are detected, the migration is blocked from finalization and a consolidated report (CSV and JSON) is generated listing matter id, field id, error type, and remediation suggestion. And upon 0 critical errors across the sample set, the migration can be finalized and the manifest is versioned and stored with checksum.
Safe Defaults for Breaking Changes and Migration Blocking
Given S1 introduces new required fields with no viable mapping from S0, When auto-remap executes, Then safe defaults are applied per type policy (string="[REVIEW REQUIRED]", number=null, date=null) without auto-filling values that could be misleading. And such fields are flagged as blocking with explicit prompts for user input or manual mapping before migration finalization. And no existing S0 data is overwritten or lost; original template and data remain intact and reversible until finalization. And the finalization step is disabled while any blocking items remain >0 and enabled only when blocking count is 0, verified by a re-check run within the last 5 minutes.
Side-by-Side Diff Viewer
"As a user, I want a clear side-by-side view of what changed in a form so that I can quickly assess impact before approving migration."
Description

Provides an interactive UI to compare old and new form versions side-by-side (stacked on mobile), highlighting structural and field-level changes, including text edits, new checkboxes, instruction updates, constraints, and required/optional shifts. Supports toggling between visual form view and schema view, with overlays showing how existing template fields will map under the proposed remap. Includes sample-data preview to demonstrate the practical impact on a real matter and exportable change reports for records or team review.

Acceptance Criteria
Visual/Schema Toggle Stays In Sync Across Views
Given a detected venue with old version vA and new version vB selected When the user switches to Visual view Then both versions render side-by-side within 2 seconds at the 95th percentile and page/zoom are synchronized Given Visual view is active When the user toggles to Schema view Then both schemas render with node counts matching their respective sources and diffs mirror the same categories as Visual view Given a diff is selected in Schema view When the user switches back to Visual view Then the corresponding element is focused and highlighted on both versions within 300 ms Given the user has chosen a view mode for a specific form pair When the page is refreshed or reopened within 30 days Then the last chosen view mode is restored for that form pair
Accurate Structural and Field-Level Diff Highlighting
Given a controlled fixture set containing structural (page/section/field add, remove, rename, move) and content changes (text edits, checkbox option changes, instruction updates, constraint edits, required/optional shifts) When the diff is computed Then each change is correctly classified and highlighted with distinct color/icon per change type and the on-screen legend matches those encodings And precision ≥ 99% and recall ≥ 99% on the fixture set And clicking any listed change scrolls both versions to the corresponding element within 300 ms Given the user applies a filter for Required/Optional changes When the filter is active Then only those changes remain visible and the badge count equals the number of visible highlights Given a rename or move is detected When the user inspects the detail Then the old and new paths are displayed and lineage is preserved in the change details
Mapping Overlay Shows Proposed Template Remap Status
Given an existing template mapping for version vA and a proposed remap to vB When the mapping overlay is toggled on Then each template field is labeled as Unchanged, Remapped, or Needs Review and header counters reflect the totals Given a field labeled Needs Review When the user opens suggestions Then the top 3 candidate targets are shown with similarity scores and constraint compatibility indicators Given the overlay is visible When the user hovers or taps a mapping badge Then a connector indicates source→target and a tooltip shows source path, target path, and reason for remap/flag Given the overlay is toggled off When the user resumes navigation Then no mapping badges or connectors remain and frame rate does not drop compared to overlay-off baseline
Sample-Data Preview Reflects Real Matter Impact
Given a matter with sample data is selected When Sample Preview is enabled Then data populate both old and new versions according to each version's constraints without persisting any changes to the matter Given Sample Preview is enabled When constraint violations occur under the new version Then a panel lists each violation with field path, rule violated, and suggested fix, and the violation count equals the number of highlighted fields Given a required→optional or optional→required shift causes data gaps When the user views the summary Then a non-blocking warning shows total affected fields and provides quick-jump links to each Given Sample Preview is disabled When the user returns to the viewer Then all sample data and markers are cleared and forms display their neutral state
Exportable Change Report with Metadata and Detail
Given a computed diff exists When the user exports the change report Then PDF and CSV files are generated within 10 seconds at the 95th percentile and filenames include venue, form ID, old/new versions, and ISO timestamp Given the PDF report is opened When the user reviews contents Then it contains summary counts by change type and a detailed table including: change type, element path, old value, new value, required/optional shift, and constraint deltas Given the CSV report is opened When parsed by a spreadsheet or script Then it contains one row per change with machine-readable fields and a JSON column for complex constraint deltas Given the same inputs are re-exported When exports are compared Then outputs are deterministic (no ordering or value drift)
Mobile Stacked View Preserves Usability and Context
Given viewport width ≤ 768 px When Visual view is active Then the old version is stacked above the new version with sticky headers and selecting a diff in one scrolls the other to the paired element Given mobile Visual view is active When the user interacts with diff badges Then tap targets are ≥ 44×44 px, text remains legible at 320 px width, and no horizontal scrolling is required for main content Given mobile Schema view is active When code blocks render Then long lines wrap without overflow and selection remains synchronized when toggling back to Visual view Given typical mobile hardware When panning or zooming Then median frame rate is 60 FPS and input latency is < 150 ms
Performance and Stability Under Large Diffs
Given a form pair containing ≥ 1000 elements and ≥ 200 detected diffs When the viewer loads Then time-to-interactive is ≤ 3 seconds (desktop p95) and ≤ 5 seconds (mid-tier mobile p95) and steady-state memory usage is ≤ 300 MB in-browser Given the user filters, searches, or expands nodes When interactions occur Then median interaction latency is < 150 ms and no frame drops cause visible jank Given a network failure occurs during report export When the export fails Then a retryable error message is displayed, no partial files are left on disk, and a telemetry event with error code is recorded
One-Click Template Migration
"As a solo attorney, I want one-click migration of my templates to new forms so that I stay compliant without manual rework."
Description

Automates end-to-end migration of user templates and packet definitions to the latest form version. Executes the auto-remap plan, runs validations against representative matters, and shows a pre-flight report of impacted templates and risks. Creates automatic snapshots for rollback, updates e-sign anchors and fill rules where applicable, and preserves custom styling/branding. Supports batch migration across multiple matters/venues with background processing and progress tracking, finishing with a compliance-ready summary.

Acceptance Criteria
One-Click Auto-Remap Execution
Given a workspace with templates and packet definitions bound to form version X and a newer version Y is available for the detected venue And an auto-remap plan is generated for X -> Y When the user initiates One-Click Migration Then the system retrieves version Y forms from the authoritative source and verifies file integrity via checksum And applies field ID remapping to all referenced templates and packets And performs updates atomically per template with no partial writes on failure And records a detailed migration log including per-item status (migrated, skipped, failed) and reason codes And completes with 0 blocking system errors and at least 95% of targeted items migrated successfully unless blocked by pre-flight rules
Pre-Flight Impact and Risk Report
Given a newer form version is detected for the venue When the user opens the pre-flight report Then the report lists all impacted templates/packets with side-by-side field diffs And flags deprecated fields and newly required fields And identifies unmapped or ambiguously mapped fields as blockers And assigns a risk score per template with rationale And provides deprecation alerts for forms being retired within 30 days And allows export of the report (CSV/PDF) And disables One-Click Migration until blockers are resolved or explicitly acknowledged by the user with audit tracking
Validation Against Representative Matters
Given representative matters are auto-selected (last 20 per venue and matter type) or user-specified When the system runs validation simulations on the new form version Then all required fields for each matter are populated or flagged with specific missing-rule messages And 0 blocking validation errors occur across the sample set And total warnings per template do not exceed a configured threshold (default <= 3) And the validation pass rate, errors, and warnings are summarized with drill-down to each matter And validation results are stored and linked in the audit log
Automatic Snapshot and One-Click Rollback
Given a migration is about to start When the system creates a pre-migration snapshot Then the snapshot captures templates, packet definitions, field mappings, e-sign anchors, and styling/branding settings And the snapshot is immutable and timestamped with a checksum When the user triggers rollback for any migrated scope Then the system restores all affected assets to the snapshot state with no residual migrated artifacts And post-rollback checksums match the snapshot checksums for restored assets And the rollback event is recorded in the audit log with initiator, time, and scope
E-Sign Anchors and Fill Rules Update
Given templates contain e-sign anchors and fill rules bound to form version X When migration to version Y is executed Then all e-sign anchors are re-bound to the correct pages and fields using IDs/text proximity And no orphan anchors remain (count == 0) And anchor positions deviate by no more than 5 px in X/Y on letter/A4 outputs And fill rules are updated to reference new field IDs with equivalent conditions And a post-migration e-sign validation passes for all migrated templates
Preservation of Custom Styling and Branding
Given templates include firm-specific fonts, colors, logos, headers/footers, and margins When migration completes Then generated drafts retain the same branding assets (logos, colors, fonts) as pre-migration outputs And header/footer images and margins remain unchanged within ±2 pt And no unintended CSS/theme setting changes are introduced And a visual diff of pre- vs post-migration drafts shows only underlying court form layout changes, with zero changes to branding layers
Batch Migration, Background Processing, Progress, and Compliance Summary
Given the user selects multiple matters, templates, or venues for migration When the user starts batch migration Then jobs are queued and executed in the background with safe concurrency limits And the UI shows per-scope progress (% complete, items remaining, ETA) and supports pause/resume/cancel And failures trigger automatic rollback for only the affected items, while successful items remain applied And users receive completion/failure notifications And on completion a compliance-ready summary is generated that includes from/to form versions per venue, validation pass/fail counts, unresolved risks/warnings, items requiring manual action, and a signed audit log with timestamps and checksums
Deprecation Alerts & Smart Notifications
"As a busy practitioner, I want timely, actionable alerts about form changes so that I can update in advance and avoid failed filings."
Description

Monitors synced sources for new releases and deprecations, then triggers configurable notifications (in-app, email, optional SMS) with severity based on effective dates and filing deadlines. Sends proactive reminders at T-30/T-7/T-1 days and upon detection, includes impacted matters/templates, and deep links to the diff viewer and migration flow. Supports digesting multiple updates, snooze/acknowledge, and preferences per venue/form category to minimize noise while preventing last-minute scrambles.

Acceptance Criteria
Immediate Alert on Deprecation/Release Detection
Given a new form release or deprecation is detected for a synced venue When the system ingests the update Then an in-app notification card is created within 60 seconds And an email notification is dispatched within 5 minutes And an optional SMS notification is queued within 5 minutes if the user enabled SMS And the notification includes venue, form name/ID/version, effective/deprecation date, severity tag, and counts of impacted templates and open matters And the alert includes deep links to the diff viewer and migration flow that resolve with the correct form/version context
Severity Determination by Effective Date and Filing Deadlines
Given an update with effective date D and a set of impacted matters with filing deadlines When severity is calculated Then severity is High if D is within 7 days from now OR any impacted matter has a filing deadline within 7 days And severity is Medium if D is 8–30 days from now And severity is Low if D is more than 30 days from now And severity defaults to Medium if D is unknown And deprecations effective immediately are marked High
Proactive Reminder Cadence at T-30/T-7/T-1
Given an update that is not acknowledged and has at least one impacted item not migrated When the calendar reaches 30, 7, or 1 days before the effective date (user’s local time) Then a reminder is sent via each enabled channel And no duplicate reminders are sent within a 24-hour window And if all impacted templates/matters are migrated, no further reminders are sent And if detection occurs after T-30, only pending milestones (T-7/T-1) are scheduled And if detection occurs on or after T-1, a single immediate reminder is sent
Digest Aggregation of Multiple Updates
Given more than 3 updates are detected for a user within a rolling 24-hour window and digesting is enabled When notifications are generated Then a single daily digest is sent at 7:00 PM local time summarizing updates by venue and form category And individual notifications for those updates are suppressed except the immediate detection alert for High severity updates And the digest includes per-severity counts and totals of impacted matters/templates And the digest provides deep links that open filtered views for the listed updates
Accurate Impacted Items and Deep Link Resolution
Given a known dataset of matters and templates and a specific form update When the impacted items are computed Then the notification’s impacted list matches the backend query results with 100% precision and recall as of last sync And selecting an impacted matter link opens that matter view filtered to the affected form And selecting View Diff opens the correct form/version diff And selecting Migrate opens the migration flow with affected template(s) preselected and the correct target version
Snooze/Acknowledge Controls and Per-Venue/Category Channel Preferences
Given a user’s notification preferences per venue, form category, and channel When an update matches a disabled venue or category for a channel Then that channel is not used for that update And when SMS is disabled globally, no SMS is sent And given an unacknowledged update When the user acknowledges it Then all future reminders for that update are canceled but the record remains in notification history And when the user snoozes it for S days (1–14) Then reminders are paused during S and resume afterward And snooze and acknowledge states propagate across devices within 2 minutes
Compliance Audit Trail & Reporting
"As a solo attorney, I want a complete audit trail of form versions and migrations so that I can demonstrate compliance if challenged by the court or a client."
Description

Captures an immutable audit trail for every draft and migration: form source and version IDs, checksums, mapping version, user approvals, timestamps, and pre/post-migration validation results. Exposes searchable reports by matter, venue, date range, or form, with export to PDF/CSV for court inquiries or malpractice defense. Stores evidence of version-in-use at e-sign and at filing generation time, with retention controls consistent with legal hold and firm policy.

Acceptance Criteria
Immutable Draft and Edit Audit Logging
Given a user creates or updates a draft for a matter using detected venue forms When the draft is saved Then the system writes an append-only audit record containing matterId, draftId, userId, action (create/update), timestamp (UTC ISO-8601), venueCode, formSource, formVersionId, formChecksum, mappingVersion, clientIp, userAgent And the audit record is immutable; no role can update/delete it; attempts return 403 and are logged as security events And records are cryptographically chained via hash(prevHash + record) and the chain is verifiable via API/UI And p95 retrieval time for a single matter's audit history up to 1,000 events is <= 2s
Migration Event Logging with Validation Results
Given a form deprecation is detected and a one-click migration is initiated for a template or draft When the migration job runs Then an audit record is stored with migrationId, sourceFormVersionId, targetFormVersionId, sourceChecksum, targetChecksum, mappingVersion, preValidationSummary {total, passed, warnings, failures}, postValidationSummary {total, passed, warnings, failures}, unmappedFields[], defaultedFields[], diffId, status (pass/fail), startedAt, completedAt And if approval is required, an approval record captures approverUserId, decision (approved/rejected), reason (required on reject), timestamp And migration audit records are immutable and included in the cryptographic chain And the side-by-side diff screen displays diffId whose values match the stored audit record
Version-in-Use Evidence at E-Sign and Filing
Given an e-sign envelope is created for a matter Then an evidence record is captured including envelopeId, documentIds, formSource, formVersionId, formChecksum, mappingVersion, signerList, createdAt, and fileHashes of rendered PDFs And Given a filing packet is generated Then an evidence record is captured including filingId, includedFormVersionIds, checksums, generationTimestamp, and outputFileHash And both evidence records are linked to the matter and remain retrievable even after upstream forms change And exporting the matter evidence shows the exact versionIds and checksums used at e-sign/filing time
Searchable Compliance Reports and Access Control
Given a user with role Compliance.Reporter opens Compliance Reports When they filter by any combination of matterId, venue, dateRange (UTC), and formId Then only matching audit and evidence records are returned and the result count is shown And users without permission receive 403, and permitted users only see matters within their access scope And results support sorting by date, matter, form, and venue, and pagination up to pageSize=200 And p95 query latency is <= 5s for result sets up to 100,000 records And invalid filters return descriptive validation errors without executing the query
Export to CSV/PDF with Provenance
Given a filtered compliance report with up to 100,000 rows When the user exports to CSV or PDF Then the export includes all visible columns plus provenance: generatedAt (UTC), filtersApplied, requesterUserId, resultCount, reportChecksum And CSV conforms to RFC 4180 (quoted values, UTF-8, CRLF) and PDF is searchable text And exports estimated >30s are queued; the user is notified when ready; the download link expires after 7 days And exported row count exactly matches the on-screen count and spot-checks match underlying records
Retention Policy and Legal Hold Enforcement
Given a firm retention policy (e.g., 7 years) is configured and legal hold can be toggled per matter by role Compliance.Admin When records exceed the retention period and no legal hold is active Then records are purged by a scheduled job and a purgeReceipt (recordType, count, dateRange, jobId, performedAt, actor=system, hash) is stored immutably And when legal hold is active, no purge occurs; attempts are logged and the UI indicates hold status And changes to retention policy and legal hold state are audited with userId, oldValue, newValue, timestamp
Tamper Detection and Alerting
Given a daily integrity verification job executes When any audit chain break or checksum mismatch is detected Then the system flags the affected matter, raises a High severity alert to Compliance.Admin, and locks edits to related drafts until resolved And an incident report is generated with affected recordIds, firstBadHash, timeWindow, and is exportable And when no issues are found, a success receipt is stored with sample size and runtime metrics

Fee SmartCalc

Calculates exact filing fees, surcharges, and e‑file provider add‑ons per venue and case type—then auto‑fills fee waiver forms when thresholds or criteria are met. Totals flow directly into trust vs. operating via Trust Split Guard with clear client disclosures. Avoids under/overpayment, clerk rejections, and awkward refund calls.

Requirements

Jurisdictional Fee Matrix
"As a solo consumer-law attorney, I want accurate, venue- and case-type-specific fee totals so that I can avoid under/overpayment and clerk rejections."
Description

Implement a normalized, effective-dated data model that calculates total filing costs per jurisdiction, court/venue, case type, filing action, and service method. The matrix must account for base filing fees, tiered amounts (e.g., amount in controversy, number of parties), surcharges (technology, law library, indigent funds), per-page charges, service of process options, and e-filing vs. in-person differentials. Include provider add-ons and location-specific quirks (e.g., compulsory copy fees, alternative dispute fees). Support multi-filing bundles across venues, currency/rounding rules, and time-bound fee changes with versioning and audit logs. Provide an admin console for fee table maintenance, source citation, and change approvals. Expose a deterministic calculation API that returns line-item breakdowns and totals, and integrates with Briefly’s questionnaire, document assembly, and billing subsystems to prevent under/overpayments and clerk rejections.

Acceptance Criteria
Deterministic Fee Calculation and Itemized Breakdown
- Given a request specifying jurisdiction, venue/court, caseType, filingAction, serviceMethod, amountInControversy, party counts, page count, provider, and submissionDate within an active fee schedule version When the Calculation API is invoked with these parameters Then the response status is 200 and contentType is application/json - Given the same inputs and fee schedule version When the Calculation API is called repeatedly Then totalAmount, currency, roundingMode, calculationId, and the ordered lineItems are identical across calls - Given configured currency and rounding rules for the jurisdiction When lineItems are computed Then each extendedAmount and totalAmount respect the configured fractionalDigits and roundingMode - Given configured components (base fees, tiered fees by amount/party count, surcharges, per-page charges, service-of-process, e-filing vs in-person differentials, provider add-ons) When the calculation runs Then the response includes lineItems for each applicable component with fields: code, label, quantity, unitAmount, extendedAmount, category, sourceCitationId - Given lineItems are returned When totals are derived Then sum(lineItems.extendedAmount) equals totalAmount and totalsByCategory match the sum of their respective lineItems
Effective-Dated Versioning and Audit Traceability
- Given fee version v1 effective through 2025-09-30 and fee version v2 effective starting 2025-10-01 for the same fee key When submissionDate = 2025-09-30 Then the calculation uses v1 (feeVersionId=v1) and totals reflect v1 values - Given the same inputs When submissionDate = 2025-10-01 Then the calculation uses v2 (feeVersionId=v2) and totals reflect v2 values - Given a calculation response When inspected Then it includes feeVersionId, effectiveDateApplied, and for each lineItem a sourceCitationId that maps to a citation record - Given audit logging is enabled When any fee version is created, modified, approved, or retired Then an audit record is written with actorId, action, timestamp, feeKey, versionId, and a structured before/after diff
Location-Specific Quirks, Per-Page, and Filing Method Differentials
- Given a jurisdiction configuration where inPerson filings require compulsory copy fees of $0.50/page after 1 included copy When a filing is submitted in-person with 3 copies and 12 pages Then the calculation includes a copyFee lineItem with quantity = 2 copies * 12 pages and unitAmount = 0.50 - Given a venue rule that adds an ADR surcharge of $25 for Limited Civil when amountInControversy is between $10,000 and $25,000 When the caseType and amountInControversy meet the rule Then an adrSurcharge lineItem is present with extendedAmount = $25 and correct sourceCitationId - Given an e-filing differential of $2.00 for the same filing action versus in-person When serviceMethod = E-Filing Then a filingMethodDifferential lineItem is included for $2.00; and when serviceMethod = In-Person, that lineItem is omitted - Given a per-page charge of $1.00 after the first 10 pages When pageCount = 18 Then a perPage lineItem is included with quantity = 8 and unitAmount = $1.00
Multi-Filing Bundle Calculation with Trust Split Guard Allocation
- Given a bundle containing two filings (A and B) in different venues with their own parameters When the Calculation API is invoked with a bundleId and per-filing inputs Then the response includes perFiling breakdowns and a bundleTotals object; and bundleTotals.totalAmount equals the sum of perFiling totalAmount - Given Trust Split Guard configuration marking government/clerical fees as trust and provider add-ons as operating When lineItems are returned per filing Then totalsTrust and totalsOperating are computed per filing and for the bundle, matching the sum of lineItems where trust=true/false - Given client disclosure templates are configured for each fee code When the bundle calculation completes Then the response includes a disclosures array per filing containing the human-readable fee descriptions mapped from the lineItems - Given currency and rounding rules per venue When bundle totals are computed Then no rounding drift occurs: sum(perFiling rounded totals) equals bundle rounded total
Admin Fee Table Maintenance and Approval Workflow
- Given an authorized admin edits a fee table row When required fields (feeKey, effectiveStart, component type, amount/formula, sourceCitation) are missing Then the save is blocked with field-level errors and code VALIDATION_FAILED - Given an admin attempts to create a new version whose effective date range overlaps an existing version for the same feeKey and scope (jurisdiction, venue, caseType, filingAction, serviceMethod) When saving Then the save is blocked with code EFFECTIVE_RANGE_OVERLAP - Given a change is submitted When saved Then it enters Pending Approval state and is not used in calculations until Approved - Given a different approver reviews the change When Approve is clicked Then the version transitions to Active on its effectiveStart and an audit entry is recorded; when Reject is clicked, the change moves to Rejected and is excluded from calculations - Given a pending or active version When Preview Calculation is requested for a target submissionDate and inputs Then the admin console shows the itemized result and effective version that would apply
API Contract, Validation, and Error Handling
- Given the OpenAPI schema for the Calculation API When the API responds Then the response validates against the published schema version, including required fields (calculationId, feeVersionId, currency, roundingMode, totals, lineItems[] with code/label/quantity/unitAmount/extendedAmount/category/sourceCitationId) - Given a request missing required parameters (e.g., jurisdiction or caseType) When the API is called Then it returns 400 with an errors[] array containing machine-readable codes and fields, and no calculationId is issued - Given a request with invalid values (e.g., negative pageCount, unknown serviceMethod) When the API is called Then it returns 422 with code VALIDATION_FAILED and details per offending field - Given no fee configuration exists for the provided key and submissionDate When the API is called Then it returns 422 with code FEE_CONFIG_NOT_FOUND and includes the resolved feeKey and submissionDate in the error payload - Given a valid request When the API returns lineItems Then the lineItems are sorted by displayOrder ascending, then by code to ensure deterministic presentation
Waiver Eligibility Engine & Auto-Fill
"As an intake assistant, I want the system to determine fee-waiver eligibility and auto-fill the correct forms so that clients don’t pay fees they qualify to waive and filings aren’t rejected."
Description

Create a rules-driven engine that determines fee-waiver eligibility based on jurisdiction-specific criteria, including household size, income relative to FPL, public benefits participation, assets, and extraordinary expenses. Support full and partial waivers with explanations and confidence flags. Automatically select the correct waiver form per venue (e.g., state/county-specific affidavits), map questionnaire responses to fields and checkboxes, prefill sworn statements, and attach supporting documentation placeholders. Trigger e-sign workflows, include notary requirements when applicable, and insert the waiver packet into the assembled filing set. Provide localized thresholds, effective-dated rule versioning, and an admin UI for policy updates with source citations. Surface concise, plain-language guidance during intake to minimize rework and reduce clerk rejections.

Acceptance Criteria
Eligibility Determination and Confidence Output
Given jurisdiction=CA:Los Angeles County Superior Court and intake_date within an active rule effective period And household_size=3, gross_monthly_income=$2,000, public_benefits includes SNAP, liquid_assets=$500, extraordinary_expenses=$0 When the Waiver Eligibility Engine evaluates the case Then it returns decision="Full Waiver" with confidence="High" And explanation contains a plain-language rationale and at least one rule source citation URL and reference number And output includes rule_version_id and rule_effective_date used for the decision And processing_time <= 500 ms at P95 under normal load And re-evaluating with identical inputs returns an identical decision and confidence
Venue-Specific Form Selection and Auto-Fill
Given venue=IL:Cook County Circuit Court and decision in {Full Waiver, Partial Waiver} When forms are assembled Then the correct county/state-specific waiver affidavit and supplemental forms are selected based on venue and waiver type And 100% of required fields/checkboxes are populated from questionnaire data or marked "N/A" per form rules And sworn statements are prefilled with applicant name, date, venue, and decision type And notary block is included only if the venue rules require notarization And generated PDF passes form schema/validation checks and is flattened, e-file ready, and named "<client_last>_FeeWaiver.pdf"
E-Sign Workflow with Notary and Filing Packet Insertion
Given a waiver packet requiring client signature and venue rules that require notarization for affidavits When the packet is generated Then an e-sign request is sent to the client within 60 seconds with all signature/initial fields correctly placed And if notarization is required, a remote notary step is inserted before completion and notary seal fields are present And upon completion, the signed waiver packet is inserted into the assembled filing set in the configured order for the venue And an e-sign certificate of completion is attached to the packet And the packet passes e-file provider preflight checks for signatures and digital seals
Rule Versioning, Effective Dating, and Auditability
Given an admin updates the income threshold table with effective_date=2025-09-01 and provides a source citation URL When a case with intake_date=2025-08-31 is evaluated Then the engine uses the pre-update rule_version and records rule_version_id in the decision When a case with intake_date=2025-09-02 is evaluated Then the engine uses the new rule_version and records rule_version_id and effective_date And the admin change is logged with who, when, before/after diffs, and citation; publishing is blocked if citation is missing And admins can rollback to a prior version, after which subsequent evaluations use the restored rule_version
Plain-Language Intake Guidance and Error Prevention
Given a user enters income within ±10% of the FPL threshold or indicates participation in public benefits When the user advances past the income step Then an in-context guidance panel appears explaining eligibility in plain language, with required documents listed And the guidance text meets readability grade <= 8 (Flesch–Kincaid) and avoids defined legalese terms And analytics events record guidance_shown with jurisdiction and rule_version_id And proceeding to form assembly results in zero missing-required waiver fields attributable to intake data
Partial Waiver Calculation and Trust Split Integration
Given the engine returns decision="Partial Waiver" with waiver_percent=50% When Fee SmartCalc recomputes the filing costs Then only fee-waivable categories are reduced by 50%, non-waivable provider add-ons remain unchanged And Trust Split Guard updates trust vs operating allocations accordingly and updates the client disclosure to reflect the adjusted totals And the payment request shows the reduced payable amount and matches the recomputed totals within $0.01
Supporting Documentation Collection and Placeholders
Given jurisdiction rules require proof_of_income and benefits_award_letter for waiver eligibility When eligibility is determined as Full or Partial pending documentation Then a checklist of required documents is generated with per-item descriptions and accepted file types {PDF, JPG, PNG} And the upload control enforces max file size <= 10 MB per file and blocks disallowed types And if a required document is not uploaded, a labeled placeholder page is inserted in the packet and the filing is blocked until satisfied or an allowed exception is recorded per rule And the final packet indexes each attachment with captions matching venue conventions
Trust Split Guard Integration
"As a practitioner, I want filing fees and pass-through charges to be automatically split to trust with clear client disclosures so that I stay compliant and avoid awkward refund calls."
Description

Integrate SmartCalc outputs with Trust Split Guard to automatically route pass-through fees and surcharges to trust while directing earned service fees to operating. Generate itemized line items with GL mappings, preserve client-money designations (IOLTA compliance), and display clear disclosures and consent language within the engagement letter and payment screens. Prevent markup of court fees, handle refunds and voids with proper trust accounting, and reflect allocations in invoices and ledgers. Provide a preview of the split before collection, support batch disbursements to courts/providers, and emit events for reconciliation and reporting. Ensure full traceability from calculation to payment and disbursement, reducing compliance risk and refund friction.

Acceptance Criteria
Auto-Routing SmartCalc Fees to Trust vs Operating
Given SmartCalc returns fee line items with a designation of Pass-Through or Earned When a payment intent is created for the matter Then the system allocates the sum of Pass-Through items to Trust and the sum of Earned items to Operating with 2-decimal precision And the displayed total equals Trust allocation + Operating allocation exactly to the cent And the ledger creates two pending entries: Trust (client money) and Operating (firm income) with correct account references And the invoice preview shows two sections labeled Trust (Pass-Through) and Operating (Earned) with matching subtotals
Itemized Line Items with GL Codes and IOLTA Designations
Given SmartCalc produces an itemized breakdown When the invoice and ledger entries are generated Then each line item includes: description, amount, GL account code, tax code (if any), and money designation (Trust or Operating) And Trust-designated items are flagged as client funds (IOLTA) and Operating-designated items as firm income And exporting to the accounting system preserves GL codes and designations without data loss And validation fails and blocks posting if any line item is missing GL code or designation
Client Disclosures, Split Preview, and Explicit Consent Capture
Given a payment is initiated from an engagement letter or payment screen When the split preview is displayed Then the client sees itemized Pass-Through vs Earned amounts, total due, and clear disclosure language stating no markup of court fees And the client must provide explicit consent (checkbox + timestamp) before payment authorization is enabled And the exact disclosure text and split snapshot (amounts and line items) are stored immutably with a hash and associated to the payment ID And the engagement letter PDF and client receipt include the disclosure and split snapshot
Prevent Markup of Court and Provider Pass-Through Fees
Given SmartCalc base calculations for court/provider fees are returned When staff attempt to modify Pass-Through amounts Then increases above SmartCalc-calculated totals (inclusive of provider-required add-ons) are blocked And permitted adjustments are limited to: (a) applying a fee waiver = 0, or (b) moving items between Earned/Pass-Through only if criteria rules allow and are logged And any difference between displayed Pass-Through sum and SmartCalc baseline triggers an error with details and prevents posting And discounts may only reduce Earned items unless a valid fee waiver is attached to the Pass-Through line
Refunds and Voids with Proper Trust Accounting
Given a payment with Trust and Operating allocations exists When the payment is voided before capture Then no funds are posted and all pending ledger entries are removed with an audit record When a captured payment requires a partial or full refund Then refunds of Trust-designated amounts are returned from Trust to the original payment instrument and Operating-designated amounts from Operating, preserving segregation And all reversing entries are posted with references to original transaction IDs and line items And the client invoice and ledgers reflect the refund and updated balances within one minute And events for refund_initiated and refund_completed are emitted with correlation IDs
Batch Disbursements to Courts and Providers from Trust
Given multiple matters have undistributed Pass-Through balances When a batch disbursement run is initiated for a venue/provider Then the system groups items by client and payee, preventing cross-client commingling And validates available client Trust balances before disbursement, skipping any with insufficient funds and logging reasons And generates remittance artifacts (PDF and CSV) listing matter, line item, amount, and reference numbers And posts trust-to-payee disbursement entries and marks items as Disbursed with immutable timestamps And emits disbursement_created events per item and one batch_summary event
End-to-End Traceability and Reconciliation Events
Given a SmartCalc result leads to a payment, allocation, and disbursement When each lifecycle step occurs (calculated, allocation_created, payment_authorized, payment_captured, invoice_posted, disbursement_created, refund_completed) Then an event is emitted within 3 seconds containing matter ID, client ID, correlation ID, line-item IDs, GL codes, amounts, and timestamps And an audit trail view can reconstruct the full chain from calculation to disbursement/refund using the correlation ID And a reconciliation report API returns totals per designation (Trust vs Operating) that match ledger balances to the cent And any missing or out-of-balance event causes the reconciliation endpoint to return a non-success status with diagnostics
E-File Provider Pricing Sync
"As a legal operations manager, I want SmartCalc to pull current e-filing provider fees automatically so that totals reflect real-time add-ons."
Description

Integrate with leading e-filing providers to ingest add-on pricing per venue, case type, document type, and service option via API, with effective-dated versioning and change detection. Normalize provider fee structures to SmartCalc’s schema, validate against known ranges, and fall back to configurable tables when APIs are unavailable. Implement health checks, rate limiting, and alerting for stale data. Provide an admin view to compare provider-reported fees with current tables, approve updates, and annotate source links. Expose synchronized add-ons to the calculation API so totals reflect real-time provider charges, minimizing surprises at submission.

Acceptance Criteria
Provider Pricing Ingestion with Effective-Dated Versioning
Given valid provider API credentials and endpoints When the scheduled pricing sync runs for a provider Then the system ingests all fee records for venue, case type, document type, and service option And stores each record with effective_from and effective_to dates, a monotonically increasing version, and a content checksum And creates a new version only when any fee amount, fee type, or applicability has changed compared to the current active version And marks newly detected changes as Pending Approval without activating them And completes ingestion for up to 10,000 fee rows per provider within 2 minutes with zero duplicate active versions
Fee Structure Normalization to SmartCalc Schema
Given provider-specific fee payloads including flat, percentage, tiered, and per-page structures When normalization runs on ingested records Then 100% of records map to SmartCalc fields: fee_type, basis (flat|percent|tiered|per_page), amount_or_rate, currency, applies_to, provider, venue_id, case_type_id, doc_type_id, service_option_id And percent fees are represented as decimal rates with up to 4 decimals; currency is USD; amounts are rounded to 2 decimals using half-up And unknown or unsupported fee structures are flagged as Unmapped, excluded from activation, and listed in the admin view And key resolution maps provider-specific identifiers to internal IDs using the mapping table with no orphaned references
Admin Approval, Diff, and Source Annotation
Given new Pending Approval fee versions exist When an approver with the Pricing Approver role opens the admin comparison view Then differences between current and pending fees are shown side-by-side with filters for provider, venue, and case type And the approver can approve, reject, or defer individual rows or bulk selections And approval requires entering a source URL or a verification note; both are stored with the version And upon approval, the pending version becomes Active immediately, and the prior active version is closed with effective_to set to approval timestamp And all actions are audit-logged with user, timestamp, action, and before/after values
Fallback on Provider API Unavailability with Stale-Data Alerting
Given the provider API returns 4xx/5xx errors or times out, or no successful sync has occurred within the freshness window When a calculation request or sync attempt occurs Then the system uses the last-known Active provider fee versions if last_success_at <= 24 hours ago And if older than 24 hours, falls back to the configured static fee tables for affected providers/venues only And emits alerts: Warning at 24 hours without success, Critical at 72 hours, with provider name and impacted venues And surfaces a STALE badge and last_success_at in the admin view until a successful sync completes And all fallbacks are included in telemetry with counts per provider per day
Rate Limiting, Retry Policy, and Health Checks
Given provider rate limits and transient errors When the sync service calls provider APIs Then it honors Retry-After headers, caps concurrency per provider to 5 req/s, and uses exponential backoff with jitter for up to 3 retries on 429/5xx And it does not retry on hard 4xx (except 408/409/429) and records the terminal error And fewer than 1% of requests per sync window result in unhandled failures; zero uncaught exceptions crash the job And a health endpoint exposes per-provider status (UP|DEGRADED|DOWN|STALE), last_sync_at, last_success_at, last_error, and rate-limit metrics, returning in <200 ms And health status is GREEN only if last_success_at <= 24 hours and error rate <1%
Calculation API Uses Synchronized Add-Ons in Totals
Given approved Active provider add-on fee versions exist for a venue, case type, document type, and service option When the Calculation API is called with those inputs Then the response includes provider add-ons in the fee breakdown with fields: name, amount, fee_type, provider, version_id, effective_from, and data_source (live|static_fallback) And totals reflect the sum of provider add-ons plus court/filing fees, with Trust Split Guard designations for trust vs operating And newly approved versions are reflected in API responses within 60 seconds of approval And Pending Approval versions are never used unless the use_pending_in_sandbox flag is enabled, in which case they appear only in sandbox calls And responses include a data_staleness_days metric when data_source is static_fallback
Intake Questionnaire Fee Hooks
"As a client completing intake on my phone, I want to see clear fee estimates and simple questions so that I understand costs and provide the info needed to reduce or waive fees."
Description

Embed SmartCalc into the mobile-friendly intake so the questionnaire gathers only the additional data needed for venue-specific fee logic (e.g., amount claimed, number of defendants, service preference, benefit participation). Provide real-time, plain-language fee estimates with an explanation of each component and likely waiver outcomes. Use conditional branching to request evidence only when eligibility is probable, minimizing friction. Allow attorney override with reason capture and track differences between provisional and final totals. Ensure accessibility, bilingual copy support, and low-latency updates so clients understand costs before e-signing the retainer.

Acceptance Criteria
Venue-Specific Data Capture Minimization
Given the client selects a venue and case type When the questionnaire renders fee-related questions Then only the additional fields required by that venue/case type’s fee logic are displayed And no questions outside the mapped set for that venue/case type are shown And the total count of additional fee fields does not exceed the venue/case mapping And analytics log each displayed field ID for audit Given the client changes venue or case type When the questionnaire re-renders Then previously captured fee fields no longer applicable are cleared and not persisted And the flow re-branches without duplicate questions
Real-Time Itemized Fee Estimate
Given the client has entered or modified any fee-relevant input (e.g., amount claimed, number of defendants, service preference) When the input is debounced for 250 ms Then the itemized fee estimate updates within 300 ms of the debounce And each line item shows a label, amount in USD, and a plain-language explanation And the total includes filing fees, surcharges, and e-file provider add-ons And a waiver likelihood badge (Eligible/Likely/Unlikely) displays with a one-line rationale And a timestamp shows the last update time Given network latency exceeds 1 s or fee tables are temporarily unavailable When the estimate cannot be refreshed Then the UI shows a non-blocking fallback notice and the last known estimate with a "may change" flag
Conditional Evidence Request for Fee Waiver
Given the client’s responses indicate categorical eligibility or a computed waiver likelihood ≥ 70% When the waiver path is entered Then the questionnaire requests only the minimum evidence required by venue rules (e.g., income proof, benefit participation) And each evidence request specifies acceptable file types and size limits And the client can skip with a reason and resume later Given the waiver likelihood < 70% and no categorical eligibility When progressing through intake Then no evidence upload is requested And a brief explanation is shown that evidence is unnecessary at this time
Attorney Override with Audit Trail and Variance Tracking
Given an attorney is reviewing the calculated fees When the attorney overrides any fee component or total Then the system requires selection of a reason from a controlled list and an optional free-text note (max 500 chars) And the audit log records before/after amounts, user ID, timestamp, venue/case, and SmartCalc rules version And client-facing disclosures reflect the override And the difference between SmartCalc provisional and overridden total is displayed in amount and percentage Given the matter reaches filing confirmation When final actual fees paid are recorded Then the system stores the final total and calculates variance against the last provisional estimate And the variance is available in reporting and the case audit log
Trust Split Guard Integration and Client Disclosures
Given an itemized estimate exists When the retainer summary step renders Then the total is split into trust vs. operating according to Trust Split Guard rules And each component shows its ledger destination and rationale in plain language And client disclosures for fees, surcharges, provider add-ons, and any anticipated waiver are displayed And the client must acknowledge the disclosures before e-signing Given a waiver is applied or anticipated When the estimate updates Then the trust request adjusts accordingly and the disclosure reflects the reduced amount
Bilingual Copy and Localization (EN/ES)
Given client language preference is Spanish When fee questions, estimates, explanations, tooltips, and errors render Then all fee-related copy is displayed in approved Spanish translations with no untranslated strings And currency remains USD with Spanish number formatting conventions And the user can toggle to English without losing form state And translation coverage for fee-related strings is ≥ 99% per automated scan Given client language preference is English When rendering the same views Then all fee-related copy appears in approved English
Accessibility Compliance for Fee UI
Given a user navigates the fee inputs and estimate on mobile and desktop When using only keyboard navigation Then all interactive elements are reachable in a logical order with visible focus indicators And dynamic estimate updates are announced via ARIA live regions without stealing focus And color contrast meets WCAG 2.2 AA (text ≥ 4.5:1; large text/icons ≥ 3:1); tap targets ≥ 44x44 px And each input has an associated label and errors are tied via aria-describedby And automated accessibility scan (axe or equivalent) reports zero WCAG 2.2 AA violations on fee screens
Audit Trail & Calculation Trace
"As an attorney, I want a transparent breakdown and audit trail of the fee calculation so that I can justify amounts to the court, clients, and auditors."
Description

Record a complete, immutable trace of every fee calculation including inputs, jurisdictional tables and versions used, provider fees retrieved, overrides, and resulting line items. Present a human-readable breakdown with formulas, dates, and sources, and allow export to PDF for clerk inquiries or audits. Store a hashed snapshot for each filing, link it to the matter, and emit timeline events for changes. Provide diff views across recalculations (e.g., fee schedule updates) and highlight impacted filings. This transparency lowers dispute risk, accelerates clerk resolution, and supports internal QA and compliance.

Acceptance Criteria
Immutable Full Calculation Trace Per Filing
Given a fee calculation is performed for a filing linked to a matter When the calculation completes Then the system persists a write-once audit record containing: Matter ID, Filing ID, User ID, Request ID, UTC timestamp, all input values and derived variables, venue and case type, jurisdictional fee table identifiers and version numbers, provider endpoints called and raw responses, manual overrides (actor, timestamp, reason, before/after), resulting fee line items with labels, amounts, currency, taxes/surcharges, and Trust Split Guard outputs And the record is immutable (no updates; only new versions may be appended) And a cryptographic integrity hash is computed for the canonical snapshot and stored with the record.
Human-Readable Breakdown With Sources and Formulas
Given an authorized user opens the Calculation Trace for a filing When the breakdown renders Then each line item displays its formula, input values, and computed result And each amount shows its source (table name/section, version/date, provider name) and timestamp And totals and trust vs. operating splits are shown And all displayed values match the stored audit record exactly.
Clerk-Ready PDF Export of Calculation Trace
Given an authorized user selects Export PDF on a Calculation Trace When the export completes Then the PDF content matches the on-screen breakdown in content and order And the PDF includes header metadata (firm, matter ID, filing ID, venue, case type, actor, UTC timestamp) And the PDF includes the audit hash and a verification link/QR to a read-only verification view And the PDF text is selectable and passes an equality check against the rendered breakdown text.
Diff View Across Recalculations With Impact Highlighting
Given a filing has at least two calculation snapshots When the user selects two snapshots for comparison Then the diff view highlights added, removed, and changed fee line items with amount deltas And shows changes to totals and trust/operating splits And shows changes to jurisdictional table and provider version identifiers And lists impacted filings in the matter that share the changed schedule/provider version, with links.
Hashed Snapshot Stored and Linked to Matter
Given a calculation snapshot is stored When it is later retrieved Then recomputing the snapshot’s hash matches the stored hash; otherwise an integrity error is logged and the snapshot is not displayed And the snapshot is linked to the Matter and Filing records and is queryable by both.
Timeline Events for Calculation and Override Changes
Given a new calculation, provider fee refresh, or manual override occurs When the action is committed Then a timeline event is appended to the matter with event type, actor, UTC timestamp, and snapshot/version references And the event appears in the matter activity feed.
Provider Fee Retrieval and Manual Override Logging
Given provider fees are retrieved during calculation When provider API calls succeed or fail Then the audit record stores provider name, endpoint, request ID, response status, response body (sanitized), and timestamp And on failure or timeout, the error and fallback rule used are recorded And any manual override of provider-provided fees requires a reason and records actor and timestamp.

Venue Verifier

Checks venue eligibility against claim‑specific rules (e.g., residency, transaction location, property county) and asks only the minimal extra questions to confirm. Generates a plain‑language rationale with rule citations, inserts it into the audit trail, and optionally into pleadings. Reduces motions to transfer and boosts first‑pass acceptance.

Requirements

Jurisdictional Rule Engine
"As a solo consumer-law attorney, I want the system to automatically evaluate venue rules for my jurisdiction so that I can file in the proper court without manual research."
Description

A deterministic, data-driven engine that evaluates venue eligibility using claim-specific rules by jurisdiction (state, county, court type). Supports rule expressions for residency, transaction locus, property situs, and defendant principal place of business. Rules are versioned with effective dates and can be toggled per claim type. The engine consumes structured facts from Briefly’s intake model and outputs a decision object listing eligible venues, ineligibility reasons, and unresolved fact requirements. Exposes a service API used by the questionnaire layer and document assembly, and logs rule paths and inputs for full auditability.

Acceptance Criteria
State/County Venue Eligibility Decision
Given a configured jurisdiction scope (state, county, court_type) with an active rule set for a claim_type and an as_of date, and complete structured facts covering all predicates referenced by the active rules When the engine evaluates the request Then the decision object includes: - eligible_venues[] containing only venues whose predicates all evaluate true - ineligible_venues[] for remaining candidates with reason_codes enumerating failed predicates - unresolved_facts == [] (empty) And no venue appears in both eligible_venues and ineligible_venues And each venue entry includes jurisdiction_id, court_type, and rule_version_id
Minimal Unresolved Facts
Given incomplete facts for a claim_type and an active rule set covering multiple candidate venues When the engine evaluates Then the decision object includes unresolved_facts listing only fact keys necessary to conclusively determine eligibility across all candidates, according to configured priority And |unresolved_facts| is minimal such that supplying exactly those facts leads to unresolved_facts == [] on reevaluation And any proper subset of those facts leaves at least one candidate undecided And unresolved_facts contains only fields declared in the intake model and referenced by active rules
Rule Versioning and Effective Dates
Given multiple rule versions per jurisdiction with effective_from, effective_to, and per-claim-type toggles When evaluating with as_of within [effective_from, effective_to] and claim_type enabled Then the engine selects exactly one rule_version_id and uses it for all evaluations When as_of is before any effective_from or all relevant versions are disabled for claim_type Then the engine returns HTTP 409 with error_code "NO_ACTIVE_RULES" and no eligible_venues When as_of equals a boundary date Then inclusivity is: effective_from inclusive; effective_to inclusive And the selected rule_version_id is included in the decision and audit log
Audit Logging of Rule Paths and Inputs
Given any evaluation request (success or validation error) When the engine completes processing Then it writes an immutable audit record containing: request_id, decision_id, timestamp, claim_type, as_of, jurisdiction scope searched, rule_version_id(s), input_facts (keys and values), evaluated_rule_paths with outcomes (true/false/unknown), and final decision summary And the audit record is retrievable via request_id or decision_id And each venue decision includes a reference to the rule_path used for rationale generation
Service API Contract for Questionnaire and Docs Layers
Given a POST /v1/venue/decisions request with JSON payload matching the defined schema (claim_type, as_of, facts{}, candidate_scope{}) When payload is valid Then respond 200 with decision object containing eligible_venues[], ineligible_venues[], unresolved_facts[], decision_id, rule_version_id, and timing metadata When payload is invalid (unknown fields, missing required fields, bad types) Then respond 422 with error_code and per-field messages; no decision_id allocated When an Idempotency-Key header is supplied and the same payload is repeated within 24h Then respond 200 with the original decision (byte-identical body) and the same decision_id And p95 latency for valid requests with <=200 candidate venues is <=400ms; p99 <=800ms
Determinism, Idempotency, and Stable Ordering
Given identical inputs (claim_type, as_of, facts, candidate_scope) and the same active rule_version_id When the engine is invoked repeatedly (including concurrent invocations) Then the eligible_venues and ineligible_venues arrays are ordered by configured sort (jurisdiction_id ascending, then court_type) And the complete response body (excluding server-generated timestamps) is byte-identical across invocations And outcomes are unaffected by cache state, threading, or evaluation order
Coverage of Supported Venue Predicates
Given active rules that rely on residency, transaction_locus, property_situs, and defendant_principal_place_of_business predicates When the corresponding facts are provided Then each predicate evaluates correctly per its operator (equals, in, intersects) and jurisdictional scope (state, county, court_type), and eligibility reflects the combined boolean expression When any one predicate fact is missing Then the venue remains undecided and the missing predicate's fact key is included in unresolved_facts And composite scenarios (e.g., property spans multiple counties) evaluate per rule definition (e.g., intersects) and produce consistent results
Geocoding & County Resolver
"As an intake respondent, I want the app to infer the correct county from my address so that I don’t have to know or type it."
Description

A reliable geocoding layer that normalizes addresses and locations collected in intake into county, municipality, and judicial district. Supports batch lookup, offline cache fallbacks, and edge cases such as P.O. boxes and rural routes. Integrates with USPS, Census TIGER, and state GIS APIs to return standardized county identifiers (e.g., FIPS) and confidence scores for consistent rule evaluation. Surfaces validation prompts when ambiguity is detected and writes normalized results back into the matter profile.

Acceptance Criteria
Single Address Normalization and County Resolution
Given a valid US street address collected during intake When the resolver processes the address Then it normalizes the address to USPS standard format And returns county name and 5-digit FIPS, municipality, and judicial district And returns latitude/longitude with precision ≤ 50 meters to TIGER reference at P95 And returns a confidence score between 0.0 and 1.0 that is ≥ 0.90 And completes processing within 800 ms at P95 under normal load
Batch Lookup Throughput and Idempotency
Given a batch submission of 500 mixed addresses/locations When the batch API executes Then ≥ 98% of items return resolved results on first pass And P95 end-to-end batch completion time is ≤ 60 seconds And duplicate inputs within the batch are deduplicated and yield identical outputs And partial failures return per-item error codes without aborting the batch And a retried batch with the same batchId returns identical successful results (idempotent)
Offline Cache Fallback on External API Outage
Given USPS and TIGER endpoints time out or return 5xx for ≥ 2 seconds When resolving an address seen within the last 90 days Then the system serves cached normalized address, county FIPS, municipality, judicial district, geocode, and confidence And sets source="cache" and includes freshness age (hours) And reduces confidence by 0.05 but not below 0.50 And logs an outage and fallback event with timestamps And responds within 1200 ms at P95
Edge Case Handling: P.O. Boxes and Rural Routes
Given an input with a P.O. Box or Rural Route When the resolver processes the input Then it avoids rooftop geocoding and sets geocode precision="postal" And resolves county/municipality using ZIP/post office locality and TIGER county centroid And returns confidence ≤ 0.80 and records the rule used And prompts for a physical service address if venue rules require it And does not block matter creation
Ambiguity Detection and Minimal Validation Prompts
Given an address matching multiple counties or municipalities When the top two candidates have confidence within 0.05 Then the system displays a single concise prompt requesting disambiguating info (e.g., cross street or parcel number) And shows the two best candidates with plain-language rationale And upon new user input, re-resolves to a single county with confidence ≥ 0.90 or sets status="unresolved" And limits to ≤ 1 prompt per ambiguous address
Standards Compliance: Identifiers and Source Traceability
Given any successful resolution When returning data to consumers Then county is labeled with 5-digit FIPS plus county and state names And municipality includes GNIS or state code where available And judicial district is mapped from the state GIS taxonomy when available And each field carries source attribution (USPS, TIGER, state GIS, cache) and retrieval timestamps And all codes validate against reference tables updated within the last 30 days
Write-Back to Matter Profile and Audit Trail
Given a matter in intake When resolution completes Then normalized address, county FIPS, municipality, judicial district, geocode, confidence, and source are written atomically to the matter profile And changes are versioned with before/after values and actor in the audit trail And the plain-language venue rationale with rule citations is stored for Venue Verifier consumption And any address updates trigger re-resolution and a new audit entry And failures result in no partial writes (transactional integrity)
Adaptive Minimal Questions
"As a client filling the intake, I want to answer as few venue-related questions as necessary so that I can finish quickly without confusion."
Description

A decision-graph that asks only the minimal additional questions required to resolve venue eligibility gaps. Leverages the rule engine’s missing-fact outputs and existing profile data to avoid re-asking. Supports conditional blocks, progressive disclosure, prefill, and cross-session persistence. Mobile-first interactions (one question per screen, large tap targets) reduce friction while maintaining evidentiary completeness. Emits a structured fact delta for downstream systems.

Acceptance Criteria
Minimal Questions from Rule Gaps
Given the rule engine returns missing_facts [X,Y], When the flow starts, Then only questions mapped to X and Y are displayed. Given a dependency chain requires A before B, When A is answered, Then B is asked only if still unresolved by inference. Given any displayed question, Then it must map to exactly one missing_fact_id and be logged with that ID. Then the total number of new questions asked equals the count of unresolved missing_facts after deduplication (difference = 0). Then no question unrelated to venue eligibility is displayed during this flow segment.
Prefill and No Re-ask of Existing Data
Given a profile fact exists with state=verified, When the flow needs that fact, Then it is auto-applied and not asked. Given a profile fact exists with state=unverified and the rule requires verified, When presented, Then the UI asks for confirm/deny; confirming sets state=verified without retyping. Given the same fact was answered earlier in this session, When revisiting, Then it is prefilled and not re-asked unless the user edits. Then all prefilled facts display provenance and are recorded in the audit trail with timestamp and source.
Conditional Blocks and Progressive Disclosure
Given a gating answer renders a fact group irrelevant, Then all questions in that group are skipped. Given a disqualifying answer is provided, Then the flow stops additional venue questions and shows the eligibility outcome. Given the decision graph determines the next question, Then only one question is visible per screen and the next is computed in <=100 ms after answer submission. Then the navigation order follows a topological dependency ordering with no cycles.
Mobile-First One-Question-Per-Screen UX
Then all tap targets are >= 44x44 px on screens <= 414 px width. Given input types (numeric, date, email, address), When prompting the user, Then appropriate mobile keyboards are invoked. Then the UI meets WCAG 2.1 AA color contrast and visible focus states for interactive elements. Given a typical mobile network (slow 4G), When loading the next question, Then time-to-interaction <= 500 ms at P95.
Cross-Session Persistence and Resume
Given the user exits mid-flow, When they return within 30 days, Then the session resumes at the next unresolved question with previous answers intact. Then answers are auto-saved within 500 ms of change (field blur/selection) and persist across app reloads. Given the same intake is opened on another device, When conflicting edits occur, Then last-write-wins is applied and both versions are logged with timestamps and device IDs.
Structured Fact Delta Emission
When the user completes venue determination or exits the flow, Then a fact_delta JSON is emitted containing only added/changed facts since the last emission. Then each delta item includes: fact_id, value, verification_state, source, timestamp, session_id, and sequence_number, and validates against schema version v1.0. Then emissions are idempotent via monotonically increasing sequence_number; repeat deliveries with the same sequence_number produce no side effects downstream. Then the delta is delivered to downstream systems within 2 seconds at P95 or queued with exponential backoff until delivery succeeds, with retries logged.
Plain-Language Rationale & Citation Builder
"As an attorney, I want a plain-language explanation with citations for the chosen venue so that I can defend it against transfer motions and communicate clearly with the client."
Description

A generator that converts rule-evaluation traces into readable rationales explaining why a venue is proper or improper, with embedded citations to statutes and local rules. Produces short and extended variants, adheres to an eighth-grade reading level, and supports variable substitution for parties, locations, and dates. Outputs both JSON and formatted snippets for audit trail storage and document insertion. Integrates with an internal citation dataset and jurisdiction-specific phrasing templates to ensure accuracy and consistency.

Acceptance Criteria
Short and Extended Rationale Generation
Given a completed venue rule-evaluation trace and variables {plaintiff_name, defendant_name, county, filing_date} When the builder is invoked with variants=["short","extended"] Then it returns both variants in a single response And the short variant is 1–3 sentences and <= 90 words And the extended variant is 200–500 words across 3–7 paragraphs And both explicitly state whether venue is proper or improper and list the top 1–3 reasons drawn from the trace And both achieve Flesch–Kincaid Grade <= 8.0 excluding citation parentheticals And both contain at least one inline citation token that maps to the citations array
Jurisdiction-Specific Citation Embedding and Resolution
Given a trace referencing rule_ids and a jurisdiction_code When generating the rationale Then each referenced rule_id resolves to an internal citation effective as_of filing_date And each inline citation in the text maps 1:1 to an entry in citations[] And citations[] entries include {id, rule_id, jurisdiction_code, display_text, normalized_citation, version_date} And citation inline formatting follows the jurisdiction’s template rules And if any rule_id cannot be resolved, the builder returns error code "CITATION_UNRESOLVED" and emits no rationale
Variable Substitution for Parties, Locations, and Dates
Given a phrasing template containing placeholders {plaintiff_name}, {defendant_name}, {county}, {transaction_date} When the builder runs with provided variable values Then all placeholders are replaced and no token matching /\{[^}]+\}/ remains in any output field And party names preserve provided casing except at sentence starts And transaction_date is formatted as "MMMM D, YYYY" by default, with locale override respected when locale is provided And outputs escape characters to prevent HTML/Markdown injection while preserving visible text And whitespace is normalized (no double spaces; no leading/trailing spaces per line)
JSON Payload and Formatted Snippet Outputs
Given successful rationale generation When emitting outputs Then the JSON payload validates against schema v1 containing {id: UUIDv4, decision: "proper"|"improper", rationale_short, rationale_extended, citations[], variables_resolved, metrics.readability.fk_grade, template_id, jurisdiction_code, created_at: ISO-8601 UTC, content_hash: SHA-256 hex} And formatted_snippet_html uses only allowed tags [p, strong, em, sup, a, ul, ol, li] and no inline styles or script And a plain_text_snippet is also provided And content_hash recomputed client-side matches the provided value And payload size <= 64KB when including only short variant and <= 256KB when including both variants
Jurisdiction-Specific Phrasing Templates and Fallback
Given jurisdiction_code values (e.g., CA vs TX) with the same trace and variables When generating rationales Then the language reflects the selected jurisdiction’s phrasing template and citation style And the output contains at least one phrase unique to the selected template and none from other jurisdictions And if a jurisdiction-specific template is unavailable, the generic template is used and metadata includes non-blocking warning code "TEMPLATE_FALLBACK"
Deterministic Output, Idempotence, and Pleading-Insertion Option
Given identical inputs (trace, variables, template_id, dataset_version) When generation is repeated Then JSON and snippets are byte-identical and content_hash is unchanged And when pleadings_insertion=true, the extended variant uses third-person voice, excludes internal IDs, and renders inline citations as numbered superscripts And when pleadings_insertion=false, snippets include machine-readable citation tags suitable for audit trail indexing And p95 generation time <= 300ms for traces with <= 100 nodes on reference hardware And failures or timeouts return structured error with correlation_id and no partial outputs are stored
Audit Trail Insertion
"As a compliance-focused practitioner, I want the venue reasoning stored in the audit trail so that I have defensible records for court or ethics audits."
Description

Automatic recording of the venue decision, rationale, input facts, rule set version, and timestamps into the matter’s immutable audit log. Supports user/actor attribution, hash-based integrity checks, and export in PDF/JSON formats. Provides quick retrieval within the case timeline and deep links to the specific intake responses that influenced the decision, ensuring defensibility and transparency.

Acceptance Criteria
Auto Record Venue Decision and Metadata
Given a matter where Venue Verifier completes When a venue decision is produced Then the system writes a new immutable audit entry for the matter And the entry includes: decision, ruleSetVersion, createdAt (UTC), decidedAt (UTC), and entryId And any attempt to update or delete this entry is blocked and logged as a separate append-only event referencing the original entry
Rationale and Input Facts Logged
Given a venue decision audit entry exists When viewing the audit entry details Then the rationale field contains a plain-language explanation And the rationale includes citations for each rule used (by rule identifier or citation) And the inputFacts list contains only the facts that influenced the decision, each with key, value, and source responseId
User and System Actor Attribution
Given a venue decision is generated by a signed-in user or system process When the audit entry is created Then the entry records actorType (user|system), actorId, and triggering channel (UI|API|BackgroundJob) And if actorType is user, the entry includes the userId and role at time of action; if system, the service account id And actor information is displayed in the UI and included in exports
Hash Integrity and Tamper Detection
Given an audit entry is created When the system computes a SHA-256 hash over the entry’s canonicalized content Then the stored contentHash equals the recomputed hash And when an integrity check is invoked for the matter, all venue audit entries verify contentHash successfully And if any mismatch occurs, the system flags the matter’s integrity status and records an integrity-failure audit event
Export Audit Entry to PDF and JSON
Given a venue audit entry exists When a user exports the entry as PDF Then the PDF contains decision, rationale, inputFacts, ruleSetVersion, timestamps, actor info, entryId, and contentHash in human-readable form And when a user exports as JSON Then the JSON validates against the auditEntry schema containing: decision, rationale, inputFacts[], ruleSetVersion, timestamps, actor, entryId, contentHash And both exports complete without error and are downloadable
Timeline Retrieval and Deep Links
Given a matter’s case timeline is open When filtering for Venue Verifier events or searching by entryId Then the audit entry appears in chronological order with a View Details action And opening the entry shows all fields within 2 seconds And each input fact includes a deep link that navigates to the corresponding intake response within the same matter and the displayed value matches the audit entry
Conditional Pleading Injection
"As an attorney generating first drafts, I want the proper-venue rationale auto-inserted into my pleadings when needed so that I save time and reduce errors."
Description

Merge fields and conditional content blocks that insert the venue rationale into pleadings and retainers when configured. Supports DOCX/RTF templates, jurisdiction-specific citation formatting, and per-template toggles to include/exclude or choose short/long rationale variants. Ensures inserted text respects formatting, pagination, and local practice style requirements.

Acceptance Criteria
Insert Rationale When Enabled (Pleadings and Retainers)
Given a pleading DOCX template contains the merge field VENUE_RATIONALE and the template's Include Rationale toggle is enabled, and the case has a generated venue rationale When the document is assembled Then the rationale text is inserted at the merge field location and any placeholder or merge syntax is removed And no extra blank lines or artifacts are introduced before or after the inserted text Given the template's Include Rationale toggle is disabled When the document is assembled Then the VENUE_RATIONALE merge field and its conditional block are removed with no visible trace And the rest of the document content remains unchanged Given a retainer DOCX template configured identically When the document is assembled Then the same behavior applies as for pleadings
Variant Selection (Short vs Long) Per Template
Given a template's Variant selection is set to Short When the document is assembled Then the Short rationale variant is inserted and the Long variant is not Given the Variant selection is set to Long When the document is assembled Then the Long rationale variant is inserted and the Short variant is not Given the Variant selection is not explicitly set for a template When the document is assembled Then the Short variant is used by default And the output text does not include any variant labels or internal metadata
Jurisdiction-Specific Citation Formatting
Given the case jurisdiction is mapped to a configured citation style (e.g., CA, NY, TX) When the document is assembled Then citations within the inserted rationale follow the jurisdiction's style map for abbreviations, section symbols, punctuation, and italics And spacing before/after citations matches the configured local practice rules Given the case jurisdiction is not mapped When the document is assembled Then the organization's default citation style is applied to all citations in the inserted rationale And a non-blocking warning is recorded to the audit log identifying the fallback
DOCX and RTF Template Compatibility
Given a DOCX template that uses named styles, numbered lists, headers/footers, and tables When the document is assembled to DOCX and exported to PDF Then the inserted rationale inherits the surrounding paragraph style unless a specific style is mapped, and fonts, sizes, spacing, numbering, and table borders are preserved And all merge fields and conditional blocks are fully resolved with no remaining field codes in the output Given an RTF template with the VENUE_RATIONALE merge field and equivalent styling When the document is assembled to RTF and exported to PDF Then the inserted rationale preserves styling and layout consistent with adjacent content, and no encoding artifacts (e.g., RTF control words) appear in the output
Pagination and Local Style Preservation
Given a pleading template with headings, numbered sections, and a signature block configured with keep-with-next When a multi-paragraph venue rationale is inserted and the document is paginated to PDF Then headings remain with the following paragraph per template settings And numbering continues consecutively without reset or duplication And the signature block remains on the same page as configured or moves as a unit if overflow occurs And no unintended page breaks or empty pages are introduced beyond natural pagination And widows/orphans and hyphenation settings on affected paragraphs remain as defined by the template
Per-Template Toggle Persistence and Safe Fallbacks
Given a template's Include Rationale toggle and Variant selection are changed and saved When the template is reopened in a new session Then the saved Include/Exclude state and Variant persist Given a template is duplicated or versioned When a new template instance is created Then the Include/Exclude toggle and Variant selection are inherited by the new instance Given Include is enabled but the template does not contain the VENUE_RATIONALE merge field or conditional block When document assembly runs Then generation completes successfully, no literal placeholders appear in the output, and a non-blocking warning is surfaced to the user and recorded in the audit log
Multi-Venue Resolution & Attorney Override
"As an attorney, I want to choose among multiple proper venues with a recommended option and clear tradeoffs so that I can make a strategic filing decision."
Description

Handling of scenarios where multiple venues qualify or conflicts arise by ranking eligible venues using configurable heuristics (e.g., speed to disposition, distance, defendant HQ, jury pool). Presents a recommended choice with pros/cons and confidence scoring. Supports attorney override with required reason capture, records the decision and rationale in the audit trail, and propagates the selection to downstream document assembly.

Acceptance Criteria
Heuristic-Based Ranking of Eligible Venues
Given a matter where venues B, A, and C are eligible and heuristic weights are configured as speed_to_disposition=0.5, distance=0.3, jury_pool=0.2 And normalized venue metrics are: - A: speed=0.8, distance=0.6, jury_pool=0.4 - B: speed=0.7, distance=0.9, jury_pool=0.3 - C: speed=0.6, distance=0.4, jury_pool=0.9 When the system calculates weighted scores and ranks venues Then the scores are B=0.68, A=0.66, C=0.60 and the displayed order is B, A, C And scores are shown to two decimal places alongside each venue And if the top two scores are equal to two decimals, the configured tie-breaker 'closest_distance' is applied and the nearer venue is ranked higher And if no custom weights exist for the matter type/jurisdiction, the default weights speed=0.4, distance=0.4, jury_pool=0.2 are applied
Recommended Venue Card with Pros/Cons and Confidence Score
Given multiple eligible venues have been ranked When presenting the recommended venue to the user Then a recommendation card is shown with: - the recommended venue name - a confidence percentage = round(((top_score - next_best_score)/top_score)*100) with label High (>=20%), Medium (10–19%), Low (<10%) - at least two pros and one con derived from heuristics (pros require metric >=10% above the median, cons require <=10% below the median), phrased in plain language - a "Why?" link that expands to the rationale with rule citations And when exactly one venue is eligible, the recommendation card is suppressed and the single venue is selected without a confidence label
Attorney Override With Mandatory Reason
Given a recommended venue is displayed When an attorney selects a different eligible venue and clicks Confirm Then the system requires an override reason: - a required picklist (e.g., Client convenience, Adverse publicity, Judge assignment, Other) - when Other is chosen, a required free-text field (10–500 characters) And the Confirm action is disabled until a valid reason is provided And upon save, the override is applied, the UI updates to show the new selection, and a success toast confirms "Venue overridden"
Immutable Audit Trail of Recommendation and Decision
Given a recommendation has been computed and a selection (recommended or overridden) is saved When the matter is persisted Then an immutable audit-trail entry is appended containing: matter_id, ISO8601 timestamp, user_id, recommended_venue_id, recommended_score, ranked_venues with scores, selected_venue_id, override_reason_code (nullable), override_reason_text (nullable), heuristic_config_version_id, rationale_text, rule_citation_ids And audit entries are read-only to all roles and non-deletable And authorized users can export the audit trail to CSV/JSON including these fields
Propagation to Documents and E-sign Packages
Given a selected venue exists for the matter When generating the retainer agreement and first pleading drafts Then the selected venue name, court address, and caption formatting appear in the correct template fields for the jurisdiction And if the venue selection changes before client e-sign, previously generated documents are marked Stale and a one-click Regenerate updates all affected documents within 5 seconds And any active e-sign packets containing stale documents are automatically invalidated and reissued upon regeneration
Minimal Tie-Breaker Questioning
Given multiple eligible venues have equal top scores to two decimals and a configured tie-breaker requires data that is missing (e.g., client travel distance) When the system prepares to present a recommendation Then it prompts only for the missing tie-breaker fields needed to resolve the tie (maximum 3 questions), skipping any already collected information And after the user answers, scores are recomputed and the recommendation is updated without asking unrelated questions And if no additional data is needed to break the tie, no questions are asked
Heuristic Weight Configuration and Versioning
Given an admin user with permission to configure heuristics When editing weights for a practice area and/or jurisdiction Then each weight must be between 0.00 and 1.00 with two-decimal precision and all weights must sum to exactly 1.00 or the form cannot be saved And saving creates a new configuration version with effective_from timestamp and optional notes And new calculations use the latest effective version while historical audit entries retain their original heuristic_config_version_id And the admin can revert to a prior version in one action, and import/export configurations via CSV with validation errors reported per line

Filing Playbook

Delivers a venue‑specific, step‑by‑step checklist covering submission channel (e‑file, mail, in‑person), required coversheets, copy counts, office hours, addresses, and formatting quirks. Mobile‑friendly for courthouse use, it trims clerk callbacks and ensures packets are right the first time.

Requirements

Venue Rules Repository & Versioning
"As a solo consumer-law attorney, I want a reliable, up-to-date repository of venue-specific filing rules so that I can trust the playbook to reflect current clerk requirements."
Description

A centralized, structured data repository that stores court- and venue-specific filing requirements, including submission channels (e-file, mail, in-person), addresses, office hours and cut-off times, coversheet and local-form requirements, copy counts, formatting quirks, and any clerk-specific notes. Data is normalized with a jurisdiction hierarchy (state > county > court > division) and keyed by filing type and matter category. Supports versioning with effective dates, audit trails, source citations, and rollback. Provides an admin UI for updates, CSV/API import for bulk loads, and a read API consumed by the Filing Playbook. Ensures data quality via validation rules and “last verified” timestamps so playbooks render accurate, up-to-date guidance.

Acceptance Criteria
Normalize Venue Data by Jurisdiction and Filing Context
- Rule: Repository requires keys: state_code, county_name, court_name, division_name (nullable), filing_type, matter_category, requirement_kind. - Rule: Create/update is rejected with 422 if any required key is missing or invalid. - Rule: Composite uniqueness: [state_code, county_name, court_name, division_name, filing_type, matter_category, requirement_kind, effective_start, effective_end) must be unique; overlapping effective windows for the same composite are rejected with code OVERLAPPING_VERSION. - Rule: Normalization on save: state_code uppercased (2 letters); ZIP 5 or 9 digits; phone E.164; office_hours in HH:MM-HH:MM with IANA timezone; cut_off_time in HH:MM local; submission_channel ∈ {efile, mail, in_person}; URLs valid; whitespace trimmed. - Given a valid payload, When saved, Then persisted record reflects normalized fields and generated version_id.
Versioning with Effective Dates and Read-time Resolution
- Rule: effective_start is required ISO 8601; effective_end is optional; if present, effective_end > effective_start; open-ended versions allowed with effective_end = null. - Rule: Overlapping versions for the same composite key are rejected on save with 422 OVERLAPPING_VERSION. - Given multiple versions exist, When Read API is called without as_of, Then return the version where now ∈ [effective_start, effective_end) or where effective_end is null and effective_start ≤ now; else return 404 NO_EFFECTIVE_VERSION. - Given as_of is provided, When Read API is called, Then return the version where as_of ∈ [effective_start, effective_end) (preferring the most recent effective_start on ties) or 404 if none. - Rule: Each version includes version_id and previous_version_id to support lineage; audit trail links to version_id.
Audit Trail and Source Citation
- Rule: Create/Update/Delete events produce immutable audit entries with: record_id, version_id, actor_id, timestamp, action, before/after diff, reason. - Rule: At least one source citation (URL or file_id with description) is required to publish a version; save without citation returns 422 MISSING_SOURCE. - Given a record is queried, Then Read API includes source_citations[] and last_verified_at for the effective version. - Rule: Audit entries are append-only; attempts to alter or delete an audit entry are rejected with 403 IMMUTABLE_AUDIT.
Admin UI CRUD with Validation and Last Verified
- Given an authenticated Rules Editor, When creating or editing a rule, Then client- and server-side validations enforce required keys, formats, and enumerations (submission_channel ∈ {efile, mail, in_person}; copy_count integer ≥ 0; hours/time formats as specified; addresses split into street, city, state, zip). - Given the editor checks "Mark as verified", When saving, Then last_verified_at is set to current timestamp and requires a selected verification source; missing source blocks save with inline error. - When save succeeds, Then the UI shows a success state, the record’s version_id, and the Read API immediately returns the updated effective version. - Rule: Delete action requires confirmation; soft-deletes create a terminal effective_end and an audit entry; hard delete is disallowed via UI.
Bulk Import via CSV/API with Error Handling
- Rule: CSV header must include: state_code, county_name, court_name, division_name, filing_type, matter_category, requirement_kind, value, effective_start, effective_end (optional), source_url (or dataset_source for batch). - Given a CSV is uploaded, Then per-row validation occurs; valid rows upserted; invalid rows skipped; response includes counts {total, inserted, updated, failed} and per-row errors with line numbers and codes. - Rule: Batch mode supports upsert_strategy=strict (all-or-none) or lenient (partial apply); strict mode rolls back all changes if any row fails. - Rule: API bulk import supports Idempotency-Key; repeating the same key within 24h produces identical results without duplicating versions. - Rule: Dates must be ISO 8601; invalid date/time values cause row failure with code INVALID_DATETIME.
Read API Contract for Filing Playbook
- Given jurisdiction_path (state/county/court/division), filing_type, matter_category, and optional as_of, When GET /v1/rules is called, Then return 200 with an array grouped by requirement_kind for the effective versions. - Response item fields include: requirement_kind, value, submission_channel, addresses, office_hours, cut_off_time, coversheet_requirements, local_forms, copy_count, formatting_notes, clerk_notes, version_id, effective_start, effective_end, last_verified_at, source_citations. - Given invalid query params, Then return 400 with field-level validation errors; Given no effective rules, Then return 404 NO_RULES_FOUND. - Rule: Responses are deterministic: items sorted ascending by requirement_kind; timestamps returned in ISO 8601 with timezone.
Rollback to Prior Version
- Given an admin selects a prior version for the same composite key and clicks Rollback, When confirmed, Then the system creates a new version cloned from the selected one with effective_start=now and effective_end=null, links previous_version_id to the current version, and writes an audit entry action=ROLLBACK. - Rule: Rollback is blocked if it would create an overlap; system either prompts to end-date the current open-ended version or auto end-dates it to now before creating the rollback version. - Then the Read API without as_of returns the rolled-back values for now; prior superseded version remains in history and is not deleted.
Dynamic Checklist Builder
"As a filing paralegal, I want a dynamic checklist tailored to my venue and filing type so that I complete every required step without omissions or rework."
Description

A rules-driven engine that assembles a step-by-step filing checklist tailored to the selected venue, filing type (e.g., initial complaint, motion, proposed order), and submission channel. Pulls requirements from the repository, orders tasks logically, shows dependencies and branching (e.g., additional steps if serving by mail), and marks mandatory vs optional steps. Integrates with Briefly matter data to pre-insert required documents and confirm prerequisites are satisfied. Persists progress per matter, supports reordering when context changes, and enables export/print/share for internal use or runners. Reduces omissions, rework, and clerk callbacks by guiding the user through exactly what to do and in what sequence.

Acceptance Criteria
Tailored checklist generation by venue, filing type, and channel
Given a matter with venue "Cook County Circuit Court", filing type "Initial Complaint", and submission channel "E-file", and repository rules exist for that combination When the user selects Build Checklist Then a checklist is generated within 2 seconds And only steps whose applicability conditions evaluate true for the matter are included And steps are ordered according to defined dependency precedence (no step appears before an unmet dependency) And each step is labeled as Mandatory or Optional per rule definition And the checklist header displays venue, filing type, submission channel, and the repository version ID used
Branching steps for service method selection
Given the generated checklist contains the step "Select Service Method" When the user selects "Serve by Mail" Then mail-specific steps defined in the repository are inserted at the correct positions with dependencies respected And step numbering updates contiguously without gaps When the user switches the selection to "Personal Service" Then mail-specific steps are removed and personal-service-specific steps appear per rules And no unrelated steps are reordered And no dangling dependencies remain
Prerequisite gating and auto-insertion from matter data
Given the matter lacks a signed retainer required by rules When generating the checklist Then a mandatory step "Obtain client e-signature on retainer" is included and gates any step tagged RequiresRetainerSigned And gated steps cannot be marked complete or started until the prerequisite is completed Given the matter already includes a validated draft complaint and required coversheets When generating the checklist Then these documents are pre-attached to relevant steps and marked Ready And prerequisite validation badges display Pass/Fail per rule for each step
Progress persistence per matter across sessions and devices
Given a user marks steps complete, adds notes, and attaches files within a matter’s checklist When the user signs out and opens the same matter on a different device (mobile or desktop) Then 100% of those state changes persist, including completion status, timestamps, notes, and attachments And the checklist shows Last updated <timestamp> and <user> And offline changes made on mobile are queued and sync within 10 seconds of reconnecting And progress is stored per matter and per checklist instance; opening a different matter does not reflect these changes
Context change triggers reorder and change summary
Given a built checklist for submission channel "E-file" When the user changes the submission channel to "In-person" Then the engine recalculates applicable steps and reorders the checklist And a change summary is shown listing counts of Added, Removed, and Modified steps and highlighting the specific steps And completion status is preserved for steps that remain semantically identical after recalculation And the user must confirm Apply changes before the checklist is updated And the recalculation and update complete within 3 seconds for checklists up to 75 steps
Export, print, and share runner-friendly checklist
Given a built checklist When the user selects Export Then a paginated PDF is generated containing matter header (matter name, venue, filing type, submission channel), repository version ID, generated timestamp, step numbers, mandatory indicators, and dependency notes And the PDF renders correctly on mobile and desktop print dialogs without truncated content or overlapping text And a secure, view-only shareable link is created that expires after 7 days by default and can be revoked manually And exported artifacts reflect the current completion status of each step
Completion rules and final readiness check
Given the checklist has one or more incomplete mandatory steps When the user attempts to mark the checklist Complete or generate a runner packet Then the action is blocked and the UI highlights remaining mandatory steps with a summary count of outstanding mandatory vs optional steps When all mandatory steps are complete Then the user can mark the checklist Complete and the system records a completion timestamp and the user ID And any optional steps left incomplete are listed in a non-blocking summary
Submission Channel & Logistics Guide
"As a runner at the courthouse, I want clear channel and logistics guidance so that I know exactly where to go, when they’re open, and how to submit without delays."
Description

Contextual guidance for each venue and filing that details the exact submission pathway and logistics: e-filing portal deep links, account prerequisites, accepted payment methods, file size limits, naming conventions, and cut-off times; in-person counter location (building, floor, window), security considerations, office hours, ticketing practices, and clerk phone numbers; mailing address with attention lines, acceptable carriers, return envelope requirements, and delivery tips. Includes click-to-call, copy-to-clipboard, and map directions, and surfaces open/closed status based on hours and holidays. Eliminates time lost to searching and reduces failed submissions by giving users everything they need at the moment of filing.

Acceptance Criteria
E-Filing Portal Deep Link & Requirements
Given a user selects a venue and filing type that supports e-filing When the Submission Channel & Logistics Guide is displayed Then it shows a working deep link to the correct e-filing portal for that venue and filing type And it lists account prerequisites (account required Y/N, registration link, two-factor required Y/N) And it lists accepted payment methods with any fees And it displays per-file and total package size limits And it displays required file naming conventions And it displays the daily submission cutoff time with clear time zone
In-Person Counter Logistics & Map
Given a venue and filing that allow in-person submission When the guide is displayed Then it shows building name, street address, floor, and window/counter identifier And it shows security considerations (screening notes, restricted items) if applicable And it shows office hours including lunch closures and last-ticket times And it shows ticketing/queuing practice (e.g., take-a-number) And it displays the clerk phone number as a click-to-call control And it provides a Directions control that opens the device's default maps app to the correct entrance
Mailing Address & Carrier Requirements
Given a venue and filing that allow submission by mail When the guide is displayed Then it shows the complete mailing address including attention lines and room/suite And it lists acceptable carriers and any required service levels And it states return envelope requirements (e.g., SASE, size) And it provides delivery tips relevant to the venue And it provides copy-to-clipboard controls for the full address and attention line
Open/Closed Status Based on Hours & Holidays
Given the current local time and the venue's business hours and holiday calendar When the guide is displayed Then it shows Open now or Closed for in-person counter and phone availability And it shows the next open or close time with the venue's time zone And it respects observed holidays defined for the venue And if hours data is unavailable, it shows Hours unavailable and hides the status badge
Action Controls: Click-to-Call, Copy, Directions
Given the guide displays a phone number, address, or portal URL When the user taps Call on a mobile device Then the device dialer opens with the number prefilled When the user clicks Copy Then the corresponding value is placed on the clipboard and a confirmation appears within 1 second When the user taps Directions Then the default maps app opens to the provided location
Channel Availability & Ordering by Venue/Filing
Given a selected venue and filing type When the guide determines available submission channels Then it shows only the channels supported by that venue for that filing And it orders channels by venue preference (e.g., mandated e-file first) And it shows a clear explanation when a channel is unavailable or restricted for that filing
Auto Coversheet & Local Form Selector
"As an attorney, I want the system to auto-select and prefill required coversheets and local forms so that I avoid clerical errors and save time."
Description

Automatic identification and retrieval of venue-required coversheets and local forms based on venue, case category, and filing type. Fetches the latest templates, flags revision dates, and pre-populates fields using Briefly intake and matter data. Validates that all required fields are present, warns on missing data, and outputs a correctly ordered PDF packet that places coversheets first and handles signatures (e.g., e-sign vs wet signature indicators). Provides links for forms that must be completed externally and records which versions were used for auditability. Reduces clerical errors and rejections while shortening preparation time.

Acceptance Criteria
Auto-identify required forms by venue and filing attributes
Given a matter with venue, case category, and filing type set When the selector runs Then the system returns the complete set of required coversheets and local forms for that venue And no forms outside that set are included And each form is labeled as Required or Optional
Retrieve latest templates with revision date flagging
Given network connectivity When fetching templates for the selected forms Then the most recent available version is retrieved from the authoritative source And each form displays its revision date and source URL And if retrieval fails, the most recent cached version is used and a warning is displayed And the audit log records each form's name, revision date/version, source URL, and retrieval timestamp used in the packet
Pre-populate fields and validate required data
Given completed intake and matter data with mappings defined When forms are generated Then all mappable fields are auto-filled with correct values and formats And a validation check confirms all required fields per form are present And any missing required fields are listed with field names and source data paths And packet finalization is blocked until missing items are resolved or explicitly overridden by an authorized user
Assemble correctly ordered PDF packet with coversheets first
Given the selected forms including coversheets When generating the packet Then the output is a single PDF where coversheets are placed first And the remaining forms are ordered per the venue-specific rule set And the final packet passes an automated order validation against the venue's rule set
Signature handling and indicators per form requirement
Given form-specific signature rules indicating e-sign acceptable or wet-sign required When generating forms and the packet Then e-sign-eligible forms include embedded e-signature fields for all required signers And wet-sign-only forms display a prominent Wet Signature Required indicator and are excluded from e-sign routing And the packet metadata lists each form with its signature type
External-only forms linking and version audit record
Given a required form must be completed externally per venue When presenting required forms Then the system provides a direct link to the current official form page And the form is excluded from the generated packet or replaced with a placeholder instruction page per configuration And the audit log records the external form's name, revision date/version, source URL, and completion method
Copy Count & Packet Assembly Calculator
"As a legal assistant, I want an accurate copy count and assembly instructions so that packets are correct the first time and avoid clerk rejections."
Description

Automated calculation of required copy counts and assembly rules per venue and filing, including court, judge, service, and conformed copies. Produces step-by-step assembly instructions covering page order, staples vs binder clips, hole punches, tabs, double-sided requirements, colored paper, label placements, and envelope prep. Integrates with matter parties to generate service lists and printable labels, and estimates page counts and postage. Outputs a print profile for batch printing and packet collation, ensuring the package is correct the first time.

Acceptance Criteria
Calculate Copy Counts by Venue and Filing Type
Given a user selects a venue, filing type, submission channel (e-file, mail, in-person), and judge (optional) When the calculator runs Then it returns integer counts for court originals, judge courtesy copies (if required), service copies per served party, and conformed copies per venue rule And counts reflect submission channel rules (e-file vs physical) And updating the party list (add/remove/mark e-service) recalculates totals within 1 second And totals match the configured rule table for the selected venue and judge
Packet Assembly Instructions: Order, Fasteners, Punches, Tabs
Given the selected venue, filing, copy type, and judge rules When assembly instructions are generated Then the output includes numbered steps for page order, fastener type (staples vs binder clips), hole punches (none/top 2-hole/left 3-hole), tab requirements, double-sided restrictions, colored paper specs, label placements, and envelope prep And instructions differ by copy type (court, judge, service, conformed) where required And prohibited elements per rules (e.g., staples, double-sided exhibits) are excluded or replaced with compliant alternatives And each step uses imperative verbs and measurable attributes (e.g., "2-hole top punch", "yellow Exhibit tabs A–F")
Service List and Printable Address Labels Generation
Given a matter with parties and counsel marked with service preferences and mailing addresses When the service list is generated Then recipients include all entities marked "service required" excluding those designated e-service-only for paper filings And duplicate addresses are consolidated unless venue rule requires distinct service per counsel And a 30-up Avery 5160 label PDF is produced, sorted alphabetically by recipient name And the user can add/edit/remove recipients and the labels regenerate within 1 second And a proof-of-service recipient table is produced with names and addresses mapped to merge fields
Page Count and Postage Estimation
Given a document bundle with known page counts and duplex settings per document When totals are computed Then pages per copy type and total sheets across all copies are displayed And postage is estimated for each mailed packet using the system-configured weight model and current USPS rate table And packages exceeding letter limits are flagged with the correct class and envelope size recommendation And conformed-copy return postage is included when the venue requires a self-addressed stamped envelope
Print Profile for Batch Printing and Collation
Given finalized copy counts and assembly rules When the user generates the print profile Then the system outputs a downloadable PDF containing cover sheets and separator sheets per copy type in the correct collation order And a JSON job ticket is exported listing per-document copy counts, duplex, paper color, hole-punch, and tab directives And headers on each segment include matter name, venue, copy type, and packet ID And printing the profile once and stacking as instructed yields the required number of ready-to-assemble packets without further sorting
Conformed Copies and Return Envelope Preparation
Given the venue requires conformed copies for in-person or mailed filings When the calculator runs Then conformed copy counts are added and steps to prepare a self-addressed stamped envelope sized to the largest document are included And a "Conform and Return" slip with case caption and return address is generated And for e-file submissions, physical conformed copy steps are replaced with instructions to acquire the file-stamped PDF and confirm return email delivery
Courthouse Mode (Offline & Mobile UX)
"As an attorney on the move, I want an offline, mobile-friendly view of my filing checklist so that I can work through steps inside the courthouse without reliable internet."
Description

A mobile-optimized interface for the Filing Playbook with large tap targets, condensed step views, and quick search, designed for low-connectivity courthouse environments. Caches selected playbooks, forms metadata, and logistics details for offline use for up to 30 days with background sync when connectivity returns. Preserves checklist progress locally and securely, minimizes PII storage, and clearly indicates data freshness. Enables reliable, fast reference and step completion in hallways and filing windows without relying on cellular service.

Acceptance Criteria
Cache Playbook for Offline Use (30-Day Retention)
- Given a user selects "Make Available Offline" on a venue playbook while online, When the download completes, Then the app caches steps, forms metadata, addresses, office hours, copy counts, coversheet requirements, and formatting notes and shows "Available offline". - Given the playbook is cached, When the device is offline, Then the playbook opens within 1 second and all cached items are viewable without network calls. - Given last successful sync timestamp, When it is < 24 hours old, Then the freshness label shows "Fresh" with the timestamp. - Given last successful sync timestamp, When it is between 24 hours and 30 days old, Then the freshness label shows "Stale" with the timestamp. - Given last successful sync timestamp, When it is > 30 days old, Then the playbook is marked "Expired", access is blocked, and a prompt to re-sync is shown.
Background Sync After Connectivity Restored
- Given step completions were recorded offline, When connectivity is restored, Then background sync begins within 60 seconds and does not block UI. - Given a step's completion state differs locally and remotely, When syncing, Then the newer timestamp wins and the losing version is logged locally; a per-step sync icon reflects status. - Given server-side content version differs, When syncing, Then the app updates to the latest version and displays a non-blocking notice summarizing changed items. - Given a sync attempt fails, When retrying, Then the app retries with exponential backoff (1 min, 5 min, 15 min) and allows manual retry; failures are surfaced with a discrete banner.
Checklist Progress Persistence Offline
- Given the user completes steps offline, When the app is force-quit or the device reboots, Then all step completion states persist with local timestamps and no steps are lost. - Given the user toggles a step completed/uncompleted offline, When undo is tapped, Then the state updates instantly and is queued for sync. - Given device storage pressure occurs, When persisting progress, Then the app preserves all progress for cached playbooks; if eviction is required, only non-progress assets are evicted and user is notified.
Mobile-Optimized Courthouse UI (Large Targets & Condensed Steps)
- Given Courthouse Mode is enabled, When viewing the playbook, Then all tappable controls have a minimum 48x48 dp hit area with at least 8 dp spacing and body text is >= 16 sp. - Given condensed step view is enabled, When opening a playbook, Then only step titles and primary actions are visible by default and details expand/collapse within 200 ms on tap. - Given a 5.8" device in portrait, When navigating one-handed, Then primary actions (Next, Mark Done, Search, Back) are reachable without zoom and without horizontal scrolling. - Given low-connectivity conditions, When rendering, Then the UI maintains >= 50 fps and defers non-essential images/animations.
Offline Quick Search Across Playbook Content
- Given the device is offline, When the user types at least 2 characters into Search, Then results return within 300 ms from the local index. - Given matching content exists, When searching, Then results include steps, coversheet requirements, copy counts, addresses, office hours, and formatting notes with query terms highlighted. - Given no match exists, When searching, Then show "No offline results" and do not attempt any network request. - Given the local index is older than 30 days, When searching, Then results are disabled and the user is prompted to re-sync.
Data Minimization, Security, and Freshness Indicators
- Given Courthouse Mode caching, When downloading for offline, Then only non-PII playbook and logistics metadata are stored; client-entered PII is excluded from the cache. - Given cached data at rest, When inspected, Then it is encrypted using OS-provided secure storage and is removed when the user signs out or clears cache. - Given the playbook header is visible, When content is shown, Then a freshness indicator displays "Updated <relative time> ago" with color coding: green <24h, amber 24h–30d, red >30d. - Given the user selects "Clear Offline Data" and confirms, When action completes, Then all cached playbooks and local progress are securely wiped and no longer available offline.
Rule Change Alerts & Feedback Moderation
"As a practitioner, I want to be alerted to rule changes and report discrepancies so that my team can adapt quickly and keep filings compliant."
Description

Alerting and feedback workflows that keep venue rules current and trusted. Users can subscribe to venues and filing types to receive notifications when rules, forms, or logistics change. In-app “Report a change” submissions route to an internal moderation queue with evidence attachments and suggested edits. Admins verify, stage, and publish updates with changelogs and effective dates, updating the repository and triggering revalidation of dependent checklists. Displays “last verified” and change history on each playbook to build confidence and reduce stale guidance risk.

Acceptance Criteria
Subscribe to Venue and Filing Type Updates
Given an authenticated user is viewing a venue playbook When the user clicks "Subscribe" and selects one or more filing types Then the system saves the subscription preferences And a confirmation toast "Subscribed to [Venue] – [Filing Types]" is displayed And the subscription appears under My Subscriptions immediately And a confirmation email is sent within 2 minutes containing manage/unsubscribe links And unsubscribing removes the subscription and stops future notifications within 60 seconds
Publish Verified Rule Update Triggers Notifications
Given an admin publishes a playbook update with a changelog and effective date When publication occurs Then an in‑app notification is generated for all subscribers within 60 seconds And an email notification is sent within 5 minutes including venue, filing type(s), changelog summary, effective date, and a deep link to the playbook And notifications are de‑duplicated per user per update And the playbook shows a "New" badge for that user until the update is viewed And delivery failures are logged with retry up to 3 times over 15 minutes
Report a Change Submission by User
Given a user opens "Report a change" from a playbook When the user completes required fields (category, subject ≥10 chars, description ≥30 chars), selects venue/filing type context, and attaches up to 5 files (pdf, jpg, png, docx) totaling ≤25 MB Then client‑ and server‑side validation prevents submit until requirements are met And attachments are virus‑scanned and stored securely; infected files are rejected with guidance And duplicate detection (venue + category + similarity ≥0.8) prompts the user to upvote an existing report instead of creating a new one And on success, a ticket ID is displayed, an email receipt is sent, and the submission status is "New" in the moderation queue And unauthenticated users cannot submit and are prompted to sign in
Moderation Queue Triage and Auditability
Given an admin opens the moderation queue When viewing a submission Then the admin can see submitter, venue, filing type(s), category, timestamps, suggested edits, and evidence attachments with scan status And the admin can Accept, Reject (with required reason ≥10 chars), or Request Info (message to submitter) And all actions append to an immutable audit log with actor, timestamp, and diffs of proposed changes And SLA status is shown; submissions older than 2 business days are flagged red And Request Info pauses SLA until the submitter responds
Stage, Version, and Publish Playbook Updates
Given an admin edits a playbook When saving changes as Draft Then the system creates a draft version (semver x.y.z‑draft) that is previewable on mobile and desktop And when publishing, the admin must enter a changelog summary ≥15 chars and set an effective date And on publish, the repository version increments (semver x.y.z), prior versions remain read‑only in history, and diff is captured And the playbook header updates Last Verified to the publish timestamp and displays Verified By (admin name)
Revalidation of Dependent Checklists After Update
Given a playbook update is published When dependencies are recalculated Then the system identifies all dependent checklists/templates via metadata and flags them as "Needs revalidation" And owners are notified with tasks due within 3 business days And generating new packets from flagged items requires acknowledgment to pull the latest rules before proceeding And flags clear automatically once revalidation is completed or if no impacted steps are detected
Display Last Verified and Change History
Given a user opens any playbook When viewing the header and History Then the header shows Last Verified (local date/time), Verified By, and current version And the History lists prior versions with publish date, effective date, and changelog summary, each link opening a read‑only snapshot And the page loads in ≤2 seconds on a 4G connection and meets WCAG 2.1 AA for text and controls And admins see a "Pending recheck" badge if no verification occurred in the last 90 days

Deadline Mapper

Turns local rules into concrete dates for service, responses, and hearings, accounting for weekends, court holidays, and service method buffers. Pushes tasks to your calendar with reminders and includes rule references for quick verification. Cuts missed cutoffs and last‑minute rushes.

Requirements

Local Rules Engine & Date Computation
"As a solo consumer-law attorney, I want deadlines computed from local rules automatically so that I never miss a cutoff and can focus on case work."
Description

Implement a jurisdiction-aware computation engine that converts anchor events (e.g., service, filing, hearing set) into concrete due dates using local court rules. The engine must support forward/backward counting, business-day calculations, weekend rollovers, court holiday adjustments, and time-of-day cutoffs. It should allow multiple courts per matter, apply court-specific calendars, and output labeled deadlines with metadata (rule ID, dependency graph). Integrate with Briefly matters to store anchors and computed deadlines, expose an API for other modules, and handle recalculation deterministically. The expected outcome is reliable, repeatable deadline schedules that reduce missed cutoffs and manual date math.

Acceptance Criteria
Forward Count with Mail Buffer and Holiday Rollover (LA Superior Civil)
Given matter M uses court CA-SC-LA (America/Los_Angeles) with court holiday 2025-01-20 and cutoff 16:30 And anchor S = Service by Mail at 2025-01-10T15:00-08:00 And rule R = "Response due 10 court days after service; add 5 calendar days for mail; exclude the day of service; roll to next court day if result lands on weekend/holiday" When the engine computes deadlines for M Then it returns a deadline labeled Response Due with ruleId R and courtId CA-SC-LA And baseCountEnd (10 court days) = 2025-01-27 And bufferApplied = 5 calendar days And preliminaryDueDate = 2025-02-01 And dueAt = 2025-02-03T16:30-08:00 (rolled from weekend) And adjustments include weekend rollover for 2025-02-01 And timezone = America/Los_Angeles
Backward Count from Hearing to Opposition Due (Preceding-Day Rule)
Given court CA-SC-LA with cutoff 16:30 And anchor H = Hearing at 2025-03-14T08:30-08:00 And rule O = "Opposition due 9 court days before hearing; exclude the hearing day; if landing on weekend/holiday, move to the preceding court day" When the engine computes deadlines Then it returns a deadline labeled Opposition Due with ruleId O And dueAt = 2025-03-03T16:30-08:00 And countDirection = backward And units = courtDays And amount = 9
Time-of-Day Cutoff Shifts Anchor Start Day
Given court CA-SC-LA with daily filing cutoff 17:00 and timezone America/Los_Angeles And anchor F = Filing at 2025-05-01T17:05-07:00 And rule RP = "Reply due 2 court days after filing; exclude the filing day; roll to next court day if landing on weekend/holiday" When the engine computes deadlines Then the anchor counting start date is treated as 2025-05-02 (post-cutoff) And dueAt = 2025-05-06T17:00-07:00 And adjustments include cutoff shift from 2025-05-01 to 2025-05-02
Multiple Court Calendars Applied per Matter
Given matter M is associated to courts CA-SC-LA (tz America/Los_Angeles, holiday 2025-03-31) and NY-CC-NYC (tz America/New_York, no holiday on 2025-03-31) And anchor S = Service (personal) at 2025-03-28T10:00-07:00 And rule A = "Answer due 2 court days after service; exclude the day of service; roll to next court day if landing on weekend/holiday" When the engine computes deadlines for both courts Then for CA-SC-LA: dueAt = 2025-04-02T16:30-07:00 (3/31 holiday observed) And for NY-CC-NYC: dueAt = 2025-04-01T16:30-04:00 And each deadline contains the correct courtId and calendarId And no cross-calendar holidays or cutoffs are applied
Deadline Metadata and Labeling
Given a computed deadline for scenario "Forward Count with Mail Buffer and Holiday Rollover (LA Superior Civil)" When the deadline is retrieved from the engine output or API Then the deadline includes fields: id, label, ruleId, courtId, calendarId, anchorId, anchorType, dueAt (ISO 8601 with zone), timezone And it includes count {direction, unit, amount} and serviceMethod {type, bufferUnit, bufferAmount} And it includes adjustments[] with entries for weekend/holiday/cutoff shifts with from/to and reasonId And it includes dependencyGraph {nodes >= 2, edges >= 1} linking anchor -> deadline And it includes generatedAt and deterministicHash And recomputation with identical inputs yields the same deterministicHash and identical dueAt
Deterministic Recalculation on Anchor Update
Given matter M with anchor S = Service by Mail at 2025-01-10T15:00-08:00 and computed deadlines D1..Dn When S is updated to 2025-01-13T11:00-08:00 and recomputation is triggered Then only deadlines that depend on S are updated with new dueAt values And unaffected deadlines retain their ids and dueAt unchanged And updated deadlines have incremented version and new deterministicHash And two recomputations with the same inputs produce identical outputs
Matter Storage and API Retrieval
Given matter M has anchors and computed deadlines persisted by the engine When GET /api/v1/matters/{M}/deadlines?courtId=CA-SC-LA&anchorType=service&page=1&pageSize=50 is called Then the API responds 200 with deadlines sorted by dueAt ascending And each item includes ruleId, label, dueAt (ISO 8601 with timezone), courtId, anchorId, dependencyGraphRef And the response includes pagination metadata and an ETag header And subsequent GET with If-None-Match matching the ETag returns 304 And all timestamps reflect their court timezones
Court Holidays & Blackout Dates Sync
"As an attorney, I want court holidays to be automatically considered so that deadlines reflect actual court availability."
Description

Maintain authoritative holiday and closure calendars per court, including observed holidays, emergency closures, and shortened hours. Provide automated ingestion from trusted sources with fallbacks for manual entry and versioning with effective dates. Surface the specific holiday or closure that caused any date shift and persist the reference with each computed deadline. Integrate tightly with the rules engine so that adjustments are applied consistently during initial calculation and recalculation. The outcome is accurate date rollovers that reflect real court availability without manual checks.

Acceptance Criteria
Automated Court Holiday Ingestion with Effective Dating
Given trusted calendar sources are configured for each court When the scheduled ingestion job runs Then the system fetches new and updated events for each court and stores fields: court_id, source_event_id, name, type (holiday|closure|short_hours), starts_at, ends_at, effective_from, effective_to, source_url, and source_hash Given an event already exists and the incoming event differs by name, dates, type, or hours When ingestion processes the event Then a new version is created and the prior version is closed with valid_to set to the new version's valid_from, preserving history Given ingestion encounters an unreachable source or parse error When the job completes Then the court's calendar status is marked "stale", the error is logged with a correlation_id, and Holiday Admins receive an alert Given duplicate or unchanged events are received When the job processes them Then no new version is created and the job reports zero changes for those events
Manual Holiday Entry and Versioning Fallback
Given a user with the HolidayAdmin role When they create or edit a calendar event Then the system requires court, event name, type, start and end date-time, effective_from and effective_to, and a source_reference note Given a manual change is saved When the event matches an existing one by key (court, date/time range, type) Then a new version is recorded with audit fields (actor_id, timestamp, change_set), and the prior version remains in history Given a manual event conflicts with an automated-source event for the same court and period When the manual event is saved without selecting override Then the save is blocked with a conflict message listing the clashing event and its source; otherwise the manual version supersedes with an explicit override flag Given overlapping effective date ranges exist for the same event key When saving the manual event Then validation fails with an overlap error and no changes are persisted
Holiday/Closure/Hours-Aware Deadline Rollover
Given a matter is assigned to Court X and a computed deadline lands on a day Court X is closed per the effective calendar When calculating the deadline Then the rules engine moves the due date to the next open court day per Court X's rollover policy and records the pre-shift date Given the computed due time falls after posted shortened hours for the day When calculating the deadline Then the due time is moved to the next open day at opening time (or court-specific policy) and the adjustment is recorded Given a weekend day is not marked as open in Court X's calendar When a due date lands on that weekend Then the date rolls over to the next open day Given no holiday, closure, or shortened hours apply When calculating a deadline Then the original date and time are retained without adjustment
Cause-of-Shift Metadata Persistence and Display
Given a deadline was adjusted due to a holiday, closure, or shortened hours When the deadline is saved Then metadata is persisted including cause_type, calendar_event_version_id, event_name, event_date(s), court_id, and rollover_rule_citation Given a user views a shifted deadline in the app, an export, or a synced calendar When the deadline had an adjustment Then a human-readable explanation is shown including old date/time, new date/time, event name/type, and rule citation Given a deadline had no shift When displayed or exported Then no cause-of-shift message is shown
Recalculation and Notifications on Calendar Change
Given existing deadlines for Court X When a calendar event for Court X is added, removed, or its effective dates/hours change Then impacted deadlines are identified and recalculated within 10 minutes of ingestion completion Given a recalculation alters a deadline When the change is saved Then an audit entry is created capturing before/after date-time, triggering event version, and recalculation reason, and subscribers are notified with a summary of changes Given deadlines are synced to external calendars When a deadline changes due to recalculation Then the existing calendar event is updated using the same UID rather than creating a duplicate, and reminders are preserved or updated per policy
Court Scoping and Applicability Resolution
Given a matter has venue Court X (and optional division) When computing deadlines Then only Court X's calendar and division-specific events are applied, and statewide or superior-court events are included only if marked applicable to Court X Given a matter lacks a set venue When a user attempts to compute deadlines Then the system blocks computation and prompts selection of a court or a default jurisdiction calendar Given a matter involves multiple venues When computing venue-specific deadlines Then each deadline uses the appropriate court calendar for its venue context, and cross-venue holidays are not applied unless explicitly configured
Service Method Buffers & Counting Rules
"As an attorney, I want the system to account for how I served or was served so that response deadlines are accurate."
Description

Encode jurisdiction-specific buffers and counting nuances for service methods (personal, mail, overnight, e-service) including added days, start-day inclusion/exclusion, after-hours service handling, and mixed-method precedence. Drive selection from Briefly’s intake (captured service date/time and method) with sensible defaults and validation. Ensure the rules engine applies these adjustments before weekend/holiday rollovers and persists the chosen method for auditability. The outcome is service-aware deadlines that match local practice and eliminate manual buffer calculations.

Acceptance Criteria
Buffer Application by Service Method (Jurisdiction Profile J1)
Given jurisdiction profile J1 has service buffers configured as: personal=+0 calendar days, mail=+5 calendar days, overnight=+1 court day, e‑service=+0 days; and start-day is excluded; and after-hours cutoff is 5:00 PM local And a base period of 30 calendar days is defined for the obligation When the user records service method=mail with service timestamp=2025-03-03 14:30 local Then the preliminary due date (before weekend/holiday rollover) equals 2025-04-07 (start on 2025-03-04 + 30 calendar days = 2025-04-02, plus +5 calendar days buffer = 2025-04-07) Given the same profile J1 and a base period of 10 court days When the user records service method=overnight with service timestamp=2025-06-13 11:00 local Then the preliminary due date (before weekend/holiday rollover) equals 2025-06-30 (start on next court day 2025-06-16; 10 court days ends 2025-06-27; +1 court day buffer = 2025-06-30) Rule: The engine adds the configured buffer for the selected service method to the base period prior to weekend/holiday rollovers, honoring the buffer’s day type (calendar vs court).
Start-Day Exclusion and After-Hours Cutoff
Given start-day exclusion is enabled and the after-hours cutoff is 5:00 PM local for jurisdiction profile J1 When service is recorded at 2025-05-09 17:15 local (a Friday) Then the deemed service date is 2025-05-12 (next court day) And the counting start date is 2025-05-13 Given the same settings When service is recorded at 2025-05-09 16:45 local Then the deemed service date is 2025-05-09 And the counting start date is 2025-05-12 Rule: If service occurs after the configured cutoff, the deemed service date is the next court day; the day of deemed service is excluded from counting when start-day exclusion is enabled.
Weekend/Holiday Rollovers After Buffer Application
Given a computed preliminary due date (base period + method buffer applied) falls on a weekend or a configured court holiday for the venue When the preliminary due date is 2025-07-04 and 2025-07-04 is in the venue’s holiday list Then the final due date is 2025-07-07 (next court day) Given the preliminary due date is 2025-12-21 (a Sunday) Then the final due date is 2025-12-22 (next court day) Rule: Weekend/holiday rollovers occur strictly after applying service method buffers and base counting; no rollover is applied before buffers are added.
Mixed-Method Precedence Selection
Given the jurisdiction profile J1 defines mixed-method precedence as [personal, overnight, e‑service, mail] When both e‑service and mail service records exist for the same document Then the controlling method is e‑service And the selected method is persisted with the precedence rationale When personal service is recorded in addition to any other method Then the controlling method is personal Rule: When multiple service methods exist, the engine deterministically selects the controlling method by the configured precedence list and uses only that method’s buffers/counting for the deadline.
Intake-Driven Defaults and Validation
Given Briefly’s intake captured service method=mail and service timestamp=2025-03-03 14:30 America/Los_Angeles for the document When the user opens Deadline Mapper for that document Then the service method defaults to mail and the date/time field is prefilled with 2025-03-03 14:30 PT And the Save action is enabled only if method, date, and time are present Given no service method is captured in intake When the user attempts to save a deadline Then Save is blocked and an inline error "Select a service method" is shown Given a date is entered without a time Then an inline error "Time of service required" is shown and Save remains disabled Given venue time zone is America/Los_Angeles When the user enters 2025-03-03 14:30 local Then the stored timestamp includes timezone metadata and displays correctly in local time Rule: Service timestamps cannot be in the future at save time; attempts to save future timestamps are blocked with an inline error.
Persistence and Audit Trail of Service Method and Rules
Given a deadline is saved Then the system persists: selected service method, service timestamp, deemed service date, start-day inclusion/exclusion setting, after-hours cutoff applied flag, buffer value and day type, mixed-method precedence decision (if any), base period definition, jurisdiction profile ID and version, and rule citations/links used And these fields are read-only on the saved record When any change is needed Then a new version is created capturing the modifier, timestamp, changed fields, and prior values And the audit history is viewable and exportable (CSV/PDF) including rule references Rule: The persisted calculation record must be sufficient to reproduce the deadline deterministically from inputs and the referenced rules profile without external assumptions.
Transparent Rule Citations & Calculation Audit Trail
"As an attorney, I want to see the rule and the math behind each deadline so that I can verify and defend the calculation if challenged."
Description

For every computed deadline, display the governing rule citation(s) and a step-by-step breakdown of the calculation (anchor date, buffer days, holiday/weekend adjustments). Link to the rule text where available and store a versioned snapshot of the rule set used. Provide exportable audit records (PDF/CSV) and a change log when recalculations occur. This transparency builds trust, eases verification, and supports defensibility if deadlines are challenged.

Acceptance Criteria
Display Rule Citations With Links
Given a computed deadline is displayed for a matter When the deadline row renders Then the governing rule citation or citations are shown including jurisdiction, rule number, subsection, and edition year And when an official online source exists Then a hyperlink opens the rule text in a new tab and returns HTTP 200 within 2 seconds And if no official link exists Then the citation displays without a link and a tooltip states No online text available
Step-by-Step Calculation Breakdown
Given a user expands the deadline details When the breakdown panel opens Then the audit lists in order the anchor event and date, counting method, service method buffer days, intermediate date after buffer, holidays and weekends encountered, adjustment rule applied for each encounter, final computed date and time, and timezone And each step includes the specific rule clause applied and the numeric values used And the final computed date equals the value shown in the deadline list
Versioned Rule Set Snapshot Stored
Given a deadline is computed When computation completes Then the system saves a snapshot identifier that includes jurisdiction, rule set version or publication date, and holiday calendar version And the deadline record stores the snapshot identifier, compute timestamp, and application build version And previously computed deadlines continue to reference their original snapshot after any rule updates
Export Audit Record to PDF and CSV
Given a user selects Export Audit for a deadline When PDF is selected Then a PDF downloads containing matter identifiers, deadline date and time and timezone, anchor event and date, full step-by-step breakdown, applied rule citations with links, snapshot identifier, compute timestamp, initiating user, and file checksum And the PDF content matches the on-screen values exactly When CSV is selected Then a CSV downloads with equivalent fields in normalized columns And each export completes within 5 seconds for a single deadline
Recalculation Change Log
Given a deadline is recalculated due to rule or data changes When recalculation occurs Then a change log entry records previous deadline value, new deadline value, reason category, initiating user or system process, timestamps, previous and new snapshot identifiers, and a diff of the breakdown steps And the UI displays a Recalculated badge with a link to the change log And exported audit records include the complete change log history
Broken or Outdated Rule Link Handling
Given a citation link fails validation or returns non 200 When the daily link validator runs Then the citation in the UI is shown without a hyperlink and a warning indicator labeled Verification required And the incident is logged with URL, status code, and timestamp and a notification is sent to maintainers And the deadline record remains available with the citation text and snapshot intact When the link validates successfully on a subsequent run Then the warning is removed and the hyperlink is restored
Calendar Push & Two-way Sync
"As an attorney, I want deadlines to appear on my calendar with reminders so that I get timely prompts without manual entry."
Description

Create and maintain events/tasks on Google Workspace and Microsoft 365 calendars for all computed deadlines, including reminders, time zones, and per-matter calendar selection. Include rule citations and calculation notes in event descriptions. Support two-way sync to reflect updates from Briefly into calendars and propagate accepted date changes back to Briefly when appropriate. Handle authentication via OAuth with secure token storage, rate limiting, retries, and conflict resolution. The outcome is seamless visibility of deadlines where attorneys actually plan their day.

Acceptance Criteria
Create Calendar Events for Computed Deadlines
Given a matter with computed deadlines and a selected destination calendar on Google or Microsoft And the user has completed OAuth authorization for the chosen provider When the user enables calendar push for the matter Then an event is created for each deadline on the selected calendar with the correct start and end datetime in the matter time zone And events are created within 60 seconds for up to 100 deadlines And reminders are created as configured, with at least one default reminder at T-24 hours if none is set And the event organizer matches the authenticated account And per-matter calendar selection is honored and no events appear on unselected calendars
Include Rule Citations and Calculation Notes in Event Description
Given a computed deadline with rule citations and calculation notes When the corresponding calendar event is created or updated Then the event description contains the rule citation(s) and calculation notes including any service-method buffers applied And the description includes a deep link back to the Briefly matter and specific deadline And the description length stays within provider limits and is not truncated mid-field And formatting remains readable on both Google and Microsoft calendars
Two-way Sync: Briefly Updates Propagate to Calendars
Given an existing synced event on a provider calendar When the deadline title, date/time, description, or reminders are changed in Briefly Then the corresponding calendar event is updated to match within 2 minutes And the provider event ID and sync token are preserved to avoid duplication And no duplicate events are created during update And user-configured attendee notification settings are respected when sending updates
Two-way Sync: Accepted Calendar Date Changes Propagate to Briefly
Given a synced event that is editable on the provider calendar And Briefly is configured to accept external date/time changes for the matter When an authorized user changes only the start date/time on the provider calendar (not deleting or cancelling) Then Briefly updates the linked deadline date/time within 5 minutes And logs the before/after values with the provider user identity where available And if the new date/time violates governing rule constraints, Briefly flags a conflict for review and does not overwrite until resolved
Conflict Resolution for Concurrent Edits
Given a deadline/event is edited in Briefly and on the provider calendar within the same sync window When the sync runs Then the system detects the version conflict using ETag or sequence IDs And applies the rule: Briefly changes win unless the provider edit is an explicit user date/time change and external changes are enabled, in which case the provider change wins And the outcome is recorded with both versions preserved in an audit log And the user is notified in-app with options to override or revert
OAuth Authentication and Secure Token Storage
Given a user connects a Google or Microsoft account When the OAuth flow completes Then access and refresh tokens are stored encrypted at rest using application key management And tokens are requested with minimum calendar read/write scopes required And token refresh occurs automatically before expiry without user action And on revocation or invalid_grant/401 responses, syncing pauses, the user is prompted to reconnect, and no tokens are logged in plaintext
Rate Limiting, Retries, and Error Handling
Given provider APIs return 429 or 5xx responses during sync When creating or updating events Then the system retries with exponential backoff and jitter up to 5 attempts And observes provider quota headers to avoid exceeding limits And partial failures are queued and retried for up to 24 hours before surfacing as errors And users see a clear sync status indicating pending, success, or failure And under normal load, eventual consistency is achieved within 10 minutes
Auto Recalculation on Trigger Events
"As an attorney, I want deadlines to update when input dates change so that my schedule stays accurate without rework."
Description

Continuously monitor for trigger events such as amended service dates, continuances, extensions, or corrected court selections. When detected, recalculate affected deadlines, present a diff highlighting changes, and allow the user to accept, reject, or annotate updates. Automatically update linked calendar entries, notify assignees, and log all changes in the audit trail. Support scenario simulations to preview outcomes before committing. The outcome is an always-current schedule without duplicated effort.

Acceptance Criteria
Amended Service Date Triggers Recalculation and Review
Given a matter with deadlines generated by Deadline Mapper and a recorded service date And a jurisdiction and service method are set When the service date is amended via intake update or synced docket event Then all deadlines dependent on service date are recalculated per jurisdictional rules and service buffers And a diff lists each affected deadline with old date, new date, delta (days), rule reference, and reason "Amended service date" And the user can Accept All, Reject All, or Accept/Reject individual deadline updates And annotations can be added; a note is required when rejecting any update And no calendar updates or notifications occur until acceptance And recalculation and diff render within 3 seconds for up to 50 deadlines
Continuance or Extension Recomputes Only Dependent Deadlines
Given a continuance or extension is recorded for a hearing or due event When the new date or added days are entered or synced Then only deadlines dependent on the continued/extended event are recalculated; unrelated deadlines remain unchanged And weekend, court holiday, and service-method buffers are applied correctly And removed/superseded deadlines are marked as Removed in the diff with rule references And recalculation completes within 3 seconds for up to 50 deadlines
Calendar Updates Occur In-Place Without Duplication
Given the user accepts a change set that modifies deadlines with linked calendar events Then existing calendar events are updated in-place (retain event IDs); no duplicate events are created And reminders adjust to preserve original lead times relative to the new dates/times And deleted deadlines result in calendar event cancellations And updated event description includes "Updated by Deadline Mapper", rule reference, and audit link And the push to connected calendars initiates within 60 seconds of acceptance
Assignee Notifications on Accepted Changes
Given a change set is accepted Then assignees and watchers receive a notification within 60 seconds And the notification contains matter name, change summary (count changed/added/removed), first three line items, link to full diff, and effective dates And no notifications are sent for rejected or simulated change sets And recipient notification preferences (email/mobile/in-app) are respected
Comprehensive Audit Trail of All Change Decisions
Given any change set is accepted or rejected Then an immutable audit entry is created with timestamp, actor, trigger source (e.g., amended service date, continuance), affected deadlines with before/after, rule references, decision (accept/reject), and any annotation And audit entries are filterable by matter, user, trigger type, and date range And each audit entry has a unique ID and can be exported to PDF/CSV And viewing an audit entry requires appropriate matter access
Scenario Simulation Provides Zero-Side-Effect Preview
Given a user initiates a simulation (e.g., alternate service date, continuance, or court selection) When the simulation is run Then a diff is displayed labeled "Simulation" with calculated outcomes and rule references And no calendar updates, notifications, or audit entries are created by simulations And the user can save the simulation for up to 24 hours and convert it to an actionable change set with one click And upon conversion, the actual change set revalidates inputs and proceeds through the standard acceptance flow
Corrected Court Selection Reapplies Local Rules and Holidays
Given a matter's court selection is corrected to a different court/jurisdiction When the court is changed Then all relevant deadlines are recalculated using the new court's local rules, holidays, time zone, and service-method buffers And the diff shows added, removed, and changed deadlines with rule citations and reason "Corrected court selection" And only affected deadlines change; unaffected deadlines remain unchanged And recalculation completes within 3 seconds for up to 50 deadlines
Intake Data Validation & Jurisdiction Detection
"As an attorney, I want the intake to capture the right dates and court info so that Deadline Mapper has everything needed to calculate correctly."
Description

Enhance Briefly’s guided questionnaire to capture required anchors (service/filing dates, method, time, court) with inline validation, date/time sanity checks, and required-field enforcement. Auto-detect jurisdiction from court selection or case metadata and pre-load the correct rule set. Provide clear error messages and confirmations to minimize missing or incorrect data. Feed validated inputs directly into the Deadline Mapper for immediate, accurate computation. The outcome is fewer errors and faster intake-to-calendar automation.

Acceptance Criteria
Inline Validation of Required Intake Anchors
- Given the intake form is loaded, when a required field is left blank and loses focus, then the field is highlighted, an inline message "This field is required" appears within 300 ms, and aria-invalid="true" is set. - Given an invalid date string is entered (not MM/DD/YYYY), when the field loses focus, then show "Enter a valid date (MM/DD/YYYY)" and prevent proceed. - Given all visible required fields (Service/Filing Date, Service/Filing Time, Service Method, Court) are valid, then the Continue button is enabled; otherwise it remains disabled. - Given at least one required field is invalid, when the user presses Continue, then focus moves to the first invalid field and a summary banner lists the total error count.
Date/Time Sanity Checks for Service and Filing Events
- Given a date is entered, when the value is not a real calendar date (e.g., 02/30/2025) or outside 1900–2100, then reject the input and show "Enter a real calendar date". - Given a time is entered, when it is not a valid 12-hour or 24-hour time, then show "Enter a valid time (e.g., 2:30 PM)" and prevent proceed. - Given the entered date is earlier than 01/01/2000 or more than 365 days in the future, when the user attempts to continue, then display a confirmation modal summarizing the outlier and require explicit Confirm before proceeding. - Given date and time are entered, then store the combined timestamp in the selected court's time zone and display the zone label next to the time.
Jurisdiction Auto-Detection from Court Selection
- Given the user selects a court, then the system resolves jurisdiction (at minimum State and Court Level) and loads the corresponding rule set version within 1 second. - Then the UI displays "Rules loaded: {RuleSetName} v{Version} for {Jurisdiction}" and a "View rule references" link. - Given the selected court maps to multiple divisions, when a tie exists, then prompt the user to choose a division before rules are loaded.
Fallback Jurisdiction Detection from Case Metadata
- Given the Court field is not selected, when a case number pattern matches a known court mapping, then auto-detect jurisdiction and pre-populate Court and Rule Set with an inline note "Detected from case number". - Given no deterministic mapping is found, then display a non-blocking banner "Select Court to load rules" and keep Continue disabled until a court is chosen. - Given both case number and court are supplied and conflict, then prioritize the explicit Court selection, show a warning "Court and case number imply different jurisdictions", and offer "Keep Court" or "Use Case Number" options.
Clear Error Messaging and Field Highlighting
- Given any validation error occurs, then the message is plain-language, field-specific, and includes the expected format or allowed values; reading grade ≤ 8 by Flesch-Kincaid. - Then errors are associated via aria-describedby and announced by screen readers; on submit, keyboard focus moves to the first errored field. - Given the user fixes the error, then the inline message and highlight clear within 200 ms and the summary banner updates the error count.
Immediate Deadline Computation After Validation
- Given all required anchors are valid and a rule set is loaded, when the user selects Confirm & Compute, then the validated payload (including ruleSetId and anchors) is sent to Deadline Mapper and a response with computed deadlines is received within 2 seconds at the 95th percentile. - Then the deadlines list renders with each deadline showing its rule citation; if no deadlines are applicable, show "No deadlines derived from provided anchors" without error. - Given the Deadline Mapper API returns an error, then show a retryable error with a correlation ID and do not create calendar tasks.

Instant QR Sign

Display a single-use, time-limited QR code that launches a combined e‑sign + ID check on the client’s phone. No app or kiosk login required—clients scan, confirm, and sign in one guided flow. Cuts curbside back‑and‑forth, speeds engagement, and reduces staff handling of client devices.

Requirements

Single-Use, Time-Limited QR Generation
"As an intake paralegal, I want to display a single-use QR tied to the matter so that the client can start on their own phone without me handling their device."
Description

Generate a cryptographically secure, single-use token bound to a specific matter and signer, encode it as a QR code, and enforce configurable expiry (e.g., 10–30 minutes). The token must be invalidated on first successful launch or timeout, resist replay, and be rate-limited to mitigate abuse. The QR payload contains no PII; resolution occurs server-side against Briefly’s matter records. Provide easy issuance from the matter view, support branded display/print, and persist session metadata for monitoring. All events are logged for audit, and regenerated codes supersede prior tokens automatically.

Acceptance Criteria
Generate Single-Use QR Token From Matter View
Given an authenticated staff user is viewing a matter with a designated signer When they click "Generate Instant QR" and confirm Then the system creates a cryptographically secure token with at least 128 bits of entropy using a CSPRNG And the token is server-signed (e.g., HMAC-SHA256 or equivalent) to prevent tampering And a QR code is rendered within 2 seconds that encodes only an HTTPS URL containing the opaque token And the QR display includes firm branding (logo and colors), a visible expiry countdown, and controls for Fullscreen and Print And the issuance event is recorded with issuer user ID, matter ID, signer ID, token ID (hashed), created_at (UTC), and configured TTL
Configurable Token Expiry (10–30 Minutes)
Given the workspace has a configured token expiry value between 10 and 30 minutes (default 15 minutes) When a new token is generated Then the token's TTL equals the configured value And the token cannot be redeemed more than 5 seconds after its TTL elapses And any post-expiry redemption attempt returns HTTP 410 Gone with reason "Token expired" and no session is created And updating the expiry configuration only affects tokens generated after the change; previously issued tokens retain their original TTL
Single-Use Enforcement and Replay Resistance
Given a valid, unredeemed token When the client scans the QR and opens the URL Then the first successful redemption transitions the token state to "consumed" and initiates the target flow And any subsequent redemption attempt for the same token from any device, browser, or IP returns HTTP 410 Gone with reason "Token already used" And under concurrent requests, at most one redemption succeeds; all others fail with 409/410 and are logged as replay attempts And the token value is never persisted in client storage (cookies/localStorage/sessionStorage)
No-PII Payload with Server-Side Matter/Signer Resolution
Given a generated QR code When the QR payload is extracted and inspected Then it contains only an opaque token (and optional routing prefix) and no PII or identifiers such as name, email, phone, address, matter ID, or docket And the HTTPS endpoint resolves the token server-side to exactly one matter and the designated signer And if the token does not resolve or the resolved signer/matter does not match the expected pairing, redemption is rejected with HTTP 403 Forbidden And requests to the endpoint without a token return HTTP 404 Not Found
Rate Limiting and Abuse Mitigation
Given repeated redemption requests are made for the same token or from the same IP When requests exceed thresholds (per-token: >5 attempts per 10 seconds; per-IP: >60 attempts per minute; per-workspace: >500 attempts per hour) Then subsequent requests receive HTTP 429 Too Many Requests with an accurate Retry-After header And threshold values are configurable by administrators within documented ranges and can be updated without redeploy And rate-limited events are logged with token ID (hashed), IP, user agent, timestamp (UTC), and limit bucket hit And limits automatically reset after their respective windows/cooldowns
Regeneration Supersedes Prior Tokens
Given a matter and signer with an existing unexpired token When a staff user selects "Regenerate QR" Then a new token is created and displayed And all prior tokens for the same matter+signer are immediately invalidated and return HTTP 410 Gone with reason "Superseded" upon redemption And the supersession is logged, linking old token IDs to the new token ID And the UI indicates that previously issued QR codes are no longer valid
Audit Logging and Session Metadata Persistence
Given issuance, redemption (success/failure), expiration, regeneration, and rate-limit events occur When each event is processed Then an immutable audit record is stored with event type, token ID (hashed), matter ID, signer ID, actor (user ID or IP), user agent, timestamp (UTC), outcome, and correlation/request ID And session metadata persists created_at, first_seen_at, last_seen_at, redemption IPs, and device/user-agent fingerprint for monitoring And authorized users can filter and export events by matter, signer, date range via UI and API (CSV/JSON) And audit records are read-only and retained for at least 1 year
Passwordless Mobile E‑Sign Launch
"As a client, I want to scan and sign in one guided mobile flow without creating an account so that I can engage quickly and privately at curbside or in the lobby."
Description

Upon QR scan, open a secure mobile web flow that requires no login or app, directly loading the client’s preassembled retainer and first-draft documents with e-sign inputs prefilled from Briefly’s questionnaire. The flow collects ESIGN/UETA consent, guides the signer step-by-step, validates required fields, and blocks signature until ID verification is satisfied. It must be device-agnostic (modern iOS/Android browsers), responsive, WCAG 2.1 AA accessible, support session resume, and localize copy as configured. On completion, lock documents, apply signatures, and return the client to a confirmation screen with next steps.

Acceptance Criteria
QR Scan Launches Passwordless Session
Given a QR code generated for Matter X with a 15-minute TTL and single-use token T When a client scans the QR with a modern iOS or Android device and opens the link in the default browser Then the flow loads over HTTPS without requiring login, username, password, or app install And token T is validated, bound to the session, and invalidated after the first successful session start And if token T is expired or already used, the client sees an Expired/Used code message with instructions to request a new code And the initial screen renders within 2 seconds on a 4G connection (p95) and is functional on iOS Safari and Android Chrome current and previous major versions
Prefilled Retainer and Draft Load
Given the matter has a preassembled retainer and first‑draft documents with questionnaire data D When the flow loads the signing package Then all e‑sign input fields are prefilled from D where available And any missing required data is clearly flagged for completion in‑context before signing And document titles, page order, and pagination match the server package And the signing package renders within 4 seconds on a 4G connection (p95)
ESIGN/UETA Consent Gate
Given the client has not provided ESIGN/UETA consent in this session When the consent screen is displayed Then the consent text configured for the firm is shown in full with a clear affirmative action control And the client cannot access signature fields until consent is affirmatively provided And if the client declines, the session ends with a non‑success state and no signatures applied And upon acceptance, the audit log records timestamp, IP, user agent, and consent language version
ID Verification Required Before Signing
Given ID verification is enabled for the matter When the client attempts to proceed to signing Then the ID verification step is presented and must be completed successfully before any signature can be applied And the Sign/Finish actions remain disabled until verification status = passed And on failure the client may retry up to 3 times before the session is locked and the QR token invalidated And the audit log records verification outcome, timestamp, and verification provider reference
Guided Flow, Required Field Validation, and Accessibility
Given the client progresses through the step‑by‑step signing flow When a required field is empty or invalid Then inline, WCAG‑compliant error messaging is announced to screen readers, associated with the field, and prevents progression And the client can navigate the entire flow with touch and keyboard, with visible focus states and a logical focus order And all text meets 4.5:1 contrast ratio, controls have accessible names/labels, and no horizontal scrolling occurs at 320px width And the Finish action remains disabled until all required fields are complete and valid
Session Resume and Localization
Given the client closes the browser mid‑flow and returns within 60 minutes on the same device When the client reopens the QR link or navigates back via history Then the session resumes at the last completed step with previously entered data intact And if the session has expired, a clear expiration message is shown with instructions to obtain a new QR code And all UI copy, consent text, error messages, and date/time formats display in the locale configured for the matter with fallback to English if missing And right‑to‑left languages render correctly where configured
Completion: Lock, Apply Signatures, and Confirmation
Given all required steps are complete and the client selects Finish When the signing package is submitted Then signatures and initials are applied to all designated fields and documents are flattened and locked with a tamper‑evident hash And the system generates finalized PDFs and stores them under the matter with a complete audit trail And the client is redirected to a confirmation screen within 2 seconds (p95) showing configured next steps And the QR token and session are invalidated and cannot be reused
Integrated ID Verification Workflow
"As an attorney, I want automated ID verification built into the signing flow so that I can reduce fraud risk and meet compliance without extra steps for staff."
Description

Embed an ID check before signing using a third‑party provider (e.g., Onfido, Persona, Stripe Identity) with government ID capture, selfie with liveness, and automated match scoring. Collect explicit consent, handle edge cases (blurry images, retries, manual review), and expose configurable pass/fail rules per matter type. Store the verification result, evidence artifacts, and decision rationale with retention controls. The signature step remains locked until the verification outcome meets the configured threshold or a staff override with reason is recorded. Failures route the client to helpful guidance and staff are alerted in real time.

Acceptance Criteria
Consent Gate Before ID Verification
Given a client launches the Instant QR Sign flow When the flow begins Then the client is shown a consent screen describing ID verification, data use, provider, and retention And the client must actively agree via a checkbox and Continue button before proceeding And the system records timestamp, IP, device fingerprint, consent text version, and provider name in an immutable audit log And if consent is declined, the flow terminates, signature remains locked, and assigned staff are notified within 30 seconds
Automated Verification Unlocks Signature
Given consent is recorded and the client proceeds to verification When government ID (front and back) is captured and selfie liveness is completed And the provider returns a match score greater than or equal to the configured threshold for the matter type Then the signature step becomes unlocked within 2 seconds of the decision And the system advances the client to the e‑sign package And decision, score, provider transaction ID, and applied rule version are persisted to the matter record
Retry Handling for Low-Quality Captures
Given the provider flags blur, glare, cutoff, or unreadable barcode/MRZ on a capture When the client retries capture up to the configured limit (default 3) Then contextual guidance with specific tips is displayed after each failed attempt And the capture UI enforces edge detection and autofocus prompts And after the retry limit is reached, the flow routes to manual review, signature remains locked, and staff are notified
Manual Review and Staff Override
Given automated verification returns indeterminate, timeout, or a score below threshold When staff open the verification review screen Then staff can approve or reject with a required reason code and free‑text note And if approved, the signature step unlocks immediately and the override is recorded with reviewer, timestamp, reason, and related artifacts And if rejected, the client receives guidance and next steps; signature remains locked And all overrides are captured in the audit trail and are exportable
Configurable Rules per Matter Type
Given an admin configures verification rules for a matter type When a new Instant QR Sign session starts for that matter type Then the system enforces the selected provider, allowed ID types, liveness requirement, match threshold, retry limit, and auto‑decline rules And rule changes are versioned, take effect only for new sessions, and are displayed on the decision record And admins can run a sandbox test with sample provider responses before enabling changes
Evidence Storage and Retention Controls
Given a verification attempt completes (pass, fail, or override) When artifacts are stored Then decision, score, provider result reference, redacted ID images, selfie/liveness evidence, and decision rationale are persisted And artifacts are encrypted at rest, access‑controlled to authorized roles, and access events are logged And retention settings per matter type purge or redact artifacts after the configured period with an immutable log of purge actions
Real-Time Alerts and Client Guidance on Failure
Given automated verification fails or routes to manual review When the decision is returned by the provider or the system timeout is reached Then the client is shown clear next steps with retry or contact options as applicable And assigned staff receive an in‑app notification and email/SMS within 30 seconds including client name, matter ID, reason, and action link And the session remains paused with signature locked until resolution or override
Real-Time Session Status & Alerts
"As a solo attorney, I want to see live progress and get alerts during QR sign so that I can intervene quickly if the client gets stuck and keep matters moving."
Description

Provide a live status panel on the matter showing QR issued, scanned, ID in progress, ID passed/failed, signing started, completed, or expired, with countdown timers and the ability to cancel or regenerate a session. Push instant alerts to assigned staff on key transitions (scan, fail, completion) via in-app notifications and optional email/SMS. Update matter timeline and engagement stage automatically upon completion or failure, and capture metrics for throughput and drop-off analysis.

Acceptance Criteria
Live Status Panel State Transitions
- The status panel displays only one current state from: QR Issued, Scanned, ID In Progress, ID Passed, ID Failed, Signing Started, Completed, Expired, Canceled. - On each backend event, the panel updates within 2 seconds without manual refresh for all viewers of the matter. - Each state shows a human-readable label, server timestamp (matter timezone), and the triggering actor/source (system/client/staff). - Disallowed transitions are ignored and logged; only these transitions are permitted: Issued → Scanned → ID In Progress → (ID Passed | ID Failed) → Signing Started → Completed; Issued/Scanned/ID In Progress/Signing Started may transition to Expired or Canceled at any time. - Out-of-order or duplicate events do not regress the displayed state and are deduplicated in the UI. - Refreshing the page or opening the matter in a new session preserves the latest state from the server.
Countdown Timers and Expiry Behavior
- Each session displays a mm:ss countdown initialized to the server-defined TTL (default 10:00) and decrements every second. - The countdown visual stays within ±1 second of server time over any 5-minute interval. - At TTL expiry, the session atomically transitions to Expired; the QR and deep link become invalid immediately. - Scanning an expired QR shows an "Session expired" message on the client flow and records an Expired event tied to the matter. - The status panel switches to Expired within 2 seconds of server expiry and surfaces a Regenerate action to authorized staff. - Regenerated sessions reset the countdown and do not reuse prior QR codes or links.
Cancel and Regenerate Session Controls
- Only users assigned to the matter with permission "Manage QR Sessions" can cancel or regenerate a session. - Cancel requires explicit confirmation; upon cancel, the session transitions to Canceled, invalidates the QR/link within 2 seconds, and prevents further client progress. - Regenerate ends the current session and creates a new single-use session with a new QR/link within 3 seconds; the previous session cannot be resumed. - The status panel reflects Canceled or the new session state immediately and displays the correct session identifier (redacted) and start time. - All cancel/regenerate actions write immutable audit entries with actor, timestamp, and reason (if provided).
In-App Notifications on Key Transitions
- In-app notifications fire for: QR Scanned, ID Failed, and Completed events. - Notifications are delivered to all assigned staff on the matter (respecting per-user mute settings) within 2 seconds of the event. - Each notification includes matter reference, client initials (not full PII), the event type, and a deep link to the matter status panel. - Duplicate notifications for the same event and user within 60 seconds are suppressed. - Delivery and user-open timestamps are recorded per recipient for audit and analytics.
Email and SMS Alerts with Preferences
- Email/SMS alerts are sent only to users who have explicitly opted in per channel and per event type. - For ID Failed and Completed, email is sent within 60 seconds and SMS within 30 seconds of the event; QR Scanned alerts follow the same SLAs if enabled. - Messages include minimal PII (client initials), matter reference, event type, and a secure deep link; no sensitive identifiers are exposed. - Up to 3 retry attempts with exponential backoff are performed on transient failures; hard bounces/invalid numbers are marked and not retried. - Per-user rate limiting prevents more than 5 alerts per session per channel; duplicates for the same event are suppressed across channels if delivered in one. - Unsubscribe and notification preference links are present in emails; SMS includes a STOP instruction where applicable.
Automatic Timeline and Engagement Stage Updates
- On Completed, a timeline entry "Engagement signed via Instant QR Sign" is added with server timestamp and session reference; the engagement stage updates to Signed. - On ID Failed, Expired, or Canceled, a timeline entry is added with the failure/expiry reason; the engagement stage updates to Needs Attention. - Updates are idempotent and apply only to the most recent session for the matter; prior sessions cannot overwrite a later Completed stage. - Timeline entries record actor as System, include pertinent metadata (event, timestamps), and are visible immediately in the matter view. - Reprocessing of delayed events does not create duplicate timeline entries or oscillate the engagement stage.
Analytics: Throughput and Drop-Off Metrics
- The system records timestamps for: QR Issued, First Scan, ID Start, ID Passed/Failed, Signing Start, Completed, Expired, Canceled. - For each session, the system computes and stores: time-to-scan, ID duration, signing duration, and total time-to-complete. - Each session is labeled with a terminal outcome: Completed, Failed ID, Expired, Canceled, or Abandoned (no scan within TTL). - Metrics are captured server-side with 99% completeness over a rolling 30-day period and are queryable by matter, user, date range, and outcome. - Events are deduplicated by session ID; clock skew is eliminated by relying on server event times only. - Captured metrics exclude sensitive PII and reference matters by ID and client initials only.
Evidence Bundle & Audit Trail
"As a compliance-minded practitioner, I want an automatically generated evidence bundle so that I can defend the validity of signatures and identity checks if challenged."
Description

On completion, compile a tamper‑evident evidence package including signed PDFs, ESIGN consent record, full event log (timestamps, IP, user agent), QR token ID linkage, ID verification report and artifacts, and a certificate of completion with cryptographic hash. Store it with the matter, enable download and secure external sharing, and ensure retention and purge policies align with legal requirements. All records must be immutable and defensible for court and e‑discovery.

Acceptance Criteria
Bundle Assembled on Completion
Given a client completes the Instant QR Sign flow for a matter When the completion event is recorded Then the system generates an evidence bundle within 60 seconds And the bundle includes: signed PDF(s), ESIGN consent record (text snapshot + timestamp), full event log (event type, ISO 8601 UTC timestamp, IP, user agent), QR token ID linkage, ID verification report and artifacts, and a certificate of completion with SHA-256 hash(es) And the bundle is assigned a unique bundle ID and associated to the matter
Cryptographic Integrity and Tamper Evidence
Given an evidence bundle has been generated When hashes are recomputed for each file using SHA-256 Then the computed hashes match the values recorded in the certificate/manifest And altering any file causes a verification mismatch And the certificate of completion contains: signer identity, creation timestamp (UTC), per-file SHA-256, and an overall manifest hash And verification can be performed using standard SHA-256 tooling without proprietary software
Immutable Storage and Matter Association
Given an evidence bundle is stored with a matter When any user attempts to modify or delete bundle contents prior to retention expiry Then the operation is blocked and returns 403 Forbidden And all read, share, export, and failed mutation attempts are logged (user, timestamp UTC, IP) And the bundle is visible under the matter record with bundle ID, created timestamp, and retention policy label
Comprehensive Event Log Coverage
Given the Instant QR Sign session lifecycle When the evidence bundle is generated Then the event log contains an ordered, monotonic sequence for: QR issued, QR scanned, ESIGN consent accepted, ID verification start/result, documents rendered, signatures applied, completion, bundle created, share link lifecycle events And each entry includes: event type, ISO 8601 UTC timestamp (ms precision), actor (e.g., Client/User ID/System), IP address, user agent, and outcome (success/failure) And timestamps are non-decreasing and reflect UTC
QR Token Single-Use and Traceability
Given a single-use, time-limited QR code is displayed When it is scanned by a client device Then the evidence captures: QR token ID, issued-at timestamp, expiry timestamp (default 15 minutes), first-scan timestamp, first-scan IP and user agent And subsequent scans after redemption are logged with status "used" and do not create a new session And the QR token cannot be reused after expiry or successful redemption
ID Verification Evidence Capture and Access Control
Given ID verification is part of the flow When verification completes with pass or fail Then the bundle includes: vendor name/version, transaction/reference ID, result (pass/fail), score or risk band, checks performed (e.g., liveness, document authenticity), failure reason codes (if any), and artifacts (e.g., ID images, selfie/liveness frames) And access to raw artifacts requires authorized roles and explicit access acknowledgement, with all accesses logged And evidence is retained even on failure, with outcome clearly marked
Secure Download, External Sharing, Retention and Purge
Given a completed evidence bundle exists When an authorized user requests download Then delivery occurs over TLS 1.2+ and includes the certificate/manifest with hashes And the user can create a secure external share link with configurable expiry (1–30 days), optional passcode, scope limited to this bundle; all views/downloads are logged; links are revocable with immediate effect And a retention policy is attached based on matter/jurisdiction; at expiry the bundle is purged within 24 hours and a proof-of-deletion receipt is recorded; legal holds prevent purge until released And an e-discovery export can be generated as a single ZIP containing signed PDFs, ESIGN record, event log (CSV and JSON), ID verification report/artifacts, and the manifest with checksums
Failure Handling & Alternate Delivery
"As intake staff, I want reliable fallbacks if a client can’t scan the QR so that we can still complete engagement without delay."
Description

Offer seamless fallbacks when QR fails: send a one-time magic link via SMS/email, allow short code entry, and enable session resume across channels while preserving security and audit continuity. Provide clear client-facing error messaging, rate-limit retries, and auto-expire abandoned sessions. Expose admin controls to disable certain channels, and capture reason codes for failures to inform future optimization.

Acceptance Criteria
QR Scan Failure → SMS Magic Link Fallback
Given a client fails to launch from the QR (timeout, unreadable, or network error) and staff selects "Send SMS Link" with a verified number When the action is confirmed Then the system issues a single-use magic link with a 10-minute TTL and ≥128-bit random token, and sends via SMS within 5 seconds And the original QR token is immediately invalidated And tapping the link opens the same e‑sign + ID check session without login And the audit log records timestamp, staff user ID, masked phone (last 2 digits), channel=SMS, correlation ID, and prior QR failure reason And if SMS delivery fails, staff sees a delivery failure notice within 15 seconds with failure code and retry/alternate options
QR Scan Failure → Email Magic Link Fallback
Given a client cannot use the QR and provides a verified email When staff selects "Send Email Link" Then the system issues a single-use magic link with a 30-minute TTL and ≥128-bit random token and sends within 15 seconds And the email uses a branded template with subject including firm name and expires-at timestamp And the original QR token is immediately invalidated And clicking the link launches the same e‑sign + ID check session without login And the audit log records timestamp, staff user ID, masked email, channel=Email, correlation ID, and prior QR failure reason And if the email hard-bounces, staff is notified with reason code and the link is revoked
Short Code Entry Alternative Join
Given staff generates a 6-digit short code for the active session When the client visits the public join URL and enters the code Then the code is valid for 5 minutes, single-use, and rate-limited to 5 attempts per minute and 10 total attempts per session And successful entry binds the client to the existing session and opens e‑sign + ID check without login And upon success, all other tokens (QR/magic links) are revoked And the audit log records code issuance, attempts (success/failure), IP, user agent, and correlation ID
Cross-Channel Session Resume With Audit Continuity
Given a client started the e‑sign + ID check via any channel and has partial progress saved When the client follows a valid alternate channel (SMS link, email link, or short code) within the active TTL Then the session resumes at the last completed step with no data loss and without duplicating completed signatures or ID checks And the system requires possession re-proof (link tap or code entry) before resume And all superseded tokens are revoked on resume And the audit trail shows a single continuous timeline with channel-switch events and correlation IDs
Retry Rate Limiting and Temporary Lockout
Given a single engagement session When staff attempts to send fallback links Then SMS sends are limited to 3 per 10 minutes and 6 per hour; Email sends are limited to 3 per 30 minutes and 6 per day And short code entry is limited to 5 failed attempts per minute and 10 failed attempts total before a 15-minute lockout And upon hitting a limit, the UI displays a clear message with remaining cooldown time and suggests alternate channels if enabled And all rate-limit and lockout events are logged with reason codes
Auto-Expire Abandoned Sessions and Tokens
Given a session has no client activity When 15 minutes elapse without activity Then all associated tokens (QR, SMS link, email link, short code) are revoked and cannot be used And the client sees "Session expired" with a prompt to request a new link/code And staff sees the session marked Abandoned with timestamp and can reissue new access And the audit log records auto-expiration with reason=SESSION_EXPIRED and includes counts of issued tokens
Admin Channel Controls and Failure Reason Capture
Given an admin has access to Instant QR Sign settings When the admin disables a channel (SMS, Email, Short Code) and saves Then the option is hidden/disabled in staff UI within 30 seconds and tokens of that type cannot be issued And any attempted issuance via a disabled channel is blocked with a clear message and reason=CHANNEL_DISABLED And all failure/abort events capture standardized reason codes: QR_TIMEOUT, QR_UNREADABLE, SMS_DELIVERY_FAILED, EMAIL_BOUNCED, CODE_MAX_ATTEMPTS, RATE_LIMITED, SESSION_EXPIRED, CHANNEL_DISABLED, CLIENT_ABORTED, UNKNOWN And reason codes are available in exports and analytics with counts by channel and timeframe

Liveness Pulse

Run real-time, micro‑motion liveness checks (blink/turn prompts with voice or on‑screen cues) to confirm the person behind the camera is present—not a photo or video. Bandwidth‑adaptive and ADA‑friendly, it keeps verification fast while blocking spoofing attempts.

Requirements

Challenge Orchestration Engine
"As a signing client, I want quick on-screen and audio prompts that prove I’m really present so that I can verify my identity and move straight to signing without delays."
Description

Implement a real-time liveness challenge flow that issues randomized micro-motion prompts (blink, turn left/right, smile, speak a short phrase) using on-screen and audio cues. Track facial landmarks and micro-movements to validate the response matches the prompt within timing tolerances, preventing photo/video replay. Support multilingual prompt sets, per-attempt randomness, limited retries, and clear user guidance. Enforce latency budgets to keep total verification under 20 seconds on typical mobile networks, and persist a signed result token to the case record for downstream gating and auditing.

Acceptance Criteria
Per-Attempt Randomized Challenge Sequence
- Given a new verification attempt, when generating the challenge flow, then select 3–5 prompts from the pool {blink, turn left, turn right, smile, speak phrase} with no prompt repeated within the same flow. - Given the sequence is generated, then order must be randomized using a cryptographically secure RNG and recorded as a challenge hash for audit. - Given two consecutive attempts by the same user within 24 hours, when comparing sequences, then they must differ by at least two positions or prompt types. - Given a rolling window of the last 500 attempts platform‑wide, then no more than 10% share an identical full sequence.
Multilingual Prompt Delivery (Audio and On‑Screen)
- Given device locale is supported (en, es, fr), when the flow starts, then prompts display and audio play in that language; user can override language and changes apply immediately. - Given audio is enabled, then captions are displayed and the on‑screen text matches the spoken audio for the same prompt. - Given network bandwidth < 700 kbps or TTS is unavailable, when a prompt is issued, then the system falls back to on‑screen text within 300 ms without blocking the flow. - Given a screen reader is active, then all controls and prompts expose accessible labels and focus order supports full navigation of the flow.
Real-Time Micro‑Motion Validation and Tolerances
- Given a blink prompt, when the cue is issued, then detect two natural blinks within a 1.5 s start window and 3 s completion window with eye aspect ratio change above threshold and continuous face tracking. - Given a turn left/right prompt, then detect yaw change ≥ 25° toward the indicated side within 3 s and return to center; reject if motion is planar (spoof) with low parallax/optical‑flow score. - Given a smile prompt, then detect lip corner displacement (AU12) above baseline threshold within 3 s. - Given a speak phrase prompt, when the user speaks, then ASR match to the prompted phrase ≥ 0.90 confidence within 4 s and detected audio exhibits live‑speech spectral variance (not playback). - Given any prompt, then fail if the face is occluded > 40% or frame rate drops below 12 fps during the response, and present specific retry guidance.
Retry Limits and User Guidance
- Given an attempt fails, when retries remain, then present the specific failure reason and actionable guidance, and allow immediate retry. - Given three failed attempts within a session, then lock liveness for 5 minutes and present alternative verification options. - Given the user cancels mid‑flow, then mark the attempt as Aborted and do not count it against the retry limit. - Given a retry after the user changes language, then all prompts and guidance reflect the new language selection.
Latency Budget Under 20 Seconds
- Given a typical mobile network (≥ 1 Mbps downlink, ≥ 100 ms RTT), when the user taps Begin, then the 95th percentile end‑to‑end time from tap to result token persisted is ≤ 20 s. - Given each prompt, then time from cue issuance to validation decision is ≤ 2 s at P95. - Given bandwidth drops mid‑flow, then the system adaptively reduces video bitrate/frame rate to maintain the P95 end‑to‑end latency target without lowering validation thresholds. - Given prompt assets are required (audio/text), then they are preloaded before flow start and total preload time is ≤ 2 s at P95.
Signed Result Token Persistence and Auditability
- Given a Pass or Fail decision, when the token is created, then it contains attemptId, caseId, user alias, UTC timestamp, outcome, per‑prompt results and scores, challenge hash/seed, and device/app version metadata. - Given token creation, then the token is signed using Ed25519 or RS256 and includes a keyId; signature verification succeeds with the current public key. - Given token issuance, then it is persisted to the case record within 1 s and encrypted at rest; retrieval by authorized roles returns bytes identical to the signed payload. - Given downstream gating, then the case cannot advance to Retainer E‑Sign without a Pass token not older than 24 hours; invalid or missing tokens block progression.
Bandwidth & Device Adaptation
"As a mobile user on a poor connection, I want the liveness check to adjust automatically so that I can still complete verification without timing out or starting over."
Description

Continuously detect network quality and device capabilities to adapt capture settings (frame rate, resolution, codec) and switch to a photo-burst challenge mode when bandwidth is constrained, preserving liveness integrity. Handle camera permission flows, retries, and graceful timeouts, with resumable sessions if the connection drops. Provide instant feedback on network issues and expected duration to minimize abandonment on low-end devices and rural connections.

Acceptance Criteria
Adaptive Capture Based on Real-Time Network Quality
Given a user starts a liveness session And uplink throughput, RTT, and packet loss are sampled every 1 second When any of the following holds for 2 consecutive samples: uplink < 600 kbps OR RTT > 400 ms OR packet loss > 5% Then the capture pipeline downgrades within 500 ms to the next tier: - Tier A: 1280x720 @ 24 fps, H.264 - Tier B: 854x480 @ 20 fps, H.264 - Tier C: 640x360 @ 15 fps, H.264 Baseline And when all metrics recover above thresholds for 5 consecutive samples Then the pipeline upgrades one tier within 1 second And every tier change is logged with timestamp and current metrics
Automatic Fallback to Photo‑Burst Mode Under Low Bandwidth
Given video liveness is active When any of the following holds for 3 continuous seconds: uplink < 200 kbps OR packet loss > 15% OR sustained encode frame rate < 12 fps at ≥360p Then switch to photo‑burst challenge mode within 2 seconds And display an in‑app notice "Switching to photo‑burst due to network" within 500 ms And for each prompt capture a burst of 5 photos within 2 seconds total And detect at least 1 blink and 2 distinct head poses across the burst And allow up to 2 additional bursts if liveness score < threshold before failing the step
Device Capability Detection and Codec/Resolution Negotiation
Given a liveness session is initialized When getUserMedia and mediaCapabilities queries return Then supported resolutions and codecs (H.264 preferred, VP8 as fallback) are determined within 1 second And the highest tier meeting ≥24 fps at preview with dropped frames < 5% is selected And if hardware acceleration is unavailable, cap resolution to ≤480p And if the device cannot sustain ≥12 fps at 360p, automatically select photo‑burst mode
Graceful Camera Permission Flow and Retries
Given the user has not granted camera access When permission is requested Then display an ADA‑friendly rationale modal with keyboard focus within 300 ms And if permission is denied, show retry CTA and "Use photo‑burst" alternative within 500 ms And allow up to 2 permission retry attempts before offering exit and help link And if permission is granted, start preview within 1 second And log permission outcome and path taken
Resumable Session After Connection Drop
Given an active liveness session When the network disconnects Then persist session state (current step, tier, partial uploads) locally within 1 second And if reconnection occurs within 10 minutes, resume at the last completed step within 3 seconds without re‑prompting passed challenges And previously uploaded media are de‑duplicated via checksums; only missing chunks are retried And if downtime exceeds 10 minutes, expire the session and prompt a fresh start with clear messaging
User Feedback on Network Status and Expected Duration
Given capture is in progress When network quality drops below Tier B thresholds Then show a non‑blocking banner "Network is slow; adapting settings" within 500 ms And display an ETA that updates every 2 seconds; ETA error is within ±30 seconds for sessions ≤2 minutes And offer a one‑tap switch to photo‑burst mode And all notices are screen‑reader announced and dismissible via keyboard
Accessibility & ADA Compliance
"As a user with accessibility needs, I want accessible prompts and alternatives so that I can complete identity verification independently and confidently."
Description

Deliver an ADA-friendly liveness experience that meets WCAG 2.2 AA: synchronized captions for audio cues, screen-reader labels, high-contrast UI, keyboard-only support, and haptic/vibration cues on mobile. Offer alternative, non-voice challenges for users with speech or hearing impairments and slower, larger tap targets for motor impairments. Include an Assisted Mode with extended time windows and simplified prompts, plus a manual verification fallback when accessibility needs cannot be met in-session.

Acceptance Criteria
Synchronized Captions for Liveness Prompts
- Given an audio liveness cue starts, When playback begins, Then on-screen captions for that cue appear within 200 ms and remain synchronized within ±300 ms until the cue ends. - Given captions are available, When the user's OS or browser preference indicates captions/subtitles on, Then captions start enabled and the captions toggle is focusable and labeled. - Given a cue is presented, When captions render, Then the caption text matches the spoken prompt wording exactly and is displayed in a high-contrast container. - Given network degradation occurs, When audio buffers or stalls, Then the full caption text remains visible without truncation until the cue completes or is canceled. - Given a supported browser (latest 2 versions of Chrome, Safari, Firefox, Edge), When the user toggles captions, Then the preference persists for the session and across steps in the liveness flow.
Screen Reader Compatibility for Liveness Flow
- Given a user navigates with a screen reader (NVDA, JAWS, VoiceOver, TalkBack), When moving through the liveness flow, Then all interactive elements expose correct role, name, and state via the accessibility tree. - Given a dynamic liveness prompt appears, When it is injected into the DOM, Then it is announced via aria-live="polite" within 500 ms and is not announced more than once. - Given a modal or dialog opens, When it appears, Then focus moves to the dialog, background content is inert, and focus returns to the trigger on close. - Given progress and countdown updates, When they change, Then they are announced no more frequently than once per second and can be muted via a clearly labeled control. - Given linear navigation is required, When tabbing, Then the reading and tab order follows a logical sequence without focus traps or dead ends.
Keyboard-Only Operation
- Given no pointing device is available, When using Tab, Shift+Tab, Enter, Space, and Arrow keys, Then the user can complete the entire liveness flow (start, consent, select challenge, respond, retry, submit) without requiring a mouse or touch. - Given an interactive control receives focus, When focused, Then a visible focus indicator with at least 3:1 contrast against adjacent colors is shown. - Given time-limited steps exist, When using keyboard controls, Then the user can request additional time for each step using a dedicated, focusable control; no prompt timeout is shorter than 5 seconds by default. - Given any step is active, When the user presses Escape, Then a confirmation dialog allows cancel with keyboard only and returns focus appropriately on dismiss. - Given navigation proceeds, When tabbing, Then no keyboard traps occur and a "Skip to main content" link is available and focusable at the start.
Haptic/Vibration Cues on Mobile
- Given a mobile device that supports vibration is used, When a liveness prompt begins, Then a distinct short haptic pattern (<= 500 ms) signals prompt start, and a different pattern signals success. - Given system settings disable haptics, When the liveness flow runs, Then the app does not trigger vibrations. - Given the user toggles haptics off in settings, When returning to the flow, Then the preference persists for at least 30 days or until explicitly changed. - Given haptics are unsupported or permission is denied, When prompts trigger, Then the system falls back to visual cues without errors or degraded performance. - Given iOS and Android (latest 2 OS versions), When haptics are active, Then vibrations do not block UI responsiveness and do not repeat more than once per second.
Alternative Non-Voice Challenges
- Given microphone access is denied or the user selects a non-voice option, When the liveness check starts, Then only visual/text and on-screen guided prompts are presented with no dependency on audio input. - Given a voice-based blink/turn prompt exists, When alternative mode is active, Then an equivalent on-screen prompt with clear visual timing indicators is displayed, supported by captions and optional haptics. - Given fraud resistance requirements, When evaluating results, Then the pass/fail thresholds for the non-voice path match the voice path with ≤ 2% variance in false reject rate across a defined test set. - Given user choice, When starting the flow, Then the user can select the non-voice option from a clearly labeled control via keyboard, touch, or screen reader. - Given localization is English-only for MVP, When alternative prompts are displayed, Then all text instructions are concise and unambiguous at ≤ 8th-grade reading level.
Assisted Mode and Manual Verification Fallback
- Given the user enables Assisted Mode or an accessibility need is detected, When liveness prompts run, Then each prompt time window is extended by at least 2x and the number of required micro-motions per attempt is limited to 2. - Given Assisted Mode is active, When instructions are shown, Then text is simplified to ≤ 6th-grade reading level and a step-by-step progress indicator is present and announced to screen readers. - Given user performance varies, When a prompt is missed, Then the user may retry up to 3 times without penalty and can pause for at least 10 seconds between prompts. - Given accessibility needs cannot be met in-session, When the user selects "Need help" or fails 3 attempts in Assisted Mode, Then a manual verification fallback is offered within one activation (click or keypress) from the current screen. - Given manual fallback is selected, When transitioning, Then camera/microphone access stops, the session is marked "Pending manual verification," prior inputs are preserved, and an audit log entry with timestamp and reason is recorded.
Perceivable and Operable UI (Contrast and Tap Targets)
- Rule: All text meets WCAG 2.2 AA contrast (normal text ≥ 4.5:1; large text ≥ 3:1); non-text UI components and focus indicators have ≥ 3:1 contrast against adjacent colors. - Rule: Interactive targets are at least 44x44 CSS pixels with a minimum of 8px spacing; the visible label matches the accessible name. - Rule: Color is not the sole means of conveying state; each status or error includes a text label and/or icon with accessible name. - Rule: Up to 200% zoom preserves content and functionality without horizontal scrolling at a 320px viewport width. - Rule: Error messages are programmatically associated to their fields (aria-describedby) and provide actionable correction guidance.
Anti-Spoofing & Deepfake Detection
"As an attorney, I want strong spoof resistance with clear pass/fail reasons so that I can trust signers are real and reduce fraud risk without adding manual review."
Description

Integrate Presentation Attack Detection (PAD) that combines 3D head pose analysis, eye-blink cadence, texture and moiré detection (screen replay), and challenge-response consistency checks. Add lightweight deepfake indicators and mask/obstruction detection. Output a configurable risk score and pass/fail decision with thresholds set by the firm. Log salient features and reasons for failure for auditability without storing full video when not necessary.

Acceptance Criteria
Configurable Composite Risk Score and Decision
Given firm-level PAD thresholds T_fail and T_review are configured (defaults: T_fail=70, T_review=40) When a liveness session completes PAD analysis Then the system outputs a composite risk score in range 0-100 And outputs a decision of Pass when score < T_review And outputs a decision of Review when T_review <= score < T_fail And outputs a decision of Fail when score >= T_fail And the output includes the per-subscore breakdown and flags used to compute the decision
3D Head Pose Challenge-Response Match
Given randomized prompts to turn/tilt head are issued When the user responds Then 3D head pose change must match the prompted axis and direction with absolute delta >= 15° And the response must occur within 2.0 seconds of the prompt And sequence order must match for all prompts issued And mismatches or timeouts increase the challenge-consistency subscore risk and are logged with timestamps
Eye-Blink Cadence Naturalness Check
Given a 10-second observation window When eye landmarks are tracked Then detected blink rate and inter-blink interval variability must fall within configured physiological ranges for Pass And unnaturally periodic or absent blinks (e.g., zero blinks or CV < 0.1) increase risk and set flag blink_anomaly And at least one voluntary blink-on-prompt is detected within 2.0 seconds when prompted
Texture and Moiré Replay Detection
Given the face region is analyzed for high-frequency patterns When moiré/aliasing frequencies consistent with screen replays are detected Then the texture/moiré subscore risk is increased and flag replay_suspected is set And on the replay attack validation set, the detector achieves AUC >= 0.95 and TPR >= 0.90 at FPR <= 0.05
Deepfake Indicators and Lip/Voice Synchrony
Given a spoken or on-screen challenge requiring a verbal or timed response When computing audiovisual sync and temporal consistency Then lip-speech sync offset must be <= 150 ms for Pass; offsets > 150 ms increase deepfake subscore risk And temporal facial consistency metric must exceed threshold; failures set flag deepfake_suspected And if deepfake subscore exceeds firm-configured threshold, decision is Fail regardless of other subscores
Obstruction/Mask Detection and Handling
Given face landmarks and segmentation are available When occlusions or coverings are present over critical regions (eyes, nose, mouth) Then if occlusion exceeds 30% or a mask/face-covering is detected, the session results in Fail with reason face_obstructed And the user is allowed up to 2 retries after guidance before final Fail is recorded
Audit Logging Without Full-Video Retention
Given the firm's data retention policy no_video_retention=true When the session completes Then the system stores only: session_id, timestamp, composite risk score, decision, per-subscore values, and failure flags/reasons And no full-motion video or full-resolution frames are persisted; transient buffers are purged within 60 seconds And an audit record is retrievable via API within 2 seconds and is cryptographically signed for integrity
Privacy, Consent & Data Retention Controls
"As a privacy-conscious client, I want to know what is captured and for how long so that I feel safe completing verification."
Description

Present clear, localized consent explaining camera use and purpose prior to capture. Minimize data by processing in-session and storing only the result token, risk score, and minimal evidence frames when configured. Encrypt data in transit and at rest, support regional storage, configurable retention (e.g., 30/60/90 days), and deletion on case closure. Maintain an immutable audit log of consent, attempts, outcomes, and configuration versions to satisfy regulatory and client requirements (e.g., GDPR/CCPA).

Acceptance Criteria
Pre-Capture Localized Consent
- On first use per case/session, the system detects the user locale and displays consent text in that language; if unavailable, it defaults to English. - Consent text explicitly discloses camera/mic activation, purpose (liveness verification), data stored (result token, risk score, and 0–3 evidence frames if enabled), retention period, and regional storage location. - User must provide explicit consent via checkbox plus Continue; both are required to proceed. - If user declines or dismisses, no camera/mic permission is requested, no capture occurs, and the flow returns a consent_not_granted outcome. - The consent text version, locale, timestamp, and user agent are recorded to the audit log before any media access is attempted.
Data Minimization & In-Session Processing
- Raw video/audio are processed only in-memory; no raw media is written to disk, logs, or external storage. - Persisted fields per attempt are limited to: result_token (UUIDv4), risk_score (0–1), evidence_frame_count (0–3), and evidence frames only if enabled. - API responses expose only result_token, risk_score, attempt_id; no raw frames or PII fields are returned. - Storage inspection post-attempt reveals zero raw media artifacts; attempts to persist raw streams are blocked and logged as errors.
Evidence Frames Configuration & Storage
- Admin can configure evidence_frame_count ∈ {0,1,2,3}; default is 0. - When set to 0, no evidence frames are stored; verification completes without frames. - When set to N>0, exactly N unique frames per attempt are stored at prompt completion boundaries; duplicates are rejected. - Each stored frame is ≥320×240, individually encrypted, and linked to attempt_id and case_id. - Workspace-level toggle/versioning ensures configuration changes apply only to new attempts and are captured in the audit log.
Encryption In Transit & At Rest
- All client/server and service/service calls for liveness flows enforce TLS 1.2+ with HSTS; weak ciphers are rejected. - All persisted artifacts (tokens, scores, evidence frames, audit logs) are encrypted at rest using AES-256 with managed KMS keys; keys rotate ≤ every 365 days. - Evidence frames use envelope encryption with per-object data keys; access is restricted to the liveness service role. - Attempts to store unencrypted artifacts are blocked and recorded as security events.
Regional Storage Enforcement
- Admin selects a workspace data region ∈ {US, EU, APAC}; the selected region is displayed in consent text. - All artifacts (tokens, scores, evidence frames, audit logs) are stored exclusively in the selected region; cross-region replication is disabled by default. - Artifact metadata includes region tags; any write outside the selected region is rejected and logged. - Region changes require successful migration of existing artifacts; setting cannot be updated while artifacts remain in the old region.
Retention Policy & Case-Closure Deletion
- Admin can set retention_days ∈ {30,60,90}; default is 60. - Artifacts older than retention_days since attempt completion are permanently deleted within 24 hours by an automated job. - When a case status transitions to Closed, all associated artifacts (tokens, scores, evidence frames) are deleted within 15 minutes regardless of retention_days; audit log entries are retained. - Deletion writes a verifiable audit entry including attempt_id, artifact types removed, timestamps, and actor=system. - Post-deletion access attempts return HTTP 404 with error code artifact_deleted_by_policy.
Immutable Audit Log of Consent and Outcomes
- Each consent and liveness attempt appends an audit record with: case_id, attempt_id, subject_id (pseudonymous), timestamp (UTC), locale, consent_version_id, region, retention_days, configuration_version, outcome, risk_score, result_token, evidence_frame_count. - Audit storage is append-only (WORM or hash-chained); edits are disallowed, corrections require compensating entries. - Authorized roles (Admin, Compliance) can export audit records by case via API; exports include an integrity checksum. - Tamper detection verifies chain integrity; any break triggers a security alert within 5 minutes.
Workflow Integration & E‑Sign Gate
"As a solo attorney, I want e‑sign to unlock only after liveness passes so that engagements remain fast for real clients and flagged for review when risk is high."
Description

Gate retainer assembly and e-sign access on a successful liveness result. On pass, proceed seamlessly to e-sign; on fail or high risk, route to manual verification with configurable retry limits and notifications to the attorney. Store the liveness outcome on the matter, expose it via API and webhook, and add an audit line to the signed packet. Support A/B configuration by practice area and jurisdiction to align with firm policies.

Acceptance Criteria
E‑Sign Gate on Liveness Pass
Given a client completes a liveness check with decision = "pass" and risk_score < configured threshold for the matter’s practice area and jurisdiction When gating rules are evaluated Then retainer assembly is triggered automatically and completes successfully And the client is advanced to the e‑sign step within 3 seconds of decision finalization And the liveness session_id is linked to the e‑sign session and matter record
Manual Verification Route on Fail/High‑Risk with Retries
Given a liveness decision of "fail" or risk_score >= threshold (or anti‑spoof flags present) When gating rules are evaluated Then retainer assembly and e‑sign access remain blocked And the client is offered a retry if attempts_used < configured retry_limit And upon reaching retry_limit, the flow is stopped and matter status is set to "Verification Required" And a notification is sent to the assigned attorney within 1 minute containing matter_id, decision, risk_score, attempts_used, and reason
Persist Liveness Outcome on Matter
Given any liveness session completes (pass, fail, or high‑risk) When the matter is saved Then the matter stores: decision, risk_score, threshold_used, attempts_used, session_id, evaluator_version, timestamp_utc, and device_signal_summary And the record is immutable (append‑only) and attributed to user_id and source_ip And the latest outcome is visible on the matter timeline and filterable in search
API and Webhook Exposure of Outcome
Given an authorized client with scope matters:read calls GET /matters/{id}/liveness When the matter exists Then respond 200 with JSON: decision, risk_score, threshold_used, attempts_used, session_id, evaluator_version, timestamp_utc, and matter_id (no biometric media) And respond 404 if the matter does not exist or the caller lacks access And when a liveness decision is finalized, POST a webhook event "liveness.decision.finalized" to registered endpoints within 10 seconds with the same payload And retry webhook deliveries with exponential backoff for up to 24 hours on non‑2xx responses, signing each request
Audit Line in Signed Packet
Given the retainer is signed and the packet is generated When the packet is assembled Then include an audit entry containing: liveness decision, risk_score, threshold_used, timestamp_utc, session_id, evaluator_version, and applied_variant_id And exclude biometric media or PII beyond the above fields And embed a hash tying the audit entry to the packet so tampering invalidates the signature audit trail
A/B Configuration by Practice Area and Jurisdiction
Given a matter with practice_area and jurisdiction attributes When liveness gating evaluates configuration Then apply the matching variant’s parameters: threshold, retry_limit, prompts_modality, and notification_recipients And record applied_variant_id on the matter and include it in API and webhook payloads And enforce firm‑defined split ratios within ±2% over a rolling 7‑day window And allow admins to update variants in the console with changes taking effect within 5 minutes without deploys
Cross‑Platform Capture SDK & Browser Support
"As a developer integrating Briefly, I want a stable, cross‑browser capture SDK so that I can add liveness checks to intake without building camera and permission handling from scratch."
Description

Provide a lightweight capture module that works on mobile and desktop web across major browsers (Safari, Chrome, Edge, Firefox), leveraging getUserMedia with fallbacks. Bundle device permission helpers, error messaging, and a UI component library for prompts and progress. Ship as an embeddable JS SDK with TypeScript types and a React wrapper, plus a REST/WS endpoint for verification results. Maintain a compatibility matrix and automated browser/device tests in CI.

Acceptance Criteria
Cross-Browser Support & Compatibility Matrix
Given a supported browser/version (Chrome ≥ 90, Edge ≥ 90, Firefox ≥ 90, Safari ≥ 14) on supported OS (iOS ≥ 15, Android ≥ 10, Windows ≥ 10, macOS ≥ 12), When init() and startCapture({ facingMode: 'user' }) are called, Then a camera preview renders within 1500 ms at P90 and uses the front-facing camera. Given an unsupported browser or missing getUserMedia, When init() is called, Then the SDK rejects with LP_ERR_BROWSER_UNSUPPORTED and a message linking to the compatibility page. Given a device with multiple cameras, When switchCamera() is invoked, Then the active camera switches within 1000 ms without black frames > 250 ms. Given the published compatibility matrix (JSON/MD), When isSupported(env) is evaluated, Then it returns true/false consistent with the matrix for all entries. Given a CI run on the matrix (≥ 24 browser/OS/device combos) via Playwright/BrowserStack, When smoke tests execute (preview-start, capture-complete, teardown), Then pass rate ≥ 98% and any failure blocks release.
Permission Handling & Error Messaging
Given camera permission is ungranted, When startCapture() is called, Then a pre-permission modal with rationale displays and the native prompt follows. Given the user denies permission, When the prompt closes, Then the SDK emits onError with code LP_ERR_PERMISSION_DENIED and renders a retry UI with OS/browser-specific steps. Given permission is permanently blocked, When startCapture() is called, Then the SDK detects the block and shows settings navigation guidance (deep links where supported) and does not loop prompts. Given insecure origin (http:), When init() is called in a browser requiring secure context, Then the SDK rejects with LP_ERR_SECURE_CONTEXT_REQUIRED and remediation text. Given invalid API usage, When methods receive bad parameters, Then TypeScript surfaces type errors at compile time and the runtime emits onError with LP_ERR_PARAMETER_INVALID. All error messages are human-readable (≤ 140 chars), localized keys exist for en and es, and snapshot tests verify presence.
Prompt and Progress UI Components
Given the React wrapper <LivenessCapture prompts=["blink","turn_left","turn_right"]>, When rendered, Then on-screen instructions, icons, and a step/total progress indicator are visible and synchronized with the active step. Given voice prompts are disabled or device audio is unavailable, When a prompt is triggered, Then equivalent on-screen cues and haptic feedback (if supported) are presented. Given a step completes, When transitioning to the next step, Then progress updates within 200 ms and onStepChange emits { stepId, index, timestamp }. Given locale is switched between "en" and "es", When the component re-renders, Then all UI strings update without reload and i18n tests pass. Given host app theme variables, When the component renders, Then it consumes CSS variables and maintains WCAG AA contrast for text and controls.
Bandwidth-Adaptive Capture
Given uplink throughput < 300 kbps or effective connection type ≤ 3g, When startCapture() runs, Then the SDK sets constraints to ≤ 360p at 12–15 fps and reduces bitrate while maintaining liveness detection. Given uplink ≥ 1 Mbps and CPU is under 70% load, When a new prompt begins, Then constraints increase up to 720p at 24 fps. Given packet loss > 5% or jitter > 100 ms, When streaming frames, Then the SDK switches to chunked/burst uploads with exponential backoff and still completes the liveness flow in ≤ 8 s at P95. Given the connection drops, When connectivity returns within 30 s, Then the session resumes at the last incomplete step without data loss and informs the user of the resume state.
Accessibility Compliance (ADA/WCAG)
All interactive elements are keyboard operable (Tab/Shift+Tab/Enter/Space) with visible focus outlines. Screen readers announce current step, total steps, and clear instructions; labels/ARIA roles are present for controls and live regions are used for step changes. Color contrast for text/icons ≥ 4.5:1; prefers-reduced-motion is honored by disabling non-essential animations. Voice prompts have synchronized captions; when a screen reader is active, auto-advance allows at least 1.5× instruction duration before progressing. Automated tests (axe-core) report zero serious/critical issues and Lighthouse Accessibility score ≥ 95 in the sample app. Manual tests confirm full flow completion with iOS VoiceOver and Android TalkBack without requiring touch gestures beyond standard navigation.
TypeScript Types & React Wrapper
The npm package publishes ESM and CJS builds with .d.ts; compiling a sample app with "strict": true yields zero TS errors and no any in public types. Public API is fully documented via JSDoc; IntelliSense surfaces method signatures and option defaults. React wrapper exposes <LivenessCapture> and useLiveness(); server-side rendering is safe (no window access at import), and hydration succeeds without warnings. Tree-shaken core SDK bundle size ≤ 150 KB gzipped and React wrapper ≤ 20 KB gzipped as enforced by CI size budgets. Semver contract tests ensure minor version upgrades do not introduce breaking type changes.
Verification Results via REST/WS
Given a valid session and Bearer token, When GET /v1/liveness/{sessionId}/result is called, Then response is 200 with { status: pending|pass|fail, score, reasonCodes[], startedAt, completedAt } or 404 for unknown session; 401 for missing/invalid token. Given a WS connection to /v1/liveness/{sessionId}/stream with token, When a session runs, Then server emits events: started, prompt(stepId), analyzing, result, with keepalive pings ≤ every 25 s and client reconnect within 5 s preserves ordering. End-to-end latency from final frame sent to result event ≤ 1500 ms at P90 under 1 Mbps uplink and ≤ 500 ms at P90 under ≥ 5 Mbps uplink. Rate limiting is enforced at 100 requests/min per API key; excess returns 429 with Retry-After; all endpoints require TLS 1.2+.

Smart Frame Capture

Auto-detects ID edges, glare, and blur, then auto‑captures the best frame with live hints (tilt, move closer, remove case reflection). Works with front/back of licenses and passports, improving first‑try success on busy sidewalks and in dim courthouse hallways.

Requirements

Real-time Document Edge & Type Detection
"As a client completing intake on my phone, I want the app to automatically find my ID’s edges and type so that I can frame it quickly without fiddling, even in poor lighting or tight spaces."
Description

Implement an on-device computer vision pipeline that continuously analyzes the camera preview to detect document boundaries (ID cards, passport data page) and orientation in real time. The detector must reliably identify rectangular edges, aspect ratios, MRZ/barcode regions, and front vs. back sides to drive context-aware overlays. It shall maintain >95% edge detection accuracy on common US and international IDs in varied conditions (outdoor glare, dim hallways) and support minimum device specs for iOS and Android. Provide fallback manual capture and adjustable thresholds to cope with older devices. Expose events to the UI layer for framing guides, success indicators, and to downstream services for classification and cropping.

Acceptance Criteria
Real-time Edge Detection Performance on Minimum Devices
Given a device on the Minimum Device Spec list and a 1280x720 camera preview When the user presents a standard ID or passport under normal indoor light for 10 seconds Then the edge detector publishes updated edges at ≥20 FPS, with average CPU ≤60% and dropped preview frames ≤5% And the median detection latency from frame arrival to edge event is ≤40 ms
Edge Detection Accuracy Across Lighting and Glare
Given a labeled test set of 1,100 frames (400 ID fronts, 400 ID backs, 300 passport data pages) across outdoor glare, dim hallway, shadow, and case reflection conditions When the on-device detector processes the set Then ≥95% of frames have edge polygons with IoU ≥0.80 against ground truth And ≥95% of frames report correct document rectangle aspect ratio within ±3% of ground truth
Document Type, Orientation, and Side Classification
Given a labeled validation set of 1,000 samples (500 US/international IDs, 500 passports) with front/back and rotation labels When the pipeline runs on-device Then document type classification (ID vs Passport) has accuracy ≥98.0% And side classification (front vs back for IDs; data page presence for passports) has accuracy ≥97.0% And orientation angle estimation has 95th percentile absolute error ≤5°
MRZ and Barcode Region Detection for Overlay Guides
Given documents bearing MRZ (TD3/TD1) or PDF417 barcodes When the detector identifies machine-readable zones Then region detection achieves recall ≥98% and precision ≥95% with IoU ≥0.85 vs ground truth And the MRZ/PDF417 region event is emitted ≤120 ms after frame arrival And no false MRZ/PDF417 regions are emitted in ≥99% of non-MRZ/non-barcode frames
Event Exposure to UI and Downstream Services
Given detection state changes (edgesFound, edgesStable, typeClassified, sideClassified, glareDetected, blurDetected) When these states occur during preview Then UI-layer events onEdgesFound, onEdgesStable, onTypeClassified, onSideClassified, onQualityWarning are emitted with payload {timestamp, frameId, bbox/mask, confidence, type, side, orientationDeg} And downstream events for classification and cropping are delivered to the event bus with at-least-once semantics, end-to-end in ≤150 ms (p95) And UI receives events in ≤50 ms (p95) from emission And event loss is ≤0.1% over a 10-minute continuous preview
Fallback Manual Capture and Adjustable Thresholds on Legacy Devices
Given a device not on the Minimum Device Spec list or a session where confidence < threshold or edgesStable is not achieved for 3 consecutive seconds When preview is active Then a Manual Capture CTA is shown within 500 ms and allows capture and manual corner adjustment And configuration flags exist to adjust blur, glare, and edge-stability thresholds per device profile, with defaults restored on app restart And when legacy mode is enabled, auto-capture is disabled and the detector continues to provide best-effort overlays without blocking manual capture
Auto-Capture Best Frame Scoring Engine
"As a user holding my ID, I want the app to take the photo automatically at the best moment so that I don’t waste time retaking blurry or glared shots."
Description

Create a frame-quality scoring engine that evaluates sharpness, motion blur, glare coverage, edge completeness, and focus confidence per frame from the live preview. When the score exceeds a configurable threshold, trigger an automatic shutter with haptic/audio confirmation. Include a safety timeout and burst capture (e.g., 3–5 frames) with best-of-burst selection to increase first-try success. Optimize for low-light by adapting exposure/ISO while preventing motion blur, and limit CPU/GPU impact to maintain smooth preview (≥24 FPS on target devices). Provide user override for manual capture and a retry flow with reason codes (e.g., glare detected, edges incomplete).

Acceptance Criteria
Auto‑Shutter Trigger on Threshold with Haptic/Audio
Given live preview is active and Smart Frame Capture is enabled with threshold T=0.80 and a debounce of 2 frames When a frame's composite score >= T for at least 2 consecutive preview frames at ≥24 FPS Then the app auto-captures within 200 ms, plays haptic and audio confirmation, logs the capture event, and suppresses additional auto-captures for 1 s
Composite Frame Score Calculation and Configurability
Given scoring config is loaded with weights and per-dimension minimums: sharpness>=0.70, motion_blur<=0.20, glare_area<=0.05, edge_completeness>=0.95, focus_confidence>=0.80 When the engine evaluates frames Then each per-dimension score is in [0,1], the composite score is in [0,1], and frames are classified as pass when all minimums are met and composite>=T And updating T or weights at runtime takes effect by the next evaluated frame without app restart and is persisted for the session
Burst Capture and Best‑of‑Burst Selection
Given auto-capture is initiated and burst_count B is configured between 3 and 5 (default 4) When the burst runs Then at least B frames are captured within 1 s, the frame with the highest composite score is selected as the result, and tie-breaking prefers the lowest motion_blur And the selected frame is saved and surfaced to the user within 2 s of trigger time
Safety Timeout Fallback Capture
Given Smart Frame Capture is active with safety_timeout=5 s When no frame reaches threshold T before timeout Then the engine selects and captures the highest-scoring frame from the last 1 s window, flags it sub_threshold if composite<T, and shows a retry affordance with the top failing reason code And auto-capture is paused until the user retries or adjusts framing
Low‑Light Adaptation Without Motion Blur
Given ambient illuminance is 5–20 lux and device torch is off When Smart Frame Capture runs Then the camera adapts ISO/exposure so exposure_time<=1/60 s, preview remains ≥24 FPS, and at least one frame with motion_blur<=0.20 and sharpness>=0.70 is captured within 3 s And the selected frame's composite score meets or exceeds T, or a retry is prompted with low_light or blur_detected reason code
Smooth Preview Performance at ≥24 FPS
Given the scoring engine is enabled on target devices during a 60 s continuous preview session When processing runs under normal device thermals Then mean preview FPS is ≥24, no continuous FPS drop below 20 lasts longer than 500 ms, and the processing queue never exceeds a backlog of 3 frames And device does not emit OS thermal-throttling warnings and UI interactions remain responsive (tap-to-focus latency <150 ms)
Manual Override and Retry Reason Codes
Given the user taps the manual shutter while auto-capture is armed When the tap occurs Then the app captures the current frame within 100 ms, cancels any pending auto-capture, and suppresses auto-capture for 1 s And if the capture is below threshold, the UI displays at least one applicable reason code from {glare_detected, edges_incomplete, blur_detected, out_of_focus, low_light} with a corresponding hint, and the reason is included in analytics
Live Hints & Multi-Modal Guidance
"As a time-pressed client in a dim courthouse hallway, I want clear, immediate hints on how to adjust my phone so that I can capture an acceptable ID image on the first try."
Description

Deliver real-time, context-aware guidance overlays and prompts that respond to detected issues: arrows and tilt indicators for perspective correction, distance/zoom cues, suggestions to remove case reflections, and prompts to enable torch in low light. Provide multi-modal feedback (text, icons, haptics, and optional voice) with localization for top languages and accessibility compliance (WCAG text size/contrast, VoiceOver/TalkBack labels). Hints should update within 200 ms of detection changes to feel live, suppress repetitive prompts, and function offline. Expose configuration for language, verbosity, and brand styling.

Acceptance Criteria
Real-time Hint Latency and Responsiveness
Given the camera preview is active and guidance is enabled When the detection state changes (e.g., tilt, distance, edge alignment, glare) by crossing a threshold Then the visible hint overlay updates within 200 ms at the 95th percentile and within 300 ms at the 99th percentile on target devices And while hints are active, the overlay frame rate remains >= 24 fps and input latency stays <= 50 ms
Low-Light Torch Prompt and Control
Given ambient brightness indicates low light and the device has a torch When the user is in capture mode Then display a torch enable prompt within 300 ms with text, icon, and optional voice, and provide a one-tap toggle And do not re-prompt more than once every 10 seconds unless the lighting state changes And if torch is enabled, update the guidance to reflect the new state and suppress further torch prompts for the next 30 seconds And if the device lacks a torch or permission is denied, present alternative suggestions without repeating more than twice per session
Glare/Reflection Guidance with Repetition Suppression
Given glare or case reflection is detected above the configured threshold for more than 500 ms When guidance is shown Then display directional tilt/move hints with arrows and a single light haptic on first occurrence per condition And do not repeat the same text or voice prompt more than once every 30 seconds unless the condition meaningfully changes And remove the hint within 300 ms after glare falls below threshold for at least 1 second
Localization and Dynamic Language Switching
Given app language is set to en, es, fr, pt-BR, or zh-Hans When hints appear Then all hint text, icons with text labels, voice prompts, and accessibility labels are localized to the selected language And switching languages in settings updates currently visible hints within 1 second without restarting the session And for unsupported languages, fall back to en-US strings and TTS
Accessibility Compliance for Text, Screen Readers, and Haptics
Given the user has increased system text size up to 200% or enabled high-contrast mode When hints are rendered Then hint text meets WCAG 2.1 AA contrast (>= 4.5:1 normal text, >= 3:1 large text) and scales with system font size without overlapping critical camera content And all icons have accessible labels that are announced by VoiceOver/TalkBack within 1 second And haptics and motion effects respect system Reduce Motion/Reduce Haptics settings and are suppressed when disabled
Offline Operation of Guidance and Voice
Given the device is offline and the guidance assets are bundled or cached When entering the capture flow Then all guidance logic, hint rendering, haptics, and on-device TTS operate without any network calls And if on-device TTS is unavailable, voice guidance is automatically disabled while equivalent text/icon cues remain And telemetry events are queued locally and transmitted when connectivity returns
Configurable Language, Verbosity, and Brand Styling
Given a configuration with language, verbosity (concise, standard, detailed), and brand style tokens (colors, typography) When the configuration is applied before a session Then guidance renders using the provided theme and language, and the selected verbosity adjusts hint frequency and content accordingly And invalid or missing values fall back to documented defaults with a non-blocking warning log And a QA debug mode can display the active configuration and last 10 guidance events
Glare, Blur, and Low-Light Mitigation
"As a user capturing my license outdoors, I want the app to prevent glare- or blur-ruined shots so that my submission is readable without back-and-forth."
Description

Integrate capture controls and post-processing to reduce failure modes: dynamic torch control with anti-flicker, exposure and focus locks once edges stabilize, short-exposure preference to minimize motion blur, and optional multi-frame denoise/HDR merge when device supports it. Detect specular glare regions and suggest micro-adjustments (small tilt/angle change) before capture; block auto-capture if glare obscures critical fields (photo, MRZ, barcode, name). Provide device capability detection and degrade gracefully on low-tier hardware. Track quality metrics to continuously tune thresholds.

Acceptance Criteria
Dynamic Torch Control with Anti-Flicker in Low-Light
Given ambient illuminance < 15 lux and device torch is available When live preview starts or light drops below 15 lux for >300 ms Then the torch enables within 300 ms and anti-banding mode matches mains (50/60 Hz) with exposure quantized to cycle multiples Given rolling banding is detected (banding score > 0.2 at 50/60 Hz) When torch is on Then exposure time adjusts within 200 ms and banding score falls below 0.1 within 1 s Given ambient illuminance >= 15 lux When preview is active Then torch remains off unless user explicitly enables it
Edge Stabilization Locks for Exposure and Focus
Given document edges are detected with confidence ≥ 0.9 and inter-frame motion < 2 px RMS over 500 ms When this stability persists Then auto-exposure and auto-focus lock within 150 ms Given AE/AF are locked When motion exceeds 4 px RMS or edge confidence drops below 0.8 for 200 ms Then locks are released within 150 ms Given AE/AF are locked and auto-capture triggers When capture is initiated Then shutter fires within 100 ms
Short-Exposure Preference to Minimize Motion Blur
Given scene EV allows multiple exposure/ISO pairs When computing exposure Then choose exposure time ≤ 1/120 s before lengthening exposure, raising ISO up to the device’s acceptable noise limit to maintain target EV Given target EV cannot be met with exposure ≤ 1/120 s at max acceptable ISO When preview is active Then prefer exposure ≤ 1/60 s and display a "Hold steady" hint within 200 ms Given live frames exhibit blur (Laplacian variance below threshold) for >300 ms When auto-capture is eligible Then auto-capture pauses and a "Hold steady" hint is displayed until the blur metric recovers
Multi-Frame Denoise/HDR Merge with Capability Detection
Given low light (SNR below target) or high dynamic range (scene DR > 10 stops) and the device supports burst capture, ZSL, and YUV processing When auto-capture triggers Then capture 3–5 frames and produce a merged image within 1.5 s with OCR confidence ≥ 0.9 on a standard test card and PSNR improvement ≥ 3 dB over single-frame Given required capabilities are unavailable or estimated merge latency > 1.5 s on the current device When auto-capture triggers Then fall back to single-frame capture with denoise, completing within 400 ms, and no unsupported feature toggles are shown Given capability probing runs at session start When the camera opens Then capability detection completes within 300 ms and is cached for the session
Specular Glare Detection and Micro-Adjustment Hints
Given specular highlight area in critical zones ≥ 5% with saturation > 0.95 When the preview updates Then display a directional hint (e.g., "Tilt left 10°" or "Move closer") within 200 ms derived from glare centroid Given glare area in critical zones drops below 1% for 300 ms When hints were displayed Then clear hints and re-enable auto-capture eligibility Given glare persists ≥ 5% for > 5 s despite user movement When the preview continues Then suggest alternate remediation (e.g., "Move to shade", "Adjust angle") within 200 ms
Auto-Capture Block When Critical Fields Obscured
Given critical fields (photo, MRZ, barcode, name) are impacted by glare or blur such that OCR/decoder confidence < 0.85 When the auto-capture threshold is otherwise met Then block auto-capture and show the specific reason within 200 ms Given critical field confidence ≥ 0.9 and edge stability ≥ 0.9 for 300 ms When monitoring continues Then auto-capture becomes eligible and triggers within 200 ms Given more than 3 consecutive blocks occur within 10 s When the user attempts capture Then offer a manual capture option with confirmation and log block reasons
Quality Metrics Tracking for Threshold Tuning
Given preview and capture sessions run When frames are processed Then record per-session metrics (lux, exposure time, ISO, motion score, glare %, edge confidence, OCR confidence, device model, capability flags) with timestamps and an anonymized session ID Given metrics are recorded When the session ends or the app backgrounds Then transmit metrics over TLS within 5 s only if telemetry is enabled; otherwise discard locally Given metrics ingestion is operational When reviewing aggregated data Then at least 95% of sessions contain complete metric sets and no image pixels or PII are stored
Two-Sided ID Workflow with Consistency Checks
"As an attorney onboarding a client quickly, I want the app to guide the client through front and back capture and verify they match so that I receive a complete, usable ID set the first time."
Description

Implement a guided front/back capture flow for driver’s licenses and a data-page/back-up page flow for passports. Enforce completion of both sides, persist state between screens, and pair images into a single document artifact. Validate consistency via barcode/MRZ parsing (where available) and simple visual hashes to detect mismatches or different documents. Provide clear progress indicators (e.g., 1 of 2, 2 of 2), instant retake options, and orientation auto-rotation. Expose metadata (side, orientation, quality score) to downstream verification and document assembly.

Acceptance Criteria
Driver’s License: Guided Front/Back Capture with Progress Lock
Given a new driver’s license capture session When the user begins the flow Then the UI displays “1 of 2 — Front” and disables Continue until a front image with quality_score >= 0.75 is auto-captured Given the front side is accepted When the flow advances Then the UI displays “2 of 2 — Back” and disables Finish until a back image with quality_score >= 0.75 is auto-captured Given only one side is captured When the user attempts to submit or exit Then the app blocks submission and prompts to complete the missing side with actions to capture or discard
Passport: Data Page then Back Page Guided Flow
Given passport mode is active (auto-detected via MRZ or user selection) When the data page is accepted with quality_score >= 0.75 Then the UI advances to “2 of 2 — Back Page” with a sample overlay and disables Finish until captured Given both pages are captured When the user submits Then submission succeeds; otherwise submission is blocked with a prompt to complete the missing page
State Persistence Across Navigation and Interruptions
Given one side has been captured When the user navigates away and returns within 30 minutes or the app is backgrounded/foregrounded Then the previously captured image, side state (1/2 or 2/2), and quality scores are restored without loss Given temporary network loss up to 2 minutes occurs during upload When connectivity is restored Then the upload resumes without requiring a retake and without creating duplicate artifacts
Artifact Pairing and Downstream Metadata Exposure
Given both sides for a single document are accepted When the user confirms Then the system creates a single document artifact with two ordered pages [front|data_page, back] and assigns a document_id Given the artifact is created When published to downstream services Then the payload includes per-side metadata: side (front|back), orientation_deg (0|90|180|270), quality_score (0..1), capture_timestamp (ISO 8601), parsing_status (parsed|failed), document_type (DL|Passport), and artifact/document identifiers Given the artifact is created When the backend responds Then the API returns 201 with artifact_id and page_count = 2
Consistency Validation via PDF417/MRZ and Visual Hash
Given a driver’s license back image with readable PDF417 When parsed Then first_name, last_name, and date_of_birth must match OCR from the front after normalization (trim, casefold, punctuation removal); on mismatch return error_code = ID_MISMATCH and block submission Given a passport data page with MRZ When parsed Then document_number and date_of_birth must be consistent across sides; on mismatch block submission with error_code = PASSPORT_MISMATCH Given parsing is unavailable or fails on either side When visual hashes are compared across sides Then flag Different document detected and block submission if normalized distance > 0.35; otherwise allow
Instant Retake and Replace Behavior
Given a side preview is shown When the user taps Retake Then the camera view opens within 300 ms; upon acceptance the new image replaces the prior one in the artifact, page order is preserved, and progress remains accurate Given the user cancels during retake When returning to preview Then the original image remains bound to the artifact with unchanged metadata
Orientation Auto-Rotation and Auto-Capture Gating
Given an image is captured with incorrect orientation metadata When processed Then the app auto-rotates to the upright orientation such that the dominant text/MRZ baseline is within ±5° of horizontal (0|90|180|270°) Given tilt, glare, or blur exceed thresholds (tilt > 8°, glare_ratio > 0.2, blur_metric < 0.55) When live preview is running Then real-time hints are shown and auto-capture is suppressed until quality_score >= 0.75
Secure On-Device Processing & Privacy Controls
"As a solo attorney, I want ID capture to happen securely on the client’s device with minimal retention so that I can protect client privacy and meet compliance obligations."
Description

Process detection, scoring, and cropping on-device by default, persisting only the final selected frames. Discard preview frames immediately; encrypt saved images at rest using platform keystores; and transmit over TLS with certificate pinning. Provide explicit consent copy, configurable retention (e.g., auto-delete after successful extraction or after X days), and redact or avoid storing derived PII unless required. Maintain audit logs (capture time, device info, quality score, side captured) without sensitive image content. Align with SOC 2 controls and applicable privacy laws for PII captured during legal intake.

Acceptance Criteria
On-Device Processing During Capture
Given the device is in Airplane Mode When the user completes front and back ID capture in Smart Frame Capture Then detection, quality scoring, and cropping complete successfully without any network requests And no outbound connections are attempted before the user confirms the final selection to proceed And a network proxy/sniffer records zero requests during the capture phase
Discard Preview Frames; Persist Only Selected Frames
Given a capture session is in progress When the live preview is active Then no preview frames are written to persistent storage and frame buffers are released within 200 ms after use When the session ends without saving Then the file system contains zero image artifacts from that session When the user selects a final frame and taps Use Photo Then exactly one image per side is persisted and all non-selected frames are permanently discarded
Encrypt Images at Rest with Platform Keystore
Given final selected images are saved on-device Then the files are encrypted at rest using non-exportable keys from the platform keystore (Android Keystore / iOS Keychain or Secure Enclave) And the files cannot be read as plaintext outside the app sandbox (e.g., via ADB/filesystem access) and appear as ciphertext And keys are destroyed on app uninstall and are invalidated/rotated per OS policy signals And decryption requires the device to be unlocked where supported by the platform
TLS Transport With Certificate Pinning on Upload
Given the app uploads final images to the server When a TLS MITM proxy presents an unpinned or invalid certificate (leaf or intermediate) Then the connection is refused and no image bytes are transmitted And only TLS 1.2+ with strong ciphers is negotiated And pin validation failures are logged with no sensitive contents
Explicit Consent Gate Prior to Camera Use
Given the user initiates Smart Frame Capture for a matter for the first time When the consent screen is shown Then the copy clearly states purpose, retention options, transmission security, and user rights with a link to the Privacy Policy And the user must explicitly accept to proceed; decline returns to intake with no images captured And a consent record (user/matter identifiers, timestamp in UTC, consent version) is stored for audit And the screen meets accessibility basics (focus order, labels) and is localized for en-US at minimum
Configurable Retention and Derived PII Minimization
Given an admin configures retention When set to delete after successful extraction Then local and server-stored images are deleted within 60 minutes of extraction completion When set to delete after N days (1–90) Then images older than N days are purged by a scheduled job; offline devices purge on next app launch And derived PII from OCR is not persisted by default; if storage is required by configuration, only the minimal required fields are stored with masking (e.g., last 4 visible) and tagged with the retention rule And all deletions are recorded in the audit log
Audit Logging Without Sensitive Content
Given any capture, retention change, or deletion event occurs Then an immutable audit entry is written containing UTC timestamp, device model, OS version, app version, capture side (front/back), quality score, retention rule applied, and event type And the entry contains no image data, thumbnails, or OCR text And audit logs are append-only, tamper-evident (e.g., hash-chained), exportable (CSV/JSON), and access-controlled by role And log retention is configurable to align with SOC 2 policy (e.g., 1–7 years)
Normalized Output & Pipeline Integration
"As a paralegal preparing a retainer, I want standardized, high-quality ID images and metadata to flow directly into document assembly so that I can finalize paperwork without manual edits."
Description

Produce perspective-corrected, cropped outputs with consistent padding and target resolution suited for court filings and KYC checks (e.g., effective 300 DPI equivalent for wallet IDs). Export dual formats: JPEG/PNG for UI preview and PDF for records, along with a compact JSON payload containing document type, side, capture timestamp, quality scores, and parsed MRZ/barcode fields when available. Provide SDK callbacks and REST endpoints to hand off artifacts to Briefly’s document assembly and e-sign flows, with versioned schemas and backward-compatible changes. Include failure codes and retry guidance for upstream UI.

Acceptance Criteria
Perspective-Corrected Crop at 300 DPI Equivalent
Given a captured image of a wallet-sized ID (85.6 mm × 54.0 mm) with perspective skew up to 15° and background visible When the Normalized Output pipeline processes the image Then the output is deskewed so detected document edges deviate ≤ 1.0° from horizontal/vertical And the crop includes the entire document with uniform padding of 3% ± 0.5% of the longer edge And the output resolution is ≥ 1011 × 638 px (effective ≥ 300 DPI for ID dimensions) with aspect ratio preserved within ± 2% And no document content is clipped (all detected corner points lie ≥ padding distance from image edges)
Dual-Format Export for Preview and Records
Given a successful normalized capture of an ID side When artifacts are exported Then a preview image is produced in the requested format (JPEG or PNG) with file size ≤ 500 KB and SSIM ≥ 0.98 versus the normalized master And a PDF record is produced at ≥ 300 DPI containing the same image without upscaling artifacts And both artifacts embed creation timestamp (UTC ISO 8601), documentType, and side metadata And for a two-sided document, a single multi-page PDF is generated in front-then-back order
Metadata JSON with Quality Scores and Parsed Fields
Given an export request where quality analysis and decoding have been performed When the JSON payload is generated Then it validates against the published schema version v1.0 (SemVer) with no errors And includes fields: documentType (enum), side (enum), captureTimestamp (UTC ISO 8601), qualityScores {glare:0..1, blur:0..1, edgeConfidence:0..1}, and optional mrz/barcode {raw, parsed, decodeConfidence} And mrz/barcode fields are present only when decodeConfidence ≥ 0.90 And total payload size ≤ 32 KB And field names and enums match the documented contract exactly
SDK Callback and REST Handoff to Briefly Pipeline
Given a completed export for a capture session with idempotency key When the SDK emits onArtifactsReady and the client POSTs to /v1/artifacts Then the callback fires exactly once per capture session And the REST request is idempotent and returns 2xx with the same artifactId on retries using the same idempotency key And end-to-end handoff to Briefly’s document assembly acknowledges receipt within 2 seconds for payloads ≤ 10 MB And 99th-percentile REST latency is ≤ 800 ms over TLS 1.2+ in staging And requests require a valid OAuth 2.0 access token
Versioned Schema with Backward-Compatible Changes
Given a client integrated to schema v1.0 and the service emits v1.1 with additive fields only When the client consumes the v1.1 payload Then no parsing or validation errors occur and unknown fields are safely ignored And responses include X-Schema-Version: v1.1 And contract tests demonstrate 100% pass for v1.0 clients against v1.1 payloads on required fields And CI blocks release if a breaking change is detected by contract tests And any deprecation is announced with a minimum 180-day window before removal
Failure Codes and Retry Guidance for Upstream UI
Given a processing failure due to glare_excessive, motion_blur, edges_not_found, barcode_unreadable, export_timeout, storage_unavailable, or invalid_params When the pipeline returns the error to the upstream UI Then the response includes failureCode (enum), isRetriable (boolean), recommendedAction (enum), and retryAfterSeconds when applicable And the SDK maps failureCode to a user-facing hint key suitable for localization And for retriable failures, the SDK suggests or performs up to 2 retries with exponential backoff between 0.5 s and 2 s and reports the final outcome

ID Auto‑Match

Parses PDF417 barcodes/OCR to extract name, DOB, and address, auto‑fills intake fields, and flags mismatches against answers. One‑tap accept/correct keeps data clean, prevents typos, and reduces downstream rework and venue errors tied to identity details.

Requirements

PDF417 Barcode Decode Engine
"As a solo consumer‑law attorney, I want to scan a driver’s license barcode to auto‑extract identity fields so that I can avoid manual typing and reduce identity errors."
Description

Implement robust decoding of PDF417 barcodes from U.S. driver’s licenses and state IDs to extract identity attributes (first/middle/last name, DOB, address lines, city, state, ZIP, license number). Support AAMVA spec variants and jurisdictional extensions, handle multiple barcodes per image, rotations, glare, and partial scans. Provide both on‑device (iOS/Android native modules) and server‑side decode paths for web uploads, auto‑selecting the fastest available path. Return a structured field map plus the raw payload with parse metadata and error codes for downstream troubleshooting. Expose a stable API to the intake service to prefill the Briefly identity model. Log decode outcomes without storing images unless consent is captured by the consent module. Gracefully signal unreadable or missing barcodes for OCR fallback.

Acceptance Criteria
Decode and Extract Core Identity Fields from PDF417
Given a standards-compliant U.S. driver’s license PDF417 image in good condition When the decode engine processes the image via the default path Then it returns field_map with first_name, middle_name (nullable), last_name, date_of_birth (ISO-8601), address_line1, address_line2 (nullable), city, state (2-letter), postal_code (ZIP or ZIP+4), and license_number populated and normalized And then field_map includes jurisdiction_code and aamva_version and passes JSON schema validation v1.0 And then on the conformance test set of 500 samples, exact-match extraction rate is ≥ 99.5% for DOB and license_number and ≥ 99% for other core fields And then normalization rules apply: state uppercase 2-letter, ZIP zero-padded to 5 or valid ZIP+4, names trimmed and single-spaced
Robustness to Rotations, Glare, and Partial Scans
Given images rotated at 0°, 90°, 180°, and 270° When the engine decodes Then orientation is auto-detected and successful decode rate is ≥ 99% on the rotation test set Given images with glare occluding ≤ 15% of barcode area When the engine decodes Then it either returns a successful result with parse_metadata.corrected_codewords ≥ 0 and warning=GlareCorrected or returns error_code=DAMAGED_BARCODE with parse_metadata.reason=glare Given images with ≥ 70% of the barcode present (partial crop) When the engine decodes Then it attempts error correction and returns success with error_correction_level and corrected_codewords if recoverable, else returns error_code=UNREADABLE_PARTIAL and sets ocr_fallback=true
Multiple Barcodes per Image Handling
Given an image containing multiple barcodes (1D and PDF417) including multiple PDF417 symbols When the engine decodes Then it detects and attempts decode of all PDF417 symbols and ranks candidates by AAMVA compliance, checksum validity, and decoded codewords And then the response contains candidates[] with metadata per symbol and selected_candidate_id referencing the highest-ranked valid AAMVA payload And then if conflicting candidate payloads exist from the same document side, the engine selects the candidate with valid fileType=AAMVA and the greatest successfully decoded codewords And then if no PDF417 symbols are found, the API returns error_code=NO_BARCODE_PDF417
Path Auto-Selection and Fallback (On-Device vs Server-Side)
Given a supported mobile device with on-device decoder available When a scan is initiated Then the engine estimates latency for on-device and server-side and selects the faster path if the difference ≥ 100ms, else prefers on-device And then if the chosen path returns a transient failure, the engine retries once on the alternate path and includes retry_reason in parse_metadata And then P95 end-to-end latency from capture to result is ≤ 800ms for on-device and ≤ 1500ms for server-side on the mobile benchmark set (max image 5MB) And then for web uploads, server-side is used by default; if service capacity is exceeded, the API responds HTTP 503 with error_code=SERVICE_UNAVAILABLE and retry_after seconds
API Contract and Versioning for Intake Prefill
Given the intake service calls Decode API v1 with image bytes or URI and optional consent_token When the request is processed Then the response conforms to JSON schema v1.0 including field_map, raw_payload, parse_metadata, and error (nullable) And then minor version changes (v1.x) are backward compatible; requests specifying an unsupported major version return HTTP 409 with error_code=VERSION_MISMATCH And then maximum request size of 10MB is enforced with HTTP 413 on exceedance And then idempotent retries with Idempotency-Key return identical results and metadata for 24 hours
Outcome Logging and Privacy Controls
Given any decode attempt completes (success or failure) When outcome metrics are logged Then logs include correlation_id, path_used, duration_ms, and error_code (nullable) but exclude plaintext PII (e.g., license_number, address) And then images and raw_payload are not stored unless consent_token authorizes image_storage=true And then if authorized, the system stores the image and raw_payload encrypted at rest with retention ≤ 30 days and links consent_audit_id in logs And then requests attempting storage without valid consent_token are rejected with error_code=CONSENT_REQUIRED (HTTP 400) and no data persisted
Unreadable or Missing Barcode Signaling for OCR Fallback
Given the engine cannot decode a PDF417 or none is present When generating the response Then it returns HTTP 200 with error_code in {NO_BARCODE_PDF417, UNREADABLE_PARTIAL, DAMAGED_BARCODE, LOW_CONTRAST}, sets ocr_fallback=true, and includes parse_metadata.reason And then, when available, a cropped_region_hint bounding box is provided to assist OCR And then only system faults return 5xx; client-visible decode failures use structured error codes as above And then integration test verifies the intake service triggers OCR within 200ms of receiving ocr_fallback=true
OCR Fallback with Confidence Scoring
"As an intake assistant, I want OCR to extract identity details when a barcode scan fails so that I can continue the intake without retyping everything from the ID."
Description

When a barcode is missing or unreadable, run OCR on front/back ID images and uploaded documents to extract name, DOB, and address fields. Use image pre‑processing (deskew, denoise, contrast) and field zoning to improve accuracy, returning per‑field confidence scores and bounding boxes. Support English and Spanish text and common ID layouts; detect and warn on low‑confidence extractions. Provide a normalized output schema identical to barcode decode so downstream flows remain consistent. Surface confidence and source (OCR vs barcode) to the UI to guide the user’s accept/correct decisions. Cache results client‑side until submission to avoid re‑scans and minimize user friction. Automatically fall back to manual entry if both decode and OCR fail.

Acceptance Criteria
Trigger OCR Fallback When Barcode Unavailable
Given the user provides front and back images of a government ID and the PDF417 barcode is missing or fails to decode When the system attempts identity auto-fill Then the system shall invoke OCR on the provided ID images and any uploaded ID documents (PDF/JPEG/PNG) And OCR shall begin within 500 ms of barcode failure detection and complete within 5 seconds per image at p95 And extracted fields shall include full name, date of birth (ISO-8601), and address components when present And the result shall include source="ocr" and a reason for fallback logged for analytics
Image Preprocessing Improves OCR Accuracy
Given an ID image that may be skewed (≤ ±15°), noisy, or low contrast When image preprocessing runs Then skew is corrected to within ±1° and denoising/contrast normalization is applied prior to OCR And preprocessing and OCR shall operate entirely on-device or server-side according to deployment without requiring additional user action And on a labeled validation set of ≥100 ID images, field-level F1 ≥ 0.92 for name and DOB and ≥ 0.90 for address after preprocessing And the pipeline returns the preprocessed image dimensions used to compute bounding boxes
Per-Field Confidence Scores and Bounding Boxes
Given OCR extracts candidate values for name, DOB, and address When results are assembled Then each field shall include: value, confidence in [0.0,1.0], and a bounding box {x,y,width,height} normalized to [0,1] relative to the processed image And if multiple candidates exist, the highest-confidence value is selected and alternates are returned in a ranked list with confidences And any field with confidence < 0.85 is marked low_confidence=true and emits a warning event
English and Spanish Text and Common ID Layout Support
Given a US state driver license or state ID containing English or Spanish labels and text When OCR with field zoning is executed Then accented characters and Spanish diacritics are preserved in extracted values And label variants (e.g., "Nombre", "Apellido", "Fecha de Nacimiento", "Dirección") are correctly mapped to name, DOB, and address And on separate English and Spanish test sets (≥100 each), field-level accuracy ≥ 95% for DOB and ≥ 92% for full name; address components each ≥ 90%
Normalized Output Schema Parity With Barcode Decode
Given identity data is obtained via barcode decode or OCR When the system produces the output payload Then the schema shall match the existing barcode decode schema exactly (field names, nesting, and data types), with added properties confidence and bbox per field and source at the root And contract tests against downstream consumers execute without code changes and all pass And DOB is normalized to ISO-8601 (YYYY-MM-DD) and address parsed into line1, line2, city, state, postal
UI Surfacing of Confidence and Source With Accept/Correct
Given extracted identity fields are available When the intake UI renders the fields Then each field displays its source (Barcode or OCR) and confidence as a percentage And fields with confidence < 0.85 are visually flagged and include an inline warning And one-tap Accept stores the value with provenance and prevents re-asking; Correct opens edit with the original value prefilled And after a manual correction, the field source updates to "user" and confidence is set to 1.0 And accessibility: source and confidence are announced via screen reader and have 4.5:1 contrast
Client-Side Caching and Manual Entry Fallback
Given the user has performed an ID scan or upload during intake When the user navigates away and returns before submission Then previously extracted values and confidence metadata are restored from client-side cache without re-running OCR or barcode decode And cache persists across refreshes for at least 30 minutes or until submission/logout and is invalidated if images are removed/replaced And if both barcode decode yields no result and OCR yields no fields above 0.50 confidence, the flow automatically presents manual entry with a non-blocking notice And telemetry records zero additional scans on return navigation within the cache window
Identity Normalization & Address Verification
"As an attorney, I want names, DOB, and addresses standardized to official formats so that documents and filings are generated correctly without venue or mailing errors."
Description

Normalize extracted identity data into Briefly’s canonical schema to ensure downstream document assembly and e‑filing compatibility. Apply name casing and punctuation rules, standardize DOB to ISO‑8601, and parse address components (street, unit, city, state, ZIP+4). Validate plausibility (e.g., DOB within realistic age bounds, ZIP‑state consistency) and enrich addresses via USPS CASS/NCOA to correct abbreviations and produce deliverable addresses. Flag unit/apartment detection and suggest structured unit fields when present. Produce a canonical record with both raw and normalized values plus transformation provenance for auditability. Expose normalization as an idempotent service invoked by both barcode and OCR pipelines.

Acceptance Criteria
Normalize Name Casing & Punctuation
Given a name extracted from barcode or OCR that may contain mixed casing, extra spaces, and punctuation When the normalization service processes the name Then First, Middle, Last, and Suffix fields are produced with Title Case for names and Unicode diacritics preserved And common suffixes are normalized to the standard set {Jr., Sr., II, III, IV, V} And single-letter middle initials are uppercased with a trailing period And hyphens and apostrophes within name tokens are preserved; other stray punctuation is removed And multiple spaces are collapsed and leading/trailing whitespace is trimmed And full_name is formatted as "First Middle Last, Suffix" without extra spaces or commas when parts are missing And if First and Last cannot be determined, the record is flagged "name_unparsable" and no normalized name is produced
Standardize DOB to ISO-8601 and Plausibility Bounds
Given a DOB string in one of the supported formats (e.g., MM/DD/YYYY, M-D-YYYY, Month DD, YYYY, YYYY-MM-DD) When the normalization service processes the DOB Then dob_normalized is in ISO-8601 format "YYYY-MM-DD" using the Gregorian calendar And leap-day dates are validated per leap-year rules And the computed age as of processing time is between 13 and 120 years inclusive; otherwise flag "dob_out_of_bounds" and do not emit dob_normalized And ambiguous numeric dates that cannot be definitively parsed are rejected with reason "dob_ambiguous"
Parse and Standardize Address Components
Given an address entered as one or two free-text lines plus city, state, and ZIP When the normalization service parses the address Then it returns structured components: primary_number, predirectional, street_name, street_suffix, postdirectional, secondary_designator, secondary_number, city, state (2-letter uppercase), zip5, zip4 And ZIP is validated as 5 digits with optional 4-digit extension And state names are normalized to USPS two-letter codes And street suffixes and directionals are standardized per USPS Publication 28 abbreviations And ZIP–state–city consistency is validated; mismatches are flagged "zip_state_city_mismatch" with suggested corrections when available
USPS CASS/NCOA Enrichment and Deliverability Outcomes
Given a parsed address When the service requests CASS and NCOA verification Then address components are updated to USPS-standard abbreviations and ZIP+4 and carrier route are populated when available And deliverability_status is set to one of {deliverable, deliverable_with_unit_required, undeliverable, moved, vacancy, not_cass_certified} based on provider response codes And when a forwarding address exists within the NCOA lookback window, the new address and move_effective_date are returned as enrichment And if the provider is unavailable or times out, normalization proceeds without enrichment, deliverability_status is "not_cass_certified", and provenance records the error and retry attempts And the enrichment step completes within 2.5s p95 with a single retry using exponential backoff; otherwise the request is short-circuited and logged
Unit/Apartment Detection and Structured Field Suggestion
Given an address line that contains indicators such as "#", "Apt", "Unit", "Ste", "Lot", or floor numbers When the normalization service processes the address Then secondary_designator and secondary_number are extracted into structured fields And unit indicators are removed from the primary delivery line in the normalized output And when CASS indicates a unit is required but none is present, the record is flagged "unit_missing" and a structured field suggestion is returned with a user-facing message key And if multiple unit-like tokens are detected, the ambiguity is flagged "unit_ambiguous" with token positions captured in provenance
Canonical Record, Provenance, and Idempotency Across Pipelines
Given inputs containing raw name, DOB, and address from barcode or OCR pipelines When the normalization service is invoked with identical payloads multiple times Then the normalized output, flags, and provenance are bit-for-bit identical and no external state is mutated And the canonical record includes raw and normalized variants for each field, validation flags, enrichment metadata (including DPV/CASS/NCOA codes), normalization_version, source_pipeline, normalization_timestamp, and a deterministic content_hash And the service exposes a stable contract (JSON in, JSON out) used by both pipelines; invalid payloads return HTTP 422 with machine-readable error codes; transient provider failures return HTTP 503 with retry-after guidance And performance meets p95 <= 150ms without enrichment and p95 <= 800ms with enrichment at >= 50 requests/second sustained, with error rate < 0.1%
Mismatch Detection & Rules Engine
"As a practitioner, I want clear, actionable flags when the ID data doesn’t match the intake answers so that I can resolve discrepancies before engagement or filing."
Description

Compare the canonical ID record against user‑entered intake answers and flag discrepancies at a field level. Classify differences (formatting‑only vs substantive mismatch) using configurable rules, thresholds, and reason codes (e.g., nickname vs legal name, old vs current address). Assign severity and recommended actions (accept ID, keep intake answer, request clarification) and support firm‑level policies for auto‑accept behavior. Emit structured mismatch events for analytics and maintain an audit link to source artifacts. Integrate with venue logic to warn when address mismatches could lead to court selection errors. Provide a simple configuration UI for admins to tune matching rules without code changes.

Acceptance Criteria
Field-Level Mismatch Detection and Classification
Given a canonical ID record (name, DOB, address) and user-entered intake answers exist When the mismatch engine runs Then each supported field is compared and mismatches are emitted at the field level And each difference is classified as "formatting-only" if normalized equality holds per configured rules and thresholds And each non-equal after normalization is classified as "substantive" with a reason code And severity is assigned per rule mapping (Info for formatting-only, Warning/Error for substantive) And a recommended action is attached (Accept ID, Keep Intake, Request Clarification) And mismatches are displayed inline next to the affected fields
Admin Rule Configuration UI and Versioning
Given an authenticated admin opens Matching Rules settings When creating or editing a rule for a field Then the admin can define normalization transforms, match thresholds, reason codes, severity, and recommended actions And the UI validates inputs and prevents conflicting or incomplete configurations And changes are versioned with metadata and take effect for new sessions upon save And a Test Against Samples mode previews classification outcomes before save And admins can export/import the full ruleset and reset to defaults
Firm Auto-Accept Policy Enforcement
Given firm auto-accept policies are configured When mismatches are classified as formatting-only for a field with auto-accept enabled Then the system auto-accepts the ID value and marks the mismatch resolved without user input And an immutable audit entry records policy, resolver=system, timestamp, and before/after values And no auto-accept occurs for DOB mismatches or any substantive mismatch unless explicitly enabled And auto-accepted fields are visually indicated with an info badge
Structured Mismatch Events and Audit Linkage
Given a mismatch is detected or resolved When the event is emitted Then the payload includes intake_id, client_id, field, intake_value, id_value, classification, reason_code, severity, recommended_action, action_taken, actor_id, timestamp, ruleset_version, venue_context, and source_artifact_uris And events are delivered to the analytics stream and persisted to the audit store And each event has a stable event_id and can be de-duplicated And clicking "View Source" opens the source artifact viewer for the ID extract and OCR text
Venue Logic Integration and Blocking Warnings
Given address fields influence venue selection When an address mismatch could result in a different venue according to venue logic Then a blocking warning is shown before venue selection can be finalized And the warning explains the impact and offers one-tap actions to accept ID address or keep intake address And resolving the address mismatch clears the warning and recomputes venue And if the mismatch does not change venue, show a non-blocking info notice
One-Tap Accept/Correct Resolution and Propagation
Given a list of field-level mismatches is shown When the user taps Accept ID, Keep Intake, or Request Clarification for a mismatch Then the selected value becomes the canonical value for downstream documents and data And the mismatch status changes to Resolved with the chosen resolution and timestamp And the retainer and draft documents are regenerated with the resolved values And an audit entry is written with resolver identity and rationale (if provided)
Normalization Defaults and Formatting-Only Determination
Given the default ruleset is enabled When comparing values Then case, punctuation, and whitespace differences in names are treated as formatting-only And standard street suffix and apartment/unit synonyms are treated as formatting-only in addresses And DOBs that parse to the same calendar date across common formats are treated as formatting-only And nickname equivalence is treated per the configured nickname map; if mapped, classification is formatting-only; if not, classification is substantive with reason code NicknameMismatch And address recency differences within the configured staleness window are classified as "old vs current address" with severity Warning
One‑Tap Accept/Correct Intake UI
"As a mobile user, I want to accept or correct each identity field with a single tap so that I can reconcile data quickly and finish intake on my phone."
Description

Provide a mobile‑first, accessible UI that displays side‑by‑side diffs between extracted and entered values and enables one‑tap accept/correct per field. Support Accept All, per‑field Accept, Keep Original, and inline edit with undo. Indicate source and confidence (barcode vs OCR) and visually highlight severity based on rules engine classifications. Apply accepted values to prefill intake forms and immediately update downstream assemblies (retainer, draft pleadings). Capture user actions for analytics (time saved, fields corrected) and write a reconciliation note to the matter timeline. Ensure performance and touch targets meet mobile usability standards and work offline until submission.

Acceptance Criteria
Side-by-Side Diff with Source, Confidence, and Severity
Given a mobile user reviewing extracted identity data alongside entered intake values, When the review screen loads, Then each field displays Entered (left) and Extracted (right) values with inline diff highlighting for mismatches. Given an extracted value, When it is displayed, Then a source badge (Barcode or OCR) and numeric confidence (0–100%) are shown. Given a field with confidence < 70%, When rendered, Then it is labeled Low Confidence with a distinct icon and secondary highlight. Given a rules engine severity classification (Info, Warning, Critical), When a field is rendered, Then a severity badge with distinct color and label is shown and meets contrast ratio ≥ 4.5:1. Given a mid‑tier mobile device, When loading the review screen over typical 4G conditions, Then first contentful paint occurs in ≤ 1.5s and interactive in ≤ 2.0s, with incremental field rendering allowed.
One‑Tap Actions: Accept All, Per‑Field Accept, Keep Original, Inline Edit with Undo
Given one or more fields with extracted values, When the user taps Accept All, Then all fields with extracted values replace the entered values and show a success state within 300ms, and an Undo All control is available for 10s. Given a single field with a mismatch, When the user taps Accept on that field, Then only that field updates to the extracted value, marks as Accepted, and offers Undo for 10s. Given a mismatched field, When the user taps Keep Original, Then the entered value is retained, the field is marked as Kept Original, and is excluded from Accept All. Given a field, When the user taps Inline Edit, Then the field becomes editable inline with mobile keyboard focus and Save/Cancel controls; Save applies the new value and Cancel reverts. Given a Critical severity field, When Accept All is tapped, Then the Critical field is excluded and requires explicit per‑field Accept with a confirmation prompt.
Immediate Prefill and Downstream Assembly Update
Given a field is accepted or edited, When the action completes, Then the canonical intake data store updates immediately and reflects in bound form inputs without page reload. Given any accepted or edited identity field, When updated, Then the retainer and draft pleading assemblies incrementally regenerate with the new values within 1s and the preview reflects the change on next open; if a preview is currently open, Then a refresh prompt appears and shows the updated document within 2s of confirmation. Given the user performs Undo for a field, When applied, Then the intake data and downstream assemblies revert to the prior values within 1s.
Analytics Capture and Matter Timeline Reconciliation Note
Given the user completes the review (Accept All or Done), When the session ends, Then analytics record: fields with extracted values, fields accepted, fields kept original, fields edited inline, accepts undone, and elapsed review time. Given analytics capture, When time saved is computed, Then it is calculated as (baseline seconds per field × fields with extracted values) − elapsed review time, with a configurable baseline default of 5s/field. Given accepted or edited fields, When the session completes, Then a reconciliation note is written to the matter timeline including timestamp, user, field names with old → new values, source and confidence for accepted values, and overall summary counts. Given offline use, When analytics and notes cannot be sent, Then they are persisted locally and queued for sync with guaranteed delivery on reconnect.
Offline‑First Review and Sync
Given the device is offline, When the review screen is opened with previously extracted data available, Then all one‑tap actions (Accept All, Accept, Keep Original, Inline Edit, Undo) function locally without errors. Given actions performed offline, When connectivity is restored, Then all queued data changes and analytics sync to the server within 5s, preserving action order. Given a server‑side concurrent change to the same fields, When sync occurs, Then the user’s latest offline actions win and an audit entry records the conflict resolution. Given sync completes, When successful, Then the UI shows a non‑blocking confirmation; When failed, Then the user is notified with a retry option and no data loss.
Accessibility and Mobile Usability Standards
Given the review UI is rendered on a mobile device, When interacted with, Then all actionable elements have touch targets ≥ 44×44 points and spacing that avoids accidental taps. Given the UI, When tested for accessibility, Then it meets WCAG 2.1 AA: color contrast ≥ 4.5:1, proper semantic roles, focus order following visual order, and labels for screen readers that announce field name, entered value, extracted value, source, confidence, and severity. Given a user navigating via screen reader, When focus lands on a mismatched field, Then the mismatch and severity are announced before actions, and actions are operable by accessible gestures. Given one‑tap actions, When tapped, Then visual and haptic feedback occur within 100ms and the state change is announced to assistive technologies. Given device orientation changes, When rotated, Then the side‑by‑side layout adapts responsively without loss of information or controls.
Parsing Gaps and Error Handling
Given a barcode scan fails or is incomplete, When OCR is available, Then OCR parsing is attempted automatically and its source and confidence are shown. Given both barcode and OCR fail to provide a value for a field, When the review screen renders, Then the field displays Not Available, allows manual entry via Inline Edit, and is excluded from Accept All. Given a field’s extracted value exists but below confidence threshold (< 70%), When Accept All is tapped, Then the field is excluded from Accept All and requires per‑field Accept. Given an unexpected error during an action, When it occurs, Then the UI shows a non‑blocking error message, the action is rolled back, the field remains consistent, and the error is logged for diagnostics without exposing PII.
Security, Consent & Audit Trail
"As a firm admin, I want consent and a complete audit trail for ID scanning so that we meet privacy obligations and can prove data provenance if challenged."
Description

Collect explicit end‑user consent before scanning or processing ID images, with jurisdiction‑appropriate language and firm branding. Store consent artifacts (text version, timestamp, user, IP/device) and cryptographically bind them to the ID scan via content hash. Encrypt images and extracted PII in transit and at rest, restrict access via role‑based controls, and redact sensitive fields from logs. Maintain an immutable audit trail linking source images, raw payloads, normalized values, mismatch decisions, and the user who accepted changes. Provide configurable retention policies and secure delete, plus admin export for audits or subpoenas. Integrate with Briefly’s matter timeline to show when and how identity details were verified.

Acceptance Criteria
Pre-Scan Explicit Consent Blocking Flow
Given a client user initiates ID Auto‑Match on a mobile device When the scan screen loads Then a consent dialog displays firm branding and jurisdiction‑appropriate language And the Scan action is disabled until the user selects "I Agree" Given the client selects "I Agree" When consent is accepted Then the system records consent_text_version, UTC timestamp, user/session identifier, IP address, device fingerprint, and a unique consent_id And the camera/upload control is enabled without re‑prompting during the session Given the client selects "Decline" When consent is declined Then the system blocks camera and upload access And no ID images or extracted PII are stored And a minimal decline event with UTC timestamp and user/session identifier is recorded Given the client’s jurisdiction cannot be resolved When the consent dialog is displayed Then the system uses the firm’s default consent language And records the fallback locale/language in the consent artifact
Cryptographic Binding of Consent to ID Scan
Given consent has been accepted and an ID image is captured or uploaded When the system receives the image payload(s) Then it computes a SHA‑256 hash per file and an aggregate hash for the scan session And stores the hashes alongside the consent_id in an append‑only record Given an auditor requests the consent/scan linkage When the system recomputes the hash of the stored image payload(s) Then the recomputed hashes match the stored hashes And the record returns consent_text_version, consent_id, UTC timestamp, user/session identifier, IP/device metadata, file_hashes, and aggregate_hash Given an image payload is altered after storage When hash verification is performed Then the verification fails and a tamper‑evidence event is appended to the audit trail And access to the altered artifact is blocked with an error code and audit entry
Encryption, Transport Security, and Log Redaction
Given any API/UI endpoint that handles ID images or extracted PII When a client attempts a non‑TLS (HTTP) request Then the request is rejected without processing payloads And a 403 error is returned with no sensitive data in the response Given images and extracted PII are stored When data is written at rest Then it is encrypted using AES‑256 with keys managed in a KMS And access to keys is limited by least‑privilege IAM policies Given application and access logs are generated during scanning and extraction When logs are written Then sensitive fields (name, DOB, address, ID number, barcode payloads, image bytes) are redacted or hashed And logs contain only references (matter_id, document_id, consent_id, hashes) and non‑PII metadata And error traces do not include raw payloads
Role‑Based Access Controls for ID Images and PII
Given firm roles are configured (Attorney, Intake Paralegal, Admin, Observer) When an authorized user (Attorney, Intake Paralegal, Admin with permission) requests to view ID images or extracted PII Then access is granted And an access event is appended to the audit trail with user_id, role, matter_id, purpose, and UTC timestamp Given an unauthorized user (Observer or user without permission) requests to view or export ID images/PII When the request is evaluated Then a 403 is returned And no data is disclosed And a denied‑access event is logged in the audit trail Given a direct file URL is shared or guessed When requested without valid authentication and a time‑limited signature Then the request is denied And the attempt is captured in the audit trail
Immutable Audit Trail of ID Auto‑Match Decisions with Export
Given an ID scan is processed When barcode/OCR extraction and normalization occur Then the system records source image references, raw extraction payloads, normalization mappings (to name, DOB, address, ID number), mismatch results, and the acting user’s accept/correct decisions with UTC timestamps in an append‑only ledger Given any audit record exists When a user attempts to edit or delete an existing event Then the system prevents mutation of prior events And only allows new corrective events to be appended with a reason Given an admin initiates an audit export for a matter or date range When the export completes Then the package includes consent artifacts, audit ledger events, hash manifest, and referenced images And the export is signed with a manifest hash And is available for secure download within 5 minutes And the export action is recorded in the audit trail
Retention Policies, Legal Hold, and Secure Delete
Given an admin configures retention settings When retention days are set per matter type and saved Then the policy is enforced for new and existing artifacts And policy changes are versioned and auditable Given artifacts reach their retention expiry and no legal hold is active When the deletion job runs Then the system crypto‑shreds encryption keys and purges images, raw payloads, and extracted PII within 24 hours And a secure‑delete event is appended to the audit trail including counts and identifiers Given a matter is placed on legal hold When retention expiry is reached Then deletion is paused until the hold is removed And hold placement/removal events are recorded with user, reason, and timestamp Given an admin triggers a manual purge for a matter not on legal hold When confirmation is provided Then the same secure delete process is executed and audited
Matter Timeline Integration of Identity Verification
Given a mismatch is flagged and a user accepts or corrects identity details When the decision is saved Then a matter timeline entry is created showing verification method "ID Auto‑Match", fields verified, mismatch outcomes, acting user, and UTC timestamp with matter‑local display And the entry links to the audit record and consent artifact Given a client declines consent or scanning fails irrecoverably When the intake session ends Then a timeline entry indicates identity verification was not completed and why (declined, timeout, error code) Given user permissions vary by role When viewing the timeline Then PII values are masked for users without view‑PII permission And authorized users can reveal values on demand, which is audited
Performance & Telemetry Targets
"As a mobile intake user, I want scanning and auto‑match to complete quickly so that I can stay in flow and finish intake without delays."
Description

Meet responsive performance goals for scanning, extraction, and matching to keep users in flow: p95 end‑to‑end under 2.5 seconds on mid‑tier mobile devices and under 2.0 seconds on desktop; fail fast to OCR or manual entry on repeated decode timeouts. Optimize on‑device models and image capture to reduce retries and battery drain. Instrument telemetry across stages (scan_start, decode_success, ocr_fallback_used, mismatch_count, accept_all_used, resolution_time) with privacy‑safe metrics. Provide dashboards and alerts for anomaly detection (e.g., sudden decode failure spikes by jurisdiction). Expose per‑tenant KPIs (time saved, error reduction) to validate ROI. Ensure horizontal scalability of server‑side components to support traffic bursts during peak intake hours.

Acceptance Criteria
Platform p95 E2E Latency Targets
Given the defined mid-tier mobile device matrix and supported desktop browsers under the STANDARD_INTAKE network profile, When a user scans an ID and the system completes decode/extraction and auto-match to produce a match_result, Then the measured p95 end-to-end latency from scan_start to match_result is ≤ 2.5 seconds on mid-tier mobile and ≤ 2.0 seconds on desktop across ≥ 1000 sessions per platform within a 24-hour window, And the p99 is ≤ 4.0 seconds on mobile and ≤ 3.0 seconds on desktop, And telemetry-derived percentiles align within ±5% of stopwatch measurements gathered from synthetic runs.
Fail-Fast Fallback on Repeated Decode Timeouts
Given a scan session has begun and no decode_success has occurred, When either (a) two consecutive decode attempts exceed 1200 ms each or (b) total elapsed time since scan_start without decode_success exceeds 3000 ms, Then the system presents an OCR fallback or manual entry prompt within 300 ms and pre-populates the last captured image for OCR, And if OCR does not complete within 2000 ms, the manual entry form is shown automatically, And events ocr_fallback_used (with reason=timeout) and a correlation_id are emitted, with a visible one-tap option to return to scanning.
Battery Impact and Retry Rate Optimization
Given standard device conditions (battery ≥ 50%, screen brightness 50%, no low-power mode) on the mid-tier mobile matrix, When a user completes a successful ID Auto-Match session, Then median battery drop per session is ≤ 1.0% and p95 ≤ 2.5%, And median capture attempts per session ≤ 1 with p95 ≤ 2, And on-device CPU time for the capture→decode pipeline is ≤ 8 seconds (aggregate) with thermal throttling occurring in < 0.5% of sessions.
Privacy-Safe Telemetry Events Emitted Across Stages
Given telemetry is enabled for the tenant, When any scan session occurs, Then events scan_start, decode_success, and ocr_fallback_used are emitted; mismatch_count is recorded on match_result; accept_all_used action is logged when selected; and resolution_time_ms is captured from first mismatch prompt to final resolution, And each event includes timestamp_ms, platform, device_class, app_version, tenant_id_hash, jurisdiction_code, and correlation_id, And no PII (name, DOB, address, raw barcode payload) is present in any event payload as verified by automated PII scanners, And event schema validation success rate is ≥ 99.9% with end-to-end event loss < 1% measured via audit beacons.
Anomaly Detection Dashboards and Alerts by Jurisdiction
Given decode and match telemetry is flowing to the analytics store, When decode_success_rate for any jurisdiction drops by ≥ 10 percentage points versus its 7-day moving baseline for ≥ 10 minutes, Then an alert with jurisdiction, platform, and app_version dimensions is delivered to the Intake Reliability channel and on-call within 2 minutes of threshold breach, And product dashboards display p50/p95/p99 latencies, decode_success_rate, ocr_fallback_rate, mismatch_count distribution, and resolution_time by jurisdiction, platform, and app_version with data freshness ≤ 5 minutes, And synthetic anomaly injection triggers and clears the alert and corresponding dashboard annotations.
Per-Tenant KPI Exposure for Time Saved and Error Reduction
Given a tenant has ≥ 50 completed scan sessions in the last 30 days, When a tenant admin opens the ID Auto-Match Analytics page or requests the KPI API endpoint, Then the system returns time_saved_minutes and error_reduction_percent for that tenant with definition tooltips and API field docs, And time_saved_minutes equals (configured baseline median manual-entry time per tenant − observed median time to complete ID fields) × session_count_last_30d, And error_reduction_percent equals (baseline_typos_rate − observed_mismatch_rate) ÷ baseline_typos_rate × 100, And KPI values match offline recomputation within ±5% and the API responds within 500 ms p95 without exposing PII.
Horizontal Scalability Under Peak Intake Bursts
Given auto-scaling is enabled for server-side decode/OCR, telemetry, and analytics ingestion components, When a load test simulates 800 RPS sustained for 15 minutes with bursts to 2000 RPS for 60 seconds at 5-minute intervals, Then p95 server-side processing latency for decode/OCR remains ≤ 250 ms and error rate (HTTP 5xx + timeouts) remains < 0.5%, And queue depth stabilizes within 90 seconds of each burst with zero data loss and no dropped telemetry, And the system scales out within 90 seconds of exceeding 70% CPU utilization and scales back within 10 minutes after load subsides without impacting SLOs.

Signer Bind Proof

Cryptographically binds the verified ID to the e‑signature certificate and audit trail, embedding timestamp, device fingerprint, geo/time context, and verification hash. Produces a court‑ready evidence packet that strengthens enforceability and defuses later identity challenges.

Requirements

KYC Identity Verification Integration
"As a solo consumer‑law attorney, I want each signer’s identity verified to a defendable standard before e‑signature so that my retainers are enforceable and identity disputes are minimized."
Description

Integrate pluggable KYC/identity verification providers to verify each signer before e‑signature, capturing a signed verification attestation and immutable hash for binding. Supports document scan, selfie liveness, biometric match scores, and optional watchlist screening with configurable verification levels (e.g., IAL2 equivalent) per matter type. Mobile-first flows embed in Briefly’s questionnaires with retry and fallback to manual verification when automated checks fail. Stores only minimal data (verification token, provider reference, normalized result, and cryptographic hash), with configurable retention/redaction to meet GDPR/CCPA and bar-ethics obligations. Provides a unified adapter interface for vendors (e.g., Onfido/Persona/Trulioo), health checks, and automatic failover. Emits normalized events for the audit trail to ensure downstream cryptographic binding and evidence generation can rely on consistent inputs.

Acceptance Criteria
Mobile IAL2 KYC Pass Enables E‑Sign; Failure Blocks Signing
Given a signer completes the mobile questionnaire flow When the signer reaches the e‑signature step without a successful KYC verification Then the e‑signature controls are disabled and a prompt directs the signer to complete KYC And the system records an audit event verification.started with device fingerprint and geo/time context When the signer completes document scan, selfie liveness, and biometric match And the biometric match score meets or exceeds the configured threshold for IAL2‑equivalent And required checks for the matter type (e.g., watchlist on/off) are satisfied Then the system records verification.succeeded with normalized result and provider reference And the e‑signature controls become enabled for that signer only
Signed Verification Attestation and Immutable Hash Binding
Given a signer’s KYC verification has succeeded When the signer is presented with a verification summary (provider, checks, score, time, device, geo) Then the signer must electronically acknowledge the verification attestation to proceed When the attestation is acknowledged Then the system generates a cryptographic hash over the normalized verification payload, timestamp, device fingerprint, geo/time context, provider reference, and verification level And stores only the hash, normalized result summary, verification token, and provider reference And emits events attestation.signed and verification.hash.created for the audit trail And binds the attestation signature and verification hash to the e‑signature certificate metadata
Automated KYC Retry and Manual Verification Fallback
Given an automated KYC attempt fails or times out When retries remain below the configured maximum (e.g., 3) Then the signer can retry with guided error messaging and the attempt is logged with provider error codes When the maximum retry count is reached or the provider remains unavailable Then the system offers a manual verification path requiring ID uploads and human review And upon manual approval, emits verification.succeeded with result_source=manual, reviewer ID, and timestamp And the same attestation and hashing steps are enforced before enabling e‑signature
Provider Adapter Health Checks and Automatic Failover
Given multiple KYC providers are configured with priority and capabilities When the primary provider’s health check fails or rolling error rate exceeds the configured threshold Then the system fails over to the next compatible provider without losing the signer’s session or collected inputs And health checks run at startup and on an interval (e.g., 60s), emitting provider.health status events And all provider responses are normalized to the unified schema regardless of vendor And the selected provider and failover reason are recorded in the audit trail
Normalized Verification Events Drive Cryptographic Evidence Generation
Given verification activities occur for a signer When events are emitted Then they conform to the normalized schema including: matter_id, signer_id, provider, verification_level, checks_performed, score, liveness_result, doc_types, device_fingerprint, geo/time context, provider_ref, verification_token, hash (when available), and retention_policy_id And events are append‑only, ordered per signer, and idempotent with deterministic event IDs And downstream evidence generation consumes these events to produce an evidence packet linked to the e‑signature certificate And any schema validation failure blocks evidence generation and surfaces an alert
Per‑Matter Configurable Verification Levels and Enforcement
Given an admin configures verification profiles per matter type (e.g., Basic, IAL2‑equivalent) When a new matter is created Then the required profile is attached and enforced for all signers on that matter When a signer attempts to e‑sign without meeting the attached profile requirements Then e‑signature is blocked with a message referencing the unmet checks (e.g., liveness not completed) And the audit trail records the profile ID, version, and checks evaluated with pass/fail per check
Data Minimization and Retention/Redaction Compliance
Given Briefly processes KYC data Then the system stores only: verification token, provider reference, normalized result summary (no raw images/biometric templates), cryptographic hash, timestamps, device fingerprint, and geo/time context And raw artifacts remain with the provider and are not persisted by Briefly When the configured retention period elapses or a GDPR/CCPA erasure/redaction request is approved Then the system redacts/deletes stored data per policy while retaining the cryptographic hash and minimal audit metadata And a retention action log is generated and exportable for compliance And data subject requests can be fulfilled within 30 days with evidence of completion
Cryptographic Binding Engine
"As an attorney, I want the signature, verified identity, and audit evidence to be cryptographically bound so that any tampering is immediately detectable and the agreement is more enforceable in court."
Description

Create a tamper‑evident binding that cryptographically links the verified identity to the e‑signature certificate, audit trail, and document. Assembles a canonical claims set (verification hash, signer certificate ID, timestamp authority token, device fingerprint hash, IP/ASN, geo context, and Briefly matter metadata) and produces a signed envelope (e.g., JWS/JAdES) using keys protected in HSM/KMS with rotation and key versioning. Embeds or references the envelope within the signed PDF (PAdES‑LTV compatible) and chains it into an append‑only audit log with hash‑linking for integrity. Provides an offline verification routine and library to validate signatures, key provenance, and chain completeness without contacting Briefly. Exposes deterministic serialization/versioning to ensure long‑term validity and expert reproducibility in court.

Acceptance Criteria
Canonical Claims Set Assembly
Given a verified signer identity, a completed e-signature, and a Briefly matter context When the binding engine assembles the canonical claims set Then the claims object includes exactly: verification_hash (SHA-256, base64url), signer_certificate_id, tsa_token (RFC 3161 DER, base64), device_fingerprint_hash (SHA-256, base64url), ip, asn, geo_context (ISO 3166-1 alpha-2, lat, lon with 4-decimal precision), matter_metadata (matter_id, product="Briefly", feature="Signer Bind Proof", requirement="Cryptographic Binding Engine", version) And the claims are serialized using a deterministic canonical form (JCS for JSON or equivalent) with lexicographically sorted property names and no insignificant whitespace And the byte-level digest of the serialized claims equals verification_hash And attempts to assemble with any missing required claim hard-fail with error code BIND-CLAIMS-REQ-MISSING and no envelope is produced
HSM-backed Signing and Key Rotation
Given a configured signing key in HSM/KMS marked non-exportable and enabled for digital signature When the engine signs the canonical claims set Then the output envelope is a detached JWS (RFC 7515) or JAdES-B-B with protected header containing alg, kid, key_version, and iat And the signing operation is performed in HSM/KMS (attested by provider audit log entry id present in envelope header hsm_audit_id) And key rotation results in subsequent envelopes containing incremented key_version while older envelopes remain verifiable And an attempt to use a disabled or retired key fails with error code BIND-SIGN-KEY-INVALID
PAdES-LTV Embedding of Binding Envelope
Given a PDF with an e-signature field finalized When the engine embeds or references the binding envelope Then the resulting document validates as PAdES-LT/LTV with 0 critical and 0 major warnings in ETSI/Adobe validators And the envelope is retrievable from the PDF as a document attachment named bind-envelope.jws (or .csig) and referenced from DSS with integrity-preserving hash And verifying the embedded envelope’s digest matches the reference recorded in the signature’s signed attributes
Append-Only Audit Log with Hash Linking
Given an existing audit log tail hash Hn When a new envelope E(n+1) is produced Then the engine computes link_hash = SHA-256(Hn || SHA-256(E(n+1)) || monotonic_timestamp || nonce) And appends an immutable record {index:n+1, envelope_hash, prior_hash:Hn, link_hash, timestamp, key_version} to the log And any deletion or modification of a prior record is detected by recomputing link_hash values and results in error code BIND-AUDIT-TAMPER on verification
Offline Verification Library Validates Binding and Provenance
Given only the signed PDF or the evidence packet and an offline trust bundle (root CAs and TSA roots) When the verifier is run with network access disabled Then it validates: envelope signature cryptographically, certificate chain to a trusted root, TSA token against TSA root, audit log hash chain completeness, and claim set digest consistency And it verifies that kid/key_version corresponds to a known Briefly key provenance record embedded in the evidence And it completes within 5 seconds for up to 5 signatures on a standard laptop (4 cores, 16GB RAM) And clear result codes are emitted: PASS, FAIL-SIGNATURE, FAIL-CHAIN, FAIL-TSA, FAIL-AUDIT, FAIL-CLAIMS
Deterministic Serialization and Versioning for Reproducibility
Given identical inputs (claims values, signing key/version, and timestamp token) When the envelope is generated on different platforms (Linux, macOS, Windows) and time zones Then the produced envelope bytes are identical (byte-for-byte) and produce the same SHA-256 digest And the protected header contains spec_version in the form "bind.v1" and serialization="JCS" And a published test vector suite verifies reproducibility with all tests passing
Court-Ready Evidence Packet Generation
Given a completed signing workflow When the user downloads the evidence packet Then the packet is an ASiC-E or ZIP container with a manifest (JSON) listing all entries with SHA-256 digests: signed.pdf, bind-envelope, audit-log-slice.json, verification-report.json, cert-chain.pem, trust-bundle-info.json, and serialization-schema.json And the offline verifier can validate the packet with no external calls, returning PASS And the packet embeds human-readable summary (PDF or HTML) of verification results and key provenance, matching the machine-readable report hash
Device Fingerprint & Consent Capture
"As a signer, I want to understand and consent to limited device data collection so that my privacy is respected while still enabling strong proof of who signed."
Description

Collect and normalize a privacy‑preserving device fingerprint at signing time (user agent, platform, screen metrics, entropy signals) and store only salted hashes and stability scores for binding. Present explicit, region‑aware consent text explaining what is collected and why, with a clear opt‑in and accessible alternative flow if declined. Handle mobile and desktop consistently, resist trivial spoofing, and avoid third‑party trackers. Link the fingerprint hash, consent record, and signer session to the audit trail and cryptographic binding. Provide data minimization, access, and deletion controls aligned with GDPR/CCPA and firm policies.

Acceptance Criteria
Fingerprint Collection and Normalization at Signing
Given a signer reaches the signature step on a supported browser/device, When the fingerprint module initializes, Then it collects user agent, platform, screen metrics, timezone offset, locale, hardware concurrency, device memory, and entropy signals (canvas/WebGL if available) and normalizes them per spec without blocking the UI. Given network conditions of 3G or better, When collection runs on mobile devices in the 90th percentile, Then the fingerprint collection and normalization complete within 500ms. Given any unsupported attribute is unavailable, When collection occurs, Then the module degrades gracefully and still produces a fingerprint with a stability score and no errors shown to the signer. Given desktop Chrome/Firefox/Safari/Edge (last 2 versions) and iOS/Android Chrome/Safari (last 2 versions), When collection occurs, Then the output format and stability scoring are consistent across platforms.
Region-Aware Consent and Opt-In With Alternative Flow
Given the signer’s region is inferred (IP geo) and confirmed via self-declared residency, When the consent dialog is displayed, Then the copy uses the correct region template (GDPR/EU, CCPA/CPRA-CA, default Rest of World) and language and references what is collected and why. Given the consent dialog is shown, When the signer has not opted in, Then device fingerprint collection does not execute and the opt-in control is unchecked by default. Given the signer opts out or closes the consent dialog, When they continue, Then an accessible alternative signing flow is presented that completes without device fingerprint binding and records consent status as declined. Given consent is accepted or declined, When the signer proceeds, Then a consent record is stored with signer ID, session ID, timestamp, region, template version, language, action (accept/decline), and is linked to the audit trail. Given WCAG 2.1 AA requirements, When tested with keyboard and screen readers, Then the consent and alternative flow controls are fully operable and announced.
Storage Minimization and Hashing Controls
Given a fingerprint vector is produced, When persisting, Then only a salted hash of the vector and the stability score are stored; no raw attribute values are stored at rest. Given the hash is generated, When inspected, Then the salt is managed server-side via KMS/HSM and rotated per policy, and the hash algorithm is SHA-256 or stronger. Given system observability, When application and access logs are reviewed, Then no raw fingerprint attributes or unhashed vectors are present. Given data retention policy, When the retention threshold is reached or deletion is requested, Then fingerprint hashes and associated records are purged from primary stores within 7 days and from backups within 30 days, with audit logs updated. Given data at rest requirements, When storage is verified, Then the data is encrypted at rest and access is role-restricted and logged.
Audit Trail and Cryptographic Binding Linkage
Given a signing session is completed, When the evidence packet is generated, Then it includes the fingerprint_hash, stability_score, consent_status, consent_version, signer_id, session_id, timestamp, IP/geo region, and verification hash fields. Given the e-sign certificate, When inspected, Then it references the same session_id and includes a binding reference to the fingerprint_hash and consent record via immutable audit event IDs. Given the audit trail API, When queried by session_id, Then it returns the consent record, fingerprint binding record, and their timestamps in chronological order with a tamper-evident signature. Given the evidence packet, When independently verified, Then its signature validates and the packet is readable in PDF and machine-readable JSON formats.
Spoofing Resistance and Integrity Signals
Given a user attempts trivial spoofing by changing only the user agent string, When a new fingerprint is computed, Then it does not collide with the prior hash and the stability score reflects the change. Given mismatched platform indicators (e.g., iOS platform with non-iOS screen metrics), When evaluated, Then a risk flag is added to the audit event and the stability score is reduced per policy. Given execution in headless or known automation contexts, When detected, Then the audit event is flagged headless=true and the stability score is reduced; functionality proceeds without breaking the signing flow. Given repeated attempts within a 10-minute window, When the same device attempts to vary low-entropy attributes, Then the produced hashes remain consistent within a tolerance, or a low-stability warning is logged without storing raw values.
Data Subject Rights: Access, Export, and Deletion
Given a verified data subject request (DSR), When an access request is submitted, Then the system produces a human-readable and machine-readable export of consent records and fingerprint hash metadata within 7 days. Given a verified DSR, When a deletion request is submitted, Then associated fingerprint hashes, stability scores, and consent records are deleted from active systems within 7 days and from backups within 30 days, and a deletion confirmation receipt is generated. Given jurisdictional rules (EU/EEA vs CA), When responding to DSRs, Then response SLAs and disclosures meet or exceed GDPR (30 days) and CCPA/CPRA (45 days) requirements, with extensions documented where applicable. Given firm policy overrides, When retention is configured per tenant, Then exports and deletions honor tenant-specific retention windows while complying with applicable law.
No Third-Party Trackers and Telemetry Restrictions
Given the signature step is loaded, When network activity is inspected, Then no third-party scripts, pixels, or beacons are requested; all calls are to first-party allowlisted domains enforced by CSP. Given Content Security Policy, When headers are evaluated, Then CSP blocks inline scripts and disallows connections to non-allowlisted domains for script/img/connect directives at the signature step. Given a user has Do Not Track enabled, When the signature step is used, Then no analytics or telemetry outside essential operational logs are collected. Given privacy configuration, When consent is not granted, Then device fingerprinting code paths remain disabled and no entropy collection occurs, verified via runtime feature flags and network traces.
Trusted Timestamp & Geo Context
"As an attorney, I want trusted time and location context captured at signing so that I can establish where and when the signature occurred if it’s challenged."
Description

Attach an independently verifiable timestamp and contextual location to each signature event. Use RFC 3161 timestamp authority (TSA) tokens with NTP cross‑checks and clock‑skew detection; record local timezone/offset and DST status. Derive coarse geo from IP and allow optional GPS‑level precision with explicit consent; store uncertainty/confidence levels and note any conflicts (e.g., VPN indicators, ASN anomalies, impossible travel). Serialize these artifacts into the claims set for cryptographic binding and display them with clear caveats in the audit trail and evidence packet.

Acceptance Criteria
RFC3161 Timestamp Token Attached and Verifiable
Given a signature event is finalized When the event is recorded Then an RFC 3161-compliant timestamp token from the configured TSA is attached to the event And the token validates successfully against the TSA's public certificate chain And at least 3 independent NTP sources are queried and a median time is computed And the NTP median and the delta to the token time are recorded in the claims set And if the absolute delta is <= 2000 ms, no clock-skew flag is set
Clock Skew Cross-Check and Flagging
Given a signature event with a TSA token time and recorded NTP median When the absolute difference between token time and NTP median exceeds 2000 ms Then the event is flagged "Clock-Skew" And the measured delta in milliseconds and the list of NTP sources are recorded in the claims set And the audit trail and evidence packet display a caveat noting the skew and sources queried
Local Timezone and DST Capture
Given a signer completes a signature on any device When the event is recorded Then the local timezone identifier (IANA), UTC offset, and DST-in-effect flag at the event moment are captured And the timestamp is stored in RFC 3339 format with offset And these fields are stored in the claims set and displayed in the audit trail and evidence packet
Geo Derivation with Consentful Precision
Given a signer initiates a signature When IP-based geo lookup succeeds Then country, region, city, ASN, centroid latitude/longitude, and an uncertainty radius (km) are captured And when the signer explicitly consents to precise location collection Then GPS latitude/longitude and horizontal accuracy (meters) are captured and stored And when consent is declined or unavailable Then only IP-derived geo is stored and the audit trail and evidence packet note "precise location not collected" And all geo entries include a source label (IP or GPS) and confidence/uncertainty values
Network and Geo Conflict Indicators
Given IP-derived geo and network metadata are collected and GPS-derived geo may be present When VPN/proxy/Tor indicators or ASN-country mismatches are detected Then a "Network Anomaly" indicator with reason codes is added to the claims set and shown in the audit trail and evidence packet And when IP and GPS locations differ by more than 50 km (considering their uncertainty radii) Then a "Geo Conflict" indicator is added with both locations and their uncertainties
Impossible Travel Detection Across Events
Given two signature events by the same verified signer occur within a 24-hour window And both events include geo data with uncertainty When the minimum required travel speed between the most probable points exceeds 1000 km/h after accounting for uncertainties Then an "Impossible Travel" flag is recorded on the later event and shown in the audit trail and evidence packet And the computed distance, time delta, and minimum speed are stored in the claims set
Claims Serialization and Cryptographic Binding
Given a signature event is finalized When the claims set is generated Then it includes the TSA token, NTP sources and deltas, timezone, UTC offset, DST flag, geo data with source and uncertainty, consent record, anomaly/conflict flags, and version metadata And the claims set hash is included in the signature's signed attributes so any modification invalidates signature verification And an external verifier can extract and validate the claims and detect tampering using only the evidence packet and public trust roots
Court‑Ready Evidence Packet Generator
"As a solo attorney, I want a single downloadable packet that contains everything needed to prove the signer’s identity and the signature’s integrity so that I can respond to challenges quickly without extra work."
Description

Produce a single, court‑ready evidence bundle that packages the signed document, signature certificate, cryptographic binding envelope, full audit trail, KYC verification attestation hash, TSA token, and a human‑readable narrative. Output PDF/A‑3 with embedded machine‑readable JSON manifest and detached signatures, include certificate chains and validation instructions, and stamp a QR code linking to an online verification portal. Default to redacting sensitive PII while retaining necessary proofs; allow firm branding and matter metadata. Ensure compliance alignment with ESIGN, UETA, and eIDAS Advanced‑equivalent practices to strengthen admissibility and enforceability across jurisdictions.

Acceptance Criteria
PDF/A‑3 Evidence Packet Assembly
- System generates a single PDF/A-3 file that packages as Associated Files (AF): a) signed document (PDF), b) signature certificate/summary, c) cryptographic binding envelope, d) full audit trail (JSON + human-readable section), e) KYC verification attestation hash (no raw PII), f) RFC 3161 TSA token, g) human-readable narrative. - PDF passes veraPDF validation for PDF/A-3 with 0 errors and 0 warnings. - PDF embeds a machine-readable JSON manifest (AF, application/json) describing each artifact with: filename, mediaType, byteLength, sha256, role, and creationTime. - Detached signatures are embedded as CMS .p7s associated files and referenced in the JSON manifest. - Packet includes a “Validation Instructions” section that explains offline verification using the manifest and signatures.
Cryptographic Integrity, Chains, and Signature Validity
- All artifact hashes in the JSON manifest recompute to the listed sha256 values. - CMS signature validates as “Signed and all signatures are valid” in Adobe Acrobat/Reader and with OpenSSL/DSS library. - Signature includes an embedded RFC 3161 timestamp; token verifies against TSA certificate; signing time within ±2 seconds of the corresponding audit-trail event. - Intermediate certificate chain(s) up to a trusted root are embedded; revocation info (OCSP/CRL) embedded to enable LTV validation in Acrobat. - Cryptographic binding envelope includes the verification hash linking verified ID to the signature certificate; recomputation from KYC attestation materials yields the same hash.
QR Code Online Verification Portal Linkage
- Cover page contains a QR code and URL that resolve over HTTPS with HSTS, returning HTTP 200 within 2 seconds. - Scanning the QR on iOS and Android loads a verification summary that recomputes the packet hash and displays “Authentic” if unchanged; any byte modification yields “Tampered” with failing component details. - Portal displays only non-sensitive data (e.g., matter ID, signer initials, signing time) and never exposes raw PII; offers download of the JSON manifest. - Portal validates the embedded TSA token and digital signature and shows pass/fail consistent with offline validation. - QR payload contains no raw PII and grants access only to the referenced packet; link remains stable and accessible for at least 5 years per retention settings.
Default PII Redaction with Proof Preservation
- By default, narrative and audit trail redact SSNs, driver’s license numbers, passport numbers, full account numbers, and full DOB; last 4 digits or year may be shown where necessary. - JSON manifest stores only salted hashes for redacted fields; no raw PII present in the packet, manifest, or QR payload. - Admin can disable redaction per matter; packet displays a “Redaction Disabled” banner and records user, timestamp, and reason in the audit trail. - Automated tests verify that sample inputs containing PII result in redacted outputs; text search across PDF and embedded files yields zero matches of raw PII. - Redaction preserves all cryptographic evidence required to validate identity binding, signatures, and timestamps.
Firm Branding and Matter Metadata
- Branded cover page includes firm logo, firm name, and accent colors without breaking PDF/A-3 compliance (veraPDF passes with 0 errors). - Matter metadata (matter ID, client initials, case type, jurisdiction, file number) appears on the cover page and in PDF XMP and Info dictionary custom properties. - Branding assets are embedded with appropriate ICC profiles and do not introduce external dependencies. - Admin can toggle branding and edit metadata; changes are reflected in the generated packet and captured in the audit trail.
Audit Trail Completeness and Human-Readable Narrative
- Audit trail includes: invite sent, consent obtained, KYC start/completion result, MFA/OTP events, document viewed, signature applied, timestamping, and packet generation; each event includes ISO 8601 UTC timestamp, IP, device fingerprint, and geolocation (if available with accuracy meters). - Human-readable narrative summarizes identity verification, binding approach, and compliance mapping with clear section headings. - Timezone and locale are displayed as UTC and local time for signer and firm; formatting is consistent across sections. - Narrative and audit trail are selectable, searchable text (not images) and included as tagged content. - Event IDs in the audit trail cross-reference entries in the JSON manifest.
Cross-Jurisdiction Compliance Alignment (ESIGN, UETA, eIDAS Advanced-equivalent)
- Narrative includes a compliance statement mapping artifacts to ESIGN 101(c), UETA §§7–8, and eIDAS Advanced characteristics (unique link to signatory, sole control, data integrity, and identification). - Consent is recorded prior to signing with timestamp and IP; evidence appears in both audit trail and narrative. - Integrity controls ensure any post-signature modification is detectable; Acrobat shows document locked; portal flags tampering on any byte change. - Identification evidence includes KYC verification attestation hash, provider name, method, and reference ID. - Retention requirement met: packet is reproducible; PDF/A-3 validation passes; machine-verifiable manifest present; certificate chains and validation instructions included. - Compliance checklist page present with version and last legal review date.
Proof Viewer & Verification API
"As an attorney, I want to share and verify the evidence via a secure link or API so that courts and opposing counsel can validate the packet without accessing my internal systems."
Description

Provide a secure, read‑only viewer inside Briefly to inspect the bound evidence (timeline, KYC status, device hash, TSA token, geo context) with automatic redaction and role‑based access. Offer one‑click export (ZIP) of the packet and a public verification API/portal that accepts the packet or QR code and returns a signed verification result (valid/invalid, reasons, artifacts). Implement expiring, tamper‑proof share links, rate limiting, audit logging, and no‑PII responses for public calls. Publish public keys and revocation lists to enable third‑party/offline validation. Integrate with matter records to track when and by whom a packet was viewed or shared.

Acceptance Criteria
Secure Read-Only Evidence Viewer (Role-Based with Auto-Redaction)
- Given an authenticated user with role Attorney and active matter access, when opening the Evidence Viewer, then the timeline, KYC status, device fingerprint hash (SHA-256), TSA token details, geo context, and verification hash are displayed and no edit/modify controls are rendered. - Given any user, when attempting a POST/PUT/PATCH/DELETE to evidence endpoints, then the request is rejected with 403 or 405 and no state changes occur. - Given a user with role Attorney, when viewing, then PII fields (name, email, phone, address, DOB, government ID) are visible; device fingerprint is shown only as a hash; precise GPS (≤50m) is visible. - Given a user with role Staff, when viewing, then PII is automatically redacted (names → initials, emails/phones masked, government IDs last 4 only); device fingerprint shown as hash; geo reduced to city/region. - Given a user with role External Viewer (via share link), when viewing, then no PII fields are displayed and geo is generalized to state/province; only hashes, timestamps, and event types are shown. - Given the viewer is loaded for a packet ≤5 MB, when rendering on a broadband connection (≥10 Mbps), then initial content appears within 2 seconds in 95% of trials. - Given accessibility requirements, when tabbing through the viewer, then all controls are reachable and labeled (ARIA) and key evidence values are readable by screen readers.
One-Click Court-Ready Evidence Packet Export (ZIP)
- Given a user with ExportEvidence permission (Attorney or Admin), when clicking Export, then a ZIP downloads without additional prompts. - Then the ZIP contains at minimum: manifest.json, evidence.json, auditTrail.csv, artifacts/ (event artifacts), signature.sig, cert-chain.pem, readme.txt, and qrcode.png. - Then manifest.json lists every file path with SHA-256 checksums, byte sizes, MIME types, and a packetVersion; the ZIP root includes packetId and createdAt ISO-8601 in readme.txt and filename. - Given the exported ZIP, when validated by the public portal, then the packetHash in the verification result matches the manifest aggregate hash; altering any file produces an invalid result with reason hash_mismatch. - Given a packet ≤50 MB, when exporting, then generation completes within 5 seconds in 95% of trials and the server streams the file with Content-Disposition attachment and checksum header (Digest: sha-256=...). - Given role External Viewer, when exporting is attempted, then the Export action is not visible and direct calls return 403.
Public Verification Portal/API (Packet or QR) Returns Signed Result
- Given a valid evidence ZIP upload, when POSTing to /verify or uploading via the portal UI, then the response is 200 with JSON: {status: valid|invalid, reasons:[], packetHash, notBefore, notAfter, keyId, signature, artifacts:{counts, types}} and no PII fields. - Given a QR code generated by Briefly, when scanned, then the portal resolves to the verification page, accepts the embedded reference or packet, and shows the signed result with a visible signature badge linked to keyId details. - Given a corrupted or tampered packet, when submitted, then status is invalid with reasons including hash_mismatch or signature_invalid and HTTP 200. - Given a packet signed with a revoked key, when submitted, then status is invalid with reason key_revoked. - Given successful verification, when the result is downloaded, then the result JSON is itself signed (JWS/COSE) with Briefly’s private key and includes keyId matching the current JWKS entry. - Given an unsupported file, when submitted, then the API returns 400 with reasons including unsupported_format and a JSON schema error path list.
Expiring Tamper-Proof Share Links (Scoped External Access)
- Given a user with ShareEvidence permission, when generating a share link with TTL (default 7 days) and scope External Viewer, then the system returns a URL containing a signed token (kid, exp, scope, packetId) that cannot be altered without invalidation. - Given the share link is accessed before exp, when opened, then the redacted External Viewer loads and the access is logged; after exp, the endpoint returns 410 Gone. - Given any modification to query parameters or token claims, when requesting, then the system returns 403 signature_invalid and no evidence is rendered. - Given a user revokes a link, when the revoked link is accessed, then the system returns 410 revoked and the event is logged. - Given single-use is enabled, when the link is first accessed, then subsequent requests return 410 used. - Given rate limits for shared links, when more than 10 requests are made from the same IP within 1 minute, then subsequent requests receive 429 with Retry-After.
Rate Limiting and No-PII for Public Verification Endpoints
- Given anonymous access to /verify and /keys, when requests exceed 60 requests per minute per IP or 10 requests per minute per token, then the API returns 429 with Retry-After and X-RateLimit-* headers; limits are configurable. - Given a successful or failed verification, when inspecting the HTTP response body and headers, then no PII fields (names, emails, phone numbers, addresses, DOB, government IDs, device identifiers, precise geo) are present; only hashes, timestamps, and non-identifying metadata are returned. - Given a request includes a packet containing PII in embedded metadata, when generating the public response, then PII is omitted or replaced with stable hashes and redaction indicators. - Given content negotiation, when requesting with Accept: application/json, then the API returns application/json; HTML UI contains the same non-PII constraints. - Given repeated abuse from an IP, when exceeding limits for 10 consecutive minutes, then the IP is temporarily blocked for 60 minutes and unblocked automatically; this action is logged.
Audit Logging and Matter Record Integration
- Given any evidence packet view, export, share creation/revocation, or public verification, when the action occurs, then an audit event is recorded with timestamp (UTC), actorId or public, actorRole, action, packetId/hash, shareLinkId (if applicable), clientIp (truncated or hashed), userAgent hash, and outcome. - Given audit events are recorded, when viewing the matter’s timeline, then these events appear in chronological order with filters by action and actor; clicking an event shows details and correlates to the packet. - Given data integrity requirements, when attempting to alter or delete audit events via API/UI, then the request is denied (403) and a tamper attempt is logged; events are append-only with immutable digests. - Given export compliance, when exporting matter activity, then audit events can be exported as CSV and JSON with SHA-256 chain hash for integrity verification. - Given time synchronization, when events are created, then timestamps are signed with TSA token references stored in the event metadata.
Public Keys and Revocation Lists for Third-Party/Offline Validation
- Given a request to /.well-known/jwks.json, when fetching, then a JWKS is returned with current public keys (keyId, alg, use, x5c or crv) signed by a root key; keys include notBefore/notAfter and rotation policy documented. - Given a request to /.well-known/briefly/revocations.json, when fetching, then a signed revocation list is returned including revoked keyIds and packetIds with reasons and timestamps. - Given offline validation, when using the published keys and revocation list to verify a packet and result JSON without network access, then signatures validate and revocations are enforceable per the last retrieved lists; documentation includes step-by-step procedure and test vectors. - Given a key is rotated, when verifying old packets, then valid signatures with non-revoked, time-valid keys continue to verify; new results reference the new keyId. - Given integrity requirements, when JWKS or revocation list signatures do not validate, then clients reject them and log integrity_error.

Encrypted ID Vault

Stores ID images and verification reports with end‑to‑end encryption, role‑based access, and automatic retention rules (e.g., redact image, keep attestation). Just‑in‑time decryption with access logs satisfies strict PII policies while keeping proof available when needed.

Requirements

Client-side E2E Encryption & Key Management
"As a solo consumer-law attorney, I want IDs encrypted end-to-end with my own keys so that client PII is protected and compliant even if servers are compromised."
Description

Implement end-to-end encryption for ID images and verification reports with encryption performed on the client prior to upload, ensuring servers store ciphertext only. Use per-tenant, per-matter data encryption keys derived from a master key with automatic rotation and revocation. Support BYOK/HYOK via external KMS/HSM, enforce TLS 1.3 in transit, and isolate keys by environment and region for data residency. Decryption occurs only within an authorized, ephemeral client session; plaintext never persists to disk on server or device caches. Provide SDKs for mobile/web capture that handle key negotiation, chunked encrypted upload, and network retry. Integrate with Briefly’s intake flow and document assembly pipeline so encrypted artifacts remain linkable to matters without exposing content.

Acceptance Criteria
Client-Side Encryption Before Upload
Given a captured ID image or verification report in the SDK When the user submits the capture Then the SDK encrypts the payload on-device prior to any network transmission And network inspection shows only ciphertext payloads (no plaintext bytes match the original file signature) And the server stores only ciphertext objects; direct retrieval of stored bytes reveals no readable metadata or image content And decryption of the stored object fails without the corresponding per-matter DEK And the upload is rejected if the local encryption step is bypassed or fails, with a non-retryable error code
Per-Tenant, Per-Matter Key Derivation and Isolation
Given master key material is configured for a tenant When deriving a DEK for matter X in tenant A within region R and environment E Then the derived DEK is unique to A/X/R/E and cannot decrypt artifacts from any other tenant/matter/region/environment And deriving the DEK for the same A/X/R/E is deterministic and yields the same key identifier without exposing key material And DEK metadata includes tenant_id, matter_id, region, environment, and rotation version And attempts to decrypt tenant B or matter Y objects with the A/X DEK fail with an audited denial And raw master key material is never transmitted to the client or persisted on Briefly servers outside the KMS/HSM boundary
Key Rotation and Revocation
Given encrypted artifacts exist under rotation version N When a rotation to version N+1 is initiated for tenant A in region R Then new uploads use version N+1 DEKs within 5 minutes of rotation initiation And existing artifacts encrypted under version N remain decryptable by authorized sessions for 90 days (configurable) unless explicitly revoked And revocation of version N blocks new decryptions within 60 seconds while preserving ciphertext for audit/retention And audit logs include timestamp, tenant, scope (matter if applicable), previous and new version, actor, and outcome And the SDK returns a retriable error with code BRF-EKEY-REVOKED for decryptions blocked by revocation
BYOK/HYOK via External KMS/HSM
Given a tenant has registered an external KMS/HSM key in region R with wrap/unwrap permissions When the SDK requests key material for encrypting/decrypting an artifact Then DEKs are wrapped/unwrapped via the external KMS/HSM, and unwrapped DEKs exist only in client volatile memory And no plaintext KEK or master key material is present on Briefly servers or written to logs And if the external KMS is unreachable, operations fail closed with no fallback to Briefly-managed keys and a clear error code And audit entries record the external key identifier, KMS request ID, operation type (wrap/unwrap), and success/failure
Ephemeral Client Decryption and No Plaintext Persistence
Given an authorized user opens an encrypted artifact linked to a matter When the client performs decryption Then plaintext resides only in volatile memory and is zeroized within 1 second after the viewer closes or the session expires And the app does not write plaintext to disk, OS galleries, cache directories, or web storage (LocalStorage/IndexedDB) And a simulated app crash or device reboot leaves no recoverable plaintext on the device And the server does not receive or log plaintext during viewing And decryption is denied if the session lacks required role scopes or if device attestation fails
SDK Upload: Key Negotiation, Chunked Encryption, Retry, and TLS 1.3
Given a 60 MB ID image is captured on a spotty mobile network When the SDK uploads the artifact Then the SDK negotiates keys successfully and transmits only over TLS 1.3; TLS 1.2 handshake attempts are rejected And the payload is encrypted and authenticated per chunk with integrity tags; the server validates chunk order and tags And a 30-second network outage causes resume from the last confirmed chunk without duplication And the upload completes within 2x the measured baseline throughput with at most 3 retries per failed chunk And end-to-end integrity verification passes; the stored object digest matches the client-computed digest
Secure Integration with Intake Flow and Document Assembly Without Content Exposure
Given an intake flow captures ID images and verification reports for a new matter When the matter is created and documents are assembled Then encrypted artifacts are linked via opaque IDs and metadata only; assembly workflows never access plaintext on the server And rendering that requires content occurs client-side post-decryption under authorization constraints And users without required scopes see placeholders and cannot retrieve or decrypt content And all access attempts and decrypt operations are logged with user, matter, artifact ID, timestamp, and success/failure And retention actions allow redaction of images while retaining attestations and audit logs per policy
Least-Privilege RBAC & Time-Bound Access
"As a firm admin, I want granular, time-limited permissions per matter so that only authorized staff can view client IDs when necessary."
Description

Provide role-based access control with least-privilege defaults and granular permissions for upload, view (decrypt), export, and policy administration. Define firm-wide roles (Attorney, Intake Paralegal, Admin, Compliance) and matter-scoped access lists with optional supervisor approval for sensitive actions. Support SSO (SAML/OIDC) and MFA enforcement, plus time-bound access grants that auto-expire after a configurable window. Enforce authorization checks at API, storage, and UI layers with centralized policy evaluation and audit of allow/deny decisions. Integrate with Briefly user/matter models to ensure access aligns with assignments and case status.

Acceptance Criteria
Default Least-Privilege Roles Provisioned
Given a new firm enables Encrypted ID Vault When default RBAC roles are created Then the roles Attorney, Intake Paralegal, Admin, and Compliance exist And only Admin has policy administration by default And only Compliance has export by default And Attorney has view (decrypt) and upload only on assigned matters by default And Intake Paralegal has upload only on assigned matters by default
Granular Permissions Enforced for Upload, View, Export, Policy Admin
Given a user assigned to a matter without export permission When they attempt to export ID artifacts Then the API and UI deny with 403 and no decryption occurs And an audit entry records the deny with user, matter, action, and policy decision ID Given the same user is granted export permission When they export within the UI Then a decrypted export is delivered And an audit entry records the allow with policy decision ID And the permission change takes effect within 60 seconds across API, storage, and UI
Matter-Scoped Access Lists with Optional Supervisor Approval
Given a matter configured to require supervisor approval for export And a user with export permission requests an export When a supervisor approves within 15 minutes Then a one-time export link is issued and expires after 10 minutes or first use And the audit log records request, approval, and fulfillment with timestamps When approval is rejected or times out Then the export is denied with 403 and a deny audit entry is recorded And no decrypted artifact leaves storage
SSO (SAML/OIDC) and MFA Enforcement
Given SSO via SAML or OIDC is enabled and MFA is enforced When a user attempts password-based login Then access is denied and the user is redirected to the IdP When the IdP assertion lacks an MFA/AMR claim per policy Then login is denied and an audit entry captures the failure reason When the assertion is valid with MFA and mapped roles Then the user is authenticated and RBAC roles are applied
Time-Bound Access Grants Auto-Expire
Given a user not on a matter’s access list is granted view (decrypt) for 2 hours When the user accesses ID artifacts within 2 hours Then access is allowed and audited as a time-bound grant When 2 hours elapse Then subsequent access attempts are denied with 403 without admin action And the grant auto-removes from the access list When the grant is manually revoked before expiry Then access is immediately denied within 60 seconds across API, storage, and UI
Cross-Layer Authorization with Centralized Policy and Audit
Given centralized policy evaluation is active When a user without permission calls the API to retrieve an ID image Then the response is 403 with a policy decision ID and no content bytes returned When the same user attempts direct object access via a pre-signed URL Then the URL is not issued and storage access is denied When the user gains permission Then UI controls render, API returns 200, storage access is mediated with just-in-time decryption And all allow/deny decisions are logged with user, matter, action, resource, decision, and reason
Access Aligns with Assignments and Case Status
Given a user is added to a matter as Attorney When they navigate to the matter’s ID Vault Then upload and view (decrypt) are allowed; export and policy admin are denied When the user is removed from the matter or the matter is closed Then all access to the matter’s ID Vault is revoked within 60 seconds When the matter is reopened and the user is re-assigned Then prior permissions are restored according to role and policy And all assignment-driven access changes are captured in the audit log
Just-in-Time Decryption Viewer
"As an attorney, I want to temporarily view an ID in a secure viewer so that I can verify identity without creating extra copies."
Description

Offer a secure in-app viewer that performs on-demand, session-scoped decryption without creating downloadable files by default. Enforce policy-driven controls: watermarking with user/time/matter, disable copy/print/download, automatic re-lock on idle, and session expiration. Require justification prompts and optional dual-approval for decryption of high-risk documents. Ensure plaintext exists only in protected memory and is wiped on close or session timeout. Provide accessibility and mobile-friendly rendering for quick identity checks during intake calls. Log every open, page view, and action to the audit trail.

Acceptance Criteria
On-Demand In-App Viewing Without Download
Given an authenticated user with Viewer or higher role is on a Matter and selects an ID document to view When they click View Then the document is decrypted just-in-time and rendered in the in-app viewer within the same tab And no file is written to localStorage, sessionStorage, IndexedDB, Cache Storage, or the device downloads folder And the HTTP response for the content stream omits Content-Disposition: attachment and enforces a Content-Security-Policy that disallows downloads And the viewer loads in ≤2 seconds for documents ≤5 MB over 4G or faster networks And the viewer is responsive for ≥320px width viewports, supports pinch-to-zoom, and is fully keyboard navigable And all controls expose accessible names/roles/states and meet WCAG 2.2 AA focus and color-contrast requirements
Policy Watermarking With User/Time/Matter
Given policy watermarking is enabled When any page of the decrypted document is displayed Then a dynamic watermark overlays each page with the authenticated user's display name, UTC timestamp (ISO 8601), Matter ID, and Client Initials And the watermark includes the active session ID truncated to 8 characters And the watermark opacity is between 10% and 20% and repeats diagonally at least every 200 pixels And users cannot disable or alter the watermark via UI or query parameters And the watermark text updates if the user changes due to re-auth within the session
Copy/Print/Download Restrictions Enforcement
Given a decrypted document is open in the viewer When the user attempts to copy text, print, save, or download Then the actions are blocked by the application and browser controls are suppressed (context menu disabled in viewer area, Ctrl/Cmd+C and Ctrl/Cmd+P prevented) And no system print dialog appears and no print-to-PDF is produced And no direct file URL is exposed; any presigned URL requires an active session token and expires in ≤60 seconds And all blocked attempts are logged with action type and reason And a persistent, non-intrusive banner indicates that copying, printing, and downloading are disabled and monitored
Idle Auto Re-Lock and Session Expiration
Given a decrypted document is open in the viewer When the user is idle (no mouse, keyboard, touch, or scroll) for the policy-defined interval (default 2 minutes) Then the viewer locks and hides the plaintext, requiring re-authentication to continue And when the session reaches the absolute timeout (default 15 minutes from open) or the tab/window is closed, the session expires And upon lock or expiration, the plaintext buffer is wiped and a lock screen is displayed within 500 ms And re-entry requires an active SSO session or MFA per policy; otherwise access is denied and logged
Justification and Dual Approval for High-Risk Documents
Given a document is tagged High-Risk by policy When a user initiates viewing Then a modal requires selecting a justification from a policy-defined list and entering free text between 5 and 200 characters And, if dual approval is enabled, an approver distinct from the requester must approve within 10 minutes before decryption proceeds And if approval is rejected or times out, the view does not decrypt and the attempt is logged with requester, approver, reason, and outcome And the approver action link is single-use and expires in 10 minutes
Protected Memory Handling and Secure Wipe
Given the viewer is rendering decrypted content Then plaintext is held only in volatile memory and is never intentionally written to persistent storage (disk, localStorage, sessionStorage, IndexedDB, Cache Storage) And when the viewer is closed, locked, or the session expires, plaintext buffers are zeroed and references released And within 5 seconds of close/lock/expire, process memory attributable to the document returns to within 10% of pre-open baseline And refreshing the page does not rehydrate the viewer without a new decryption step
Comprehensive Audit Logging of Viewer Activity
Given any action occurs in the viewer When an open, page view, page navigation, zoom, search, blocked copy/print/download attempt, lock, unlock, approval request, or approval decision happens Then an audit log entry is recorded with: user ID, role, matter ID, document ID, session ID, action type, page number (if applicable), UTC timestamp, IP address, user agent, and outcome (allowed/blocked) And entries are immutable, queryable within 60 seconds, and retained per policy And exports to CSV include the same fields with field-level PII redaction where configured And gaps in sequence are detectable via monotonically increasing sequence IDs
Automated Retention & Redaction Policies
"As a compliance officer, I want automated retention and redaction so that we minimize stored PII while keeping proof available for audits."
Description

Build a policy engine to automatically redact or delete raw ID images after configurable events (e.g., 30 days post-engagement) while retaining verification attestations, hashes, and minimal metadata for compliance. Support matter status triggers, legal holds, policy versioning, and backfill on policy changes. Perform irreversible server-side redaction with cryptographic proof of alteration and preserve linkage to documents assembled in Briefly. Provide region-aware schedules and exceptions, plus admin dashboards for policy configuration and upcoming deletions. Expose APIs and UI to preview impact before enforcement.

Acceptance Criteria
30-Day Post-Engagement Redaction
Given a retention policy P1 configured to redact raw ID images 30 days after matter engagement and a matter M with engagement_date D0, region R without exceptions, and no legal hold When the retention processor runs at or after D0 + 30 days Then each associated raw ID image is replaced with a server-side redacted version and the original bytes are irrecoverably destroyed And a signed cryptographic alteration record is stored containing original SHA-256 hash, redacted SHA-256 hash, timestamp, policy version, and processor ID And the retention audit log records an entry with matter ID, policy ID, action=redact, count of images processed, and success status And metrics expose the number of images redacted for P1 during the run
Preserve Linkage and Minimal Retained Artifacts After Redaction
Given a matter has assembled documents that reference ID images and a verification attestation A with stored hashes and minimal metadata When redaction occurs under policy P1 Then attestation A, original content hash, verification result, document type, issuer, and timestamps remain retrievable via API /attestations/{id} And assembled documents remain accessible with placeholders for redacted images and no broken links And attempts to retrieve raw image bytes via any API return 410 Gone with reason=redacted And the retained metadata conforms to the minimal schema and contains no disallowed PII fields
Legal Hold Supersedes Retention Actions
Given a matter M in scope of policy P1 with a scheduled redaction date D and an active legal hold H applied before processing When the retention processor runs on or after D Then no redaction or deletion is performed on assets covered by H And the audit log records action=skipped_due_to_legal_hold with references to H and P1 And when H is released, the next scheduled run processes the deferred actions and records action=processed_after_hold with the applied policy version
Policy Versioning With Automatic Backfill
Given policy P1 v1.0 is active and P1 v1.1 changes the redaction schedule from 30 to 14 days When an admin publishes P1 v1.1 Then the system computes the delta of items newly in-scope under v1.1 and enqueues backfill tasks within 15 minutes And items already processed under v1.0 are not reprocessed And audit entries for backfill include applied_policy_version=v1.1 and backfill_run_id And API GET /policies/{id}/backfills/{runId} returns counts by action, successes, and errors
Region-Aware Schedules and Exception Tags
Given a policy defines schedules EU=14 days and US=30 days and an exception tag retain_longer=60 days And two matters M_EU (region=EU) and M_US1 (region=US, no exception) and M_US2 (region=US, tag=retain_longer) share engagement_date D0 When the retention processor runs daily Then M_EU images are redacted on or before D0 + 14 days And M_US1 images are redacted on or before D0 + 30 days And M_US2 images are redacted on or before D0 + 60 days And audit entries include region and exception rationale for each action
Admin Dashboard for Policy Configuration and Upcoming Deletions
Given an admin with permission policy_admin opens the ID Vault retention settings When they create or edit a policy with name, scope, schedules, region rules, exception tags, and legal-hold behavior and click Save Then client-side and server-side validation reject invalid inputs (e.g., negative days, overlapping scopes) with field-level errors And on success, the new or updated policy appears in the policies list within 10 seconds with incremented version and status=Active And the Upcoming Deletions view shows a 30-day forecast with counts by day, region, and action that match API GET /retention/upcoming within ±1% And all admin actions are recorded in the admin audit log with before/after diffs
Impact Preview API/UI Before Enforcement
Given a draft or active policy P and a reference date D When the user requests a preview via UI or POST /retention/preview with policyId and date D Then the response includes deterministic counts and item IDs per action (redact, delete) without performing any data changes And repeated identical requests return identical results unless underlying data changes And the response includes inclusion/exclusion reasons (policy rule, region, exception, legal hold) And promoting a preview to an execution plan requires explicit confirmation and permission policy_admin
Tamper-Evident Audit Trail
"As a managing attorney, I want a tamper-evident audit log so that I can prove who accessed which IDs and when."
Description

Capture immutable, append-only logs for all sensitive events: upload, key issuance, decrypt requests, viewer opens, exports, policy changes, and admin overrides. Chain entries with cryptographic hashes and store in WORM-capable storage with periodic anchored checkpoints. Provide searchable dashboards, exportable reports, and per-matter access history suitable for regulator or court submission. Emit alerts for anomalous patterns (e.g., bulk views after hours), with integrations to SIEM via webhook or log streaming. Ensure every audit entry includes user, role, matter, device, IP, reason code, and policy snapshot at decision time.

Acceptance Criteria
Append-Only Event Logging
- Given a sensitive event type (upload, key issuance, decrypt request, viewer open, export, policy change, admin override), When the event occurs, Then exactly one log entry is written within 2 seconds and assigned a monotonically increasing sequence number. - Given an existing log entry, When any actor attempts to modify or delete it via API, UI, or storage, Then the operation is blocked (HTTP 405/403), no data is changed, and a "tamper-attempt" event is logged. - Given the audit store, When queried for write operations, Then only create/append operations are exposed; no update/delete operations exist in interfaces. - Given a transient failure, When a write fails, Then it is retried with exponential backoff for up to 3 minutes without creating duplicate entries.
Hash-Chained Log with Anchored Checkpoints
- Given any new log entry N, When it is persisted, Then it includes prev_hash equal to the SHA-256 hash of entry N-1 and entry_hash equal to the SHA-256 of its canonical payload. - Given a contiguous block of entries, When the hash chain is recomputed, Then all hashes validate end-to-end and any alteration causes validation to fail with the first offending index identified. - Given normal operation, When 15 minutes elapse or 10,000 entries accumulate (whichever comes first), Then a checkpoint digest of the current head is written to WORM storage and its identifier recorded in the log. - Given a checkpoint, When an auditor verifies it, Then the checkpoint digest matches the independently recomputed head and includes an RFC3339 timestamp and signer identity.
WORM Storage Enforcement
- Given a configured retention policy, When an entry is written, Then it is stored on WORM-capable media and cannot be deleted or altered before expiry. - Given an early deletion request, When a user or process attempts deletion prior to expiry, Then the system denies the request, returns an error, and logs the denial with reason and requester identity. - Given retention expiry, When the purge job runs, Then entries reaching end-of-retention are purged and a signed deletion manifest (ranges, counts, checkpoint reference) is appended to the audit trail. - Given tenant-level settings, When retention is configured per tenant or matter, Then the enforced period matches the configuration visible in settings and in the policy snapshot for each entry.
Complete Audit Entry Metadata
- Given any sensitive event, When the audit entry is created, Then it includes: user_id (or service principal), role, matter_id, device_fingerprint, ip_address, reason_code (from configured list), policy_snapshot_id, and policy_snapshot_hash captured at decision time. - Given an entry missing any required field, When validation runs, Then the write is rejected with HTTP 400 and field-level errors; no partial entry is persisted. - Given a policy change between request and decision, When the entry is written, Then the policy snapshot reflects the policy at decision time, not the current policy, and is immutable.
Search and Per-Matter History
- Given the audit dashboard, When a user filters by matter, user, event type, time range, IP, or reason code, Then results include all matching entries and exclude non-matching entries. - Given a dataset of up to 1,000,000 entries, When a filtered query is executed, Then the first page returns within 3 seconds and supports stable pagination with a cursor. - Given a matter detail view, When opened, Then a chronological timeline of that matter’s events is displayed with local timezone rendering and an option to toggle UTC. - Given export of search results, When CSV export is requested, Then the file includes only the filtered results, has headers, and preserves timestamps in ISO 8601.
Regulator-Ready Report Export
- Given a matter, When a report is generated, Then produce a digitally signed PDF and a CSV containing: ordered events, required metadata fields, hash-chain validation summary, and checkpoint references. - Given the report, When verified offline, Then the embedded digital signature validates against Briefly’s public certificate and the hash-chain proof recomputes successfully. - Given PII handling rules, When the report is created, Then ID images are not embedded by default; only content-addressed references (hash, pointer) are included unless policy explicitly permits embedding. - Given localization needs, When reports are generated, Then timestamps are ISO 8601, numbers/addresses are locale-safe, and a legend page defines fields and reason codes.
Anomaly Detection and SIEM Streaming
- Given anomaly rules (e.g., >50 views by one user between 19:00–07:00 local), When a rule condition is met, Then an alert is created within 60 seconds containing actor, counts, time window, affected matters, and investigation links. - Given alert destinations, When email, webhook, and SIEM are configured, Then alerts are delivered to each; webhooks use HMAC-SHA256 signatures, retries with exponential backoff (up to 5 attempts), and idempotency keys to avoid duplicates. - Given SIEM streaming is enabled, When logs are produced, Then events are streamed as JSON Lines over HTTPS with at-least-once delivery and include tenant_id, event_id, event_type, and checkpoint_id where applicable. - Given alert lifecycle, When an alert is acknowledged or closed, Then the action is recorded in the audit trail with user, role, timestamp, and reason.
Verification Integrations & Attestation Linking
"As an intake paralegal, I want verification results linked to the matter so that I can see pass/fail and reasons without handling raw IDs."
Description

Integrate with third-party identity verification providers to ingest signed verification results, images, and metadata via secure webhooks. Verify provider signatures, normalize result schemas, and store attestations and decision reasons separately from redacted images. Link each verification to its Briefly matter, client, and retainer documents, surfacing pass/fail status and confidence to users without exposing raw PII unless authorized. Provide retries, dead-letter queues, and monitoring for webhook reliability. Support provider-agnostic mapping to enable switching vendors without data loss.

Acceptance Criteria
Signed Webhook Ingestion and Canonical Mapping
- Given a valid provider webhook with a verifiable signature (HMAC or public-key per provider spec) and required headers, When the event is POSTed to the configured webhook endpoint, Then the signature is validated against the stored credential and a 200 OK is returned within 2 seconds. - Given a webhook with an invalid/missing signature or a timestamp outside the accepted skew (±5 minutes), When received, Then the event is rejected with 401/403, no data is persisted, and the attempt is audit-logged with reason. - Given a duplicate delivery of the same provider event_id, When processed, Then handling is idempotent (no duplicate verification records or links) and a 200 OK is returned. - Given an accepted event payload from any supported provider, When processed, Then it is normalized to the canonical schema fields {provider, event_id, verification_id, subject_external_id, decision(pass|fail), confidence(0–1), decision_reasons[], created_at, artifacts{report, images[]}}; validation failures route the event to the DLQ with a structured error reason.
Attestation and Media Separation with Redaction
- Given a successful verification ingestion, Then the attestation record (provider signature/headers hash, decision, confidence, decision reasons, timestamps, canonical payload hash) is stored in an Attestations store separate from Media blobs; cross-referenced by immutable verification_id. - Given an org retention policy set to "redact images after 30 days, keep attestation", When a verification reaches 30 days, Then all associated image/media blobs are irreversibly deleted or replaced with redacted placeholders, while the attestation remains queryable. - Given media has been redacted, When a user without restore privileges attempts to access images, Then the system returns 404 or a redacted placeholder and the UI indicates "Images redacted per policy". - Given an attestation is exported, Then the export includes the canonical payload hash, provider signature metadata, and verification_id sufficient to prove provenance without containing raw PII.
Matter/Client/Retainer Linking and Status Surfacing
- Given an ingested verification carrying subject_external_id and a Briefly matter_id mapped to that subject, When processing completes, Then the verification record is linked to the corresponding Client and Matter and is referenceable by retainer document generation. - Given a user opens the Matter Overview, When the verification exists, Then the UI displays decision (pass/fail), confidence score/band, and decision reasons within 1 second without loading or rendering any raw PII assets. - Given retainer document assembly, When placeholders for identity attestation are present, Then the generated document includes attestation fields (decision, timestamp, provider, hash) but excludes images unless PII_VIEW permission is present at generation time. - Given the linked Matter/Client is merged or reassigned, When the merge completes, Then the verification links update to the new canonical Client/Matter without data loss.
Just-in-Time Decryption and Access Logging
- Given a user with PII_VIEW permission requests to view an ID image for a linked verification, When they click "Reveal ID", Then the media is decrypted just-in-time, transmitted over TLS, and p95 time-to-first-byte is ≤300 ms; an access log entry is created with user_id, matter_id, verification_id, timestamp, action=view, purpose-of-use. - Given a user without PII_VIEW permission requests the same, Then the system returns 403, no decryption occurs, and an access-denied audit entry is recorded. - Given an access log entry is created, When the Audit page is queried, Then the entry appears within 60 seconds and is filterable by matter_id and user_id. - Given the same authorized user attempts bulk export, Then only attestation data is included unless PII_EXPORT permission is granted, and all exported items are individually audit-logged.
Webhook Reliability, Retries, Idempotency, DLQ, Monitoring
- Given a transient internal processing error occurs during webhook handling, Then the event is retried with exponential backoff up to 5 attempts; if still failing, it is moved to a DLQ with error reason and correlation id. - Given a provider retries delivery of the same event, When received, Then the system recognizes the event_id and processes idempotently without duplicate side effects. - Given messages accumulate in the DLQ, When DLQ depth exceeds 50 or 5-minute failure rate exceeds 2%, Then an alert is sent to on-call and the Monitoring dashboard shows current metrics (success rate, error rate, DLQ depth, p95 latency). - Given an operator selects a DLQ item and clicks "Replay", Then the event is reprocessed and success/failure is reflected in metrics and logs.
Provider-Agnostic Canonical Schema and Vendor Switch
- Given canonical mapping definitions exist for Provider A and Provider B, When Provider B is enabled and set as default, Then new verifications ingest via Provider B map into the same canonical fields without requiring database schema changes. - Given existing verifications from Provider A, When Provider B is enabled, Then historical records remain accessible via the same read API and UI components without migration steps by end users. - Given an export request for verifications over a date range spanning both providers, Then the export returns a unified canonical JSON/CSV with provider-specific metadata nested but optional, and all required canonical fields populated. - Given a new provider is added, When mapping tests run, Then 100% of required fields are populated and unit tests for decision/confidence normalization pass.
PII Minimization in Surfaces and Transport
- Given a user role without PII_VIEW permission, When viewing Matter, Client, API responses, and network traffic, Then no raw PII (images, DOB, document numbers) is present; only opaque references, redacted placeholders, or hashes are exposed. - Given a privileged user reveals PII, Then the UI requires a purpose-of-use confirmation and enforces time-boxed access (auto-hide after 5 minutes); all reveals are audit-logged and attributable. - Given API clients request verification details without PII scope, Then the API omits PII fields and returns only attestation fields; attempts to include PII fields return 403. - Given feature flag "restrict_pii_globally" is enabled, Then all PII viewing endpoints return 403 for all users except system administrators, and this state is reflected in health/feature diagnostics.
Secure Export & Subpoena Package
"As a records clerk, I want a controlled export package so that we can respond to subpoenas quickly without exposing unnecessary PII."
Description

Provide a guided export workflow that assembles the minimum necessary artifacts for court or subpoena response. Apply policy-driven redactions, include an inventory manifest with cryptographic hashes and audit stamps, and package as a signed archive. Gate exports behind role- and matter-scoped permissions, justification capture, optional approval, and OTP-protected, expiring download links. Watermark all rendered documents and log every access of the package. Offer templates for common jurisdictions and include a machine-readable chain-of-custody file for verification by opposing counsel or regulators.

Acceptance Criteria
Role- and Matter-Scoped Export Authorization
Given a user without Export permission for the specific matter When they attempt to access the Secure Export workflow Then access is denied with a clear message and an audit log entry is created Given a user with Export permission scoped to the specific matter When they open the Secure Export workflow Then the workflow loads and is scoped only to that matter with no cross-matter selection available Given a user with global Export permission but without assignment to the matter When they attempt to export from that matter Then access is denied and the attempt is logged
Justification Capture and Optional Approval
Given a firm policy that requires justification for exports When a user initiates an export Then the workflow requires entry of reason, recipient, legal basis, and intended use before proceeding Given a policy that requires approval for this export type or jurisdiction When the user submits the export request Then the request is routed to designated approvers and export is blocked until approved Given an approver reviews the request When they approve or reject with comments Then the decision, approver identity, timestamp, and comments are recorded and the export is respectively enabled or blocked
Minimum-Necessary Export with Policy-Driven Redactions
Given a selected export policy/template When the export is assembled Then only the minimum necessary artifacts required by the policy are included Given PII elements marked for redaction by policy (e.g., ID images) When documents are rendered Then those elements are redacted and the manifest notes redaction presence per file Given a new policy version is active When an export runs under that version Then the manifest records the policy identifier and version used
Signed Archive with Manifest and Hashes (Chain-of-Custody Included)
Given an export is approved When the package is generated Then the output is a single signed archive containing: all included artifacts, an inventory manifest with file names, sizes, and SHA-256 hashes, an audit summary, and a machine-readable chain-of-custody file Given the signed archive and included public certificate When signature verification is performed Then the signature verifies successfully; and if any file is altered, verification fails Given the manifest hashes When hashes are recomputed externally Then they match the manifest values or the package is flagged as tampered
OTP-Protected, Expiring Download Link
Given an export package is ready When a download link is issued Then the link requires OTP verification and has a default 72-hour expiration that is configurable and revocable by authorized users Given a recipient enters an OTP When the correct OTP is provided within 10 minutes Then the download begins; and after 3 failed attempts the link is locked and an audit event is recorded Given an expired or revoked link When it is accessed Then access is denied with an appropriate message and the attempt is logged
Watermarking and Access Logging
Given any rendered document within the export package When it is viewed or printed Then each page displays a visible watermark including matter ID, export timestamp, and package ID Given a user or recipient downloads or previews the package or a file within it When the access occurs Then an audit log entry is recorded with identity (or link recipient), IP, timestamp, action, target file, and outcome (success/failure)
Jurisdiction Templates and Validation
Given the user selects a jurisdiction template (e.g., CA civil subpoena, NY family court) When configuring the export Then the template applies predefined artifact lists, redaction rules, and cover letter format Given required template fields are incomplete or incompatible with matter data When the user attempts to proceed Then validation errors specify the missing or conflicting fields and block export until resolved Given a template is used for export When the export completes Then the manifest records the template name and version applied

ChainSeal Ledger

Append‑only, hash‑chained event logging for every matter. Each action—intake edits, consent captures, version saves, e‑signs, payments, and accesses—becomes a signed record with a chain hash and per‑matter integrity anchor. Exports include a verifier so regulators (and opposing counsel) can independently confirm nothing was altered, delivering tamper‑evident assurance without extra IT overhead.

Requirements

Unified Event Capture Schema
"As a solo consumer-law attorney, I want every action on a matter to be consistently recorded so that I can prove what happened and when without reconciling logs from multiple systems."
Description

Define and implement a normalized, append-only event schema that records all matter activities across Briefly (intake edits, consent captures, document version saves, e-sign events, payments, access views/downloads). Each event must include: matter_id, event_id, event_type, actor (user/service) identity, authenticated session/context, RFC 3339 timestamp plus monotonic sequence, request_id/idempotency key, payload hash (SHA-256) of referenced artifacts, previous_event_hash pointer, and signature metadata placeholder. Instrument all relevant services to emit events through a reliable queue/bus with at-least-once delivery and idempotent ingestion. Ensure low overhead (<10 ms p95 per event) and zero user-flow degradation on mobile. Provide backfill utilities for legacy matters and a validator that rejects malformed/unsourced events. Store only minimal metadata in the event payload; sensitive document contents are referenced by hash and object store pointer, not duplicated in the ledger.

Acceptance Criteria
Schema Field Completeness and Type Validation
Given an event is emitted by any Briefly service via the event bus When the event is received by the ledger ingestion service Then the event contains matter_id, event_id, event_type, actor identity, authenticated session/context, RFC 3339 timestamp, per-matter sequence, request_id, idempotency_key, payload_hash (SHA-256), previous_event_hash, and signature_metadata placeholder And all fields match the defined types and formats (UUIDs, enums, hex-encoded SHA-256, RFC 3339 with timezone, integer sequence >= 1) And event_id is globally unique; duplicates are rejected with code EVT_ID_409 And event_type is one of {intake_edit, consent_capture, doc_version_save, e_sign, payment, access_view, access_download}; unknown types are rejected with code EVT_SCHEMA_400 And events missing required fields or with invalid formats are rejected with code EVT_SCHEMA_400 and are not persisted
Per-Matter Sequence and Timestamp Ordering
Given two or more events exist for the same matter_id When events arrive out of order due to transport retries Then the ingestion service persists only events whose sequence is strictly greater than the last accepted sequence for that matter And deliveries with the same request_id or idempotency_key and identical canonical content are acknowledged without creating a new ledger entry And events with sequence <= last accepted and not idempotent are rejected with code EVT_SEQ_409 And the event timestamp is RFC 3339 and not earlier than the last accepted timestamp for that matter; otherwise the event is rejected with code EVT_TIME_409
Hash Chain Integrity Enforcement
Given an accepted prior event for a matter with computed event_hash Hn When the next event En+1 is ingested Then En+1.previous_event_hash equals Hn And the ledger recomputes En+1's canonical event_hash over the normalized event contents and persists it And any mismatch between previous_event_hash and the last accepted event_hash results in rejection with code EVT_CHAIN_409 And the first event for a matter must have previous_event_hash set to null or the agreed genesis value; otherwise it is rejected with code EVT_CHAIN_400
Idempotent Ingestion with At-Least-Once Delivery
Given the message bus may deliver duplicates and retries When the same event (identified by request_id or idempotency_key) is delivered multiple times Then only one persisted ledger entry exists for that event And subsequent deliveries are acknowledged without persistence and increment a deduplication metric And concurrent deliveries of the same event do not create race-condition duplicates And client retries after transient failures return success if the event is already persisted or has just been persisted
Minimal Metadata with Payload Hash Referencing
Given an event references an external artifact (document/file) When the event is persisted Then the ledger stores only payload_hash (SHA-256) and an object_store_pointer for the artifact; no raw artifact bytes are stored in the ledger And the validator rejects events that include inline artifact content with code EVT_PAYLOAD_400 And a verifier job can fetch the artifact by pointer and recompute SHA-256 to exactly match payload_hash; mismatches are flagged with code EVT_PAYLOAD_409 and the event is quarantined from the chain
Mobile Performance Overhead p95 <= 10ms
Given mobile users execute intake, consent, document review, e-sign, and payment flows in staging When ChainSeal event emission is enabled behind a feature flag Then the added p95 latency per API call attributable to event emission is <= 10 ms as measured by server-side A/B (flag off vs on) across representative traffic And client-side completion and error rates show no statistically significant degradation compared to baseline And no additional mobile timeouts or retries are introduced due to event emission
Legacy Matters Backfill and Chain Reconstruction
Given a legacy matter without prior ledger entries When the backfill utility is executed for that matter Then the utility emits a deterministic sequence of schema-compliant events ordered by historical occurrence And ingested backfill events form a valid hash chain starting from a genesis event for the matter And rerunning the backfill for the same matter is idempotent and does not create duplicate ledger entries And the backfill job produces a report of emitted events, skipped items, and validation failures for audit
Per‑Matter Hash Chain and Integrity Anchors
"As an attorney preparing for potential challenges, I want a tamper-evident chain with a per-matter anchor so that any alteration would be immediately detectable by third parties."
Description

Create an append-only, per-matter hash chain where each event’s record contains the previous_event_hash, forming an unbroken chain. Compute and persist a matter “integrity anchor” (current chain head hash and length) after each write and at key milestones (e.g., retainer signed, first filing). Maintain a daily system-level anchor manifest that aggregates all matter anchors and is itself signed. On read/verify, recompute hashes to detect any insertion, deletion, or mutation. If a mismatch is detected, raise a critical alert, quarantine the affected matter’s ledger, and block further writes until resolved. Ensure chain operations are deterministic and independent of storage order (rely on index/prev hash, not timestamps). Support efficient range proofs for exporting a subset of events while preserving verifiability.

Acceptance Criteria
Append-Only Event Linking and Deterministic Hashing Per Matter
Given a matter with chain length N and head hash HN When a new event EN+1 is submitted Then the system assigns index N+1, sets previous_event_hash = HN, computes event_hash deterministically from canonicalized fields and previous_event_hash, and persists the record atomically And the write is rejected with no state change if supplied previous_event_hash != HN or index != N+1 Given an attempt to modify or delete any existing event record When the operation is attempted Then the system rejects the operation with a conflict error and the ledger remains unchanged
Integrity Anchor Persisted After Each Write and Milestones
Given a successful event write EN When the transaction commits Then a per-matter integrity anchor is updated and persisted with head_hash = hash(EN) and length = N, and is retrievable via API returning those values Given milestone events "retainer signed" and "first filing" When these events are recorded Then anchors are persisted and tagged with the milestone type, and querying anchors by milestone returns the correct head_hash and length
Daily System-Level Anchor Manifest Signing and Verification
Given the end of each UTC day When the manifest job runs Then the system publishes a manifest containing all current {matter_id, head_hash, length} anchors and a detached signature And verifying the manifest with the platform public key succeeds Given any later mutation to a matter ledger that would change its anchor When the previously published manifest is verified Then verification fails, indicating tamper evidence
Tamper Detection, Alerting, Quarantine, and Write-Block
Given a matter ledger where any event has been inserted, deleted, or mutated When a read or explicit verify(matter_id) is performed Then hash recomputation detects a mismatch, emits a Critical alert with matter_id and failing index, marks the matter as quarantined, and records an audit entry And any subsequent write attempts to the quarantined matter are blocked with a Locked error until resolved by an authorized action Given a quarantined matter When a read of the ledger is requested Then the response indicates IntegrityMismatch and includes no mutable operations
Order-Independent Chain Verification
Given the same set of events stored and retrieved in arbitrary physical order When verify(matter_id) runs multiple times with different retrieval orders Then the computed head hash and chain length are identical across runs and verification succeeds Given two events share the same index or an event's previous_event_hash does not match the prior head in sequence When verify(matter_id) runs Then verification fails and identifies the first offending index deterministically
Verifiable Range Export with Embedded Verifier
Given a request to export events i..j for a matter with current anchor {head_hash, length} When the export is generated Then the artifact contains the subset records [i..j], boundary proofs (including event_hash of i-1 or a signed anchor at i-1), the target anchor reference, and a standalone verifier And running the verifier with only the export and the platform public key validates the subset successfully Given any alteration to any record or boundary proof in the export When the verifier is run Then verification fails and reports the first mismatched event index
Cryptographic Signing and Key Management
"As a practitioner who may be audited, I want events to be signed with managed keys so that authenticity can be proven even if infrastructure or personnel change."
Description

Digitally sign every event record using tenant-scoped keys managed in a cloud KMS/HSM (FIPS 140-2 validated). Use ECDSA P-256 with SHA-256 or Ed25519 (selectable per deployment), and embed signature, algorithm, key_id, and key_version in the record. Implement key rotation (annual or on-demand), publishing rotation events to the ledger; new events must use the new key while historic signatures remain verifiable. Enforce least-privilege access to signing operations, with dual-control for rotation and revocation. Provide offline verification artifacts (public keys/cert chain) and maintain a key revocation list. Ensure signing latency adds <15 ms p95 and is resilient to regional KMS outages via multi-region failover with deterministic retries.

Acceptance Criteria
Per-Event Digital Signature with Embedded Metadata
Given a tenant creates any ledger event record, When the record is persisted, Then the record contains signature, algorithm, key_id, and key_version fields and no field is null or empty. Given the persisted event's canonicalized bytes, When verifying the signature using the tenant public key matching key_id/key_version, Then verification succeeds for 100% of a sample size >= 1000 events across all event types. Given the algorithm field value, When evaluated, Then it equals exactly one of ["ECDSA_P256_SHA256","Ed25519"]. Given key_id and key_version, When cross-checked against KMS metadata, Then they map to an existing tenant-scoped key version in a FIPS 140-2 validated KMS/HSM. Given a signing operation occurs, When reviewing KMS audit logs, Then a corresponding Sign API call is recorded under the tenant key for each ledger event persisted.
Deployment-Level Algorithm Selection
Given deployment configuration sets algorithm = "Ed25519", When new events are signed, Then algorithm == "Ed25519" for all new events and signatures verify with the Ed25519 public key. Given deployment configuration sets algorithm = "ECDSA_P256_SHA256", When new events are signed, Then algorithm == "ECDSA_P256_SHA256" for all new events and signatures verify with the ECDSA P-256 public key and SHA-256 digest. Given an algorithm change is requested, When a corresponding rotation event is not published to the ledger, Then the algorithm change is not applied to new events. Given an algorithm change accompanied by key rotation is executed, When verifying old and new events offline, Then pre-change events verify with the old algorithm/key and post-change events verify with the new algorithm/key.
Key Rotation and Ledger Publication
Given a scheduled annual rotation, When rotation executes, Then a rotation event is appended to the ledger including new key_id, key_version, algorithm, and effective_at timestamp. Given rotation has completed, When creating events after effective_at, Then those events use the new key_id/key_version and verify with the corresponding public key. Given historic events created before effective_at, When verifying signatures offline, Then each verifies with its original key material and fails verification with non-matching keys. Given an on-demand rotation is requested, When dual approvals are completed, Then the rotation executes immediately and the rotation event is published before any subsequent event is signed.
Least-Privilege and Dual-Control Enforcement
Given service principals are configured, When an application component signs an event, Then its IAM role has only kms:Sign on the tenant key and does not have kms:CreateKey, kms:ScheduleKeyDeletion, kms:RotateKey, or kms:DisableKey. Given a rotation or revocation is requested, When fewer than two distinct authorized approvers approve, Then the operation does not execute. Given a rotation or revocation is executed, When auditing, Then two distinct approvals with approver IDs, timestamps, and reasons are recorded and linked to a ledger event. Given a key is revoked, When the application attempts to sign using that key, Then the operation is denied and no ledger event is persisted. Given an unauthorized identity attempts to sign, rotate, or revoke, When the attempt occurs, Then the action is denied and an access-denied event is appended to the ledger.
Offline Verification Artifacts and Key Revocation List
Given a matter ledger export is generated, When opened offline, Then it contains a verifier tool/script, public keys or certificate chain for all key versions used, and a current key revocation list (KRL). Given the offline verifier is executed without network access, When verifying the exported ledger, Then it validates all signatures and flags any tampering using only included artifacts. Given a key is listed in the KRL with an effective revocation time, When running the verifier, Then signatures with timestamps after the effective time using that key are reported invalid and signatures before are reported valid. Given the KRL is updated, When generating a new export, Then the export includes the updated KRL with issuer, version, and issue timestamp metadata.
Signing Latency and Multi-Region KMS Failover
Given steady-state operation, When measuring end-to-end signing time at the application layer, Then signing adds < 15 ms p95 latency over 5-minute windows across at least 10,000 operations. Given transient KMS errors (e.g., deadline exceeded or internal error), When deterministic retries with idempotent request identifiers execute, Then exactly one signed ledger event is persisted and the chain remains gap-free. Given a simulated primary-region KMS outage, When signing requests occur, Then the system fails over automatically to a secondary region and resumes successful signing within 30 seconds without operator intervention. Given primary region recovers, When health is restored, Then signing traffic fails back without violating the < 15 ms p95 latency objective under steady-state and without producing duplicate signatures.
Verifiable Export Package
"As a regulator or opposing counsel receiving evidence, I want an export with a built-in verifier so that I can independently confirm integrity without relying on Briefly’s systems."
Description

Provide one-click generation of a portable export that includes: JSONL ledger records, a manifest with matter integrity anchor(s), public keys/cert chain, and a standalone verifier (CLI binary and script) capable of offline validation. The verifier must: validate signatures, recompute the hash chain, confirm anchors match, and detect gaps or duplicates. Package includes human-readable README with instructions and expected outputs, plus SHA-256 checksums for all files. Support selective exports by date range or event types without breaking verifiability (via range proofs). Exports must be deterministic and reproducible, and sized efficiently for email/portal delivery. Ensure the export contains no sensitive document contents beyond necessary metadata and hashes.

Acceptance Criteria
One‑Click Full Matter Export Package Creation
Given a matter with at least 200 recorded ledger events and no filters applied When the user selects “Export verifiable package” from the matter actions Then a single compressed archive is generated and downloaded successfully And the archive contains: a ledger JSONL file (one event per line), a manifest file with matter ID and integrity anchor(s), the public key(s) and certificate chain required to validate all signatures, a CLI verifier binary and a script wrapper, a human‑readable README with usage and expected results, and a SHA‑256 checksums file covering every included file And every file listed in the manifest exists in the archive and is readable And all file paths referenced in the manifest match exactly the files present in the archive (no missing or extra files) And the checksums file contains SHA‑256 for every file in the archive except itself, and the manifest contains the SHA‑256 of the checksums file And verifying each checksum against its file content succeeds (no mismatches)
Offline Signature, Hash‑Chain, and Anchor Verification
Given a valid export archive and a host with all outbound network access blocked When the included verifier is executed against the archive without any network connectivity Then the verifier completes without attempting any network calls And it validates the digital signature of every ledger event using only the included public keys/cert chain And it recomputes the hash chain across the ordered ledger and confirms the terminal hash(es) match the manifest’s integrity anchor(s) And it detects and reports any gap (missing sequence index), out‑of‑order record, or duplicate event ID/hash And on complete success it exits with code 0 and prints a summary including counts of events verified, anchors verified, gaps=0, duplicates=0 And on any failure it exits non‑zero and prints a clear error describing the first failing check (signature, chain, anchor, gap, duplicate)
Selective Export by Date Range with Range Proofs
Given a matter whose ledger spans multiple dates and a user specifies a start and end timestamp filter When the export is generated with the date range filter applied Then only events whose timestamps fall within the inclusive range are present in the ledger JSONL And the export includes range‑proof metadata sufficient for the verifier to validate continuity to the immediately preceding and following events outside the range without revealing their contents And running the verifier on the range export confirms chain continuity at both boundaries and that the recomputed boundary links match the manifest’s anchor(s) And the verifier fails if any in‑range event is missing or any out‑of‑range event is included And the verifier output reports the subset event count and “subset verified” status on success
Selective Export by Event Types with Skip/Range Proofs
Given a matter containing mixed event types and a user selects a subset of event types to export (e.g., e‑signs and payments) When the export is generated with the selected event‑type filter Then the ledger JSONL contains only events of the selected types, in original chain order And the export includes skip/range proofs that allow the verifier to bridge excluded events while preserving hash‑chain verifiability And running the verifier confirms that all chain positions containing the selected types are present and that chain continuity is intact across excluded segments And the verifier fails if any included‑type event is omitted or any nonselected type is present And the verifier output reports filtered types and “subset verified” status on success
Deterministic and Reproducible Export Output
Given the same matter snapshot and identical export parameters (filters, options, archive format) When two exports are produced on different hosts and file system paths within a 24‑hour window Then the resulting archive byte streams are identical (their SHA‑256 digests match exactly) And internal files are ordered deterministically, JSON is serialized canonically, line endings are normalized, and file mtimes within the archive are fixed to a deterministic value And compression settings are deterministic so re‑exporting yields identical bytes And running the included verifier on both archives produces identical exit codes and identical summary text
Privacy Safeguards: No Sensitive Document Contents
Given a matter that includes uploaded documents and PII within the system When a verifiable export is generated (full or selective) Then no raw document bytes (PDF, DOCX, images, etc.) are included in the archive And only document metadata (e.g., filename, size, content hash) and ledger facts are present; document contents are represented solely by cryptographic hashes And no access tokens, API keys, or session cookies appear in any file And an automated scan of archive contents finds no files whose magic numbers identify common document types and no strings matching known secret patterns And the manifest explicitly lists allowed data classes included; any attempt to include disallowed content causes export to fail with a clear error
Size Efficiency and Delivery Readiness
Given a representative matter with up to 10,000 ledger events and no binary documents included in the export When a full export is generated Then the compressed archive size is ≤ 25 MB to meet common email/portal limits And for a matter with 2,000 ledger events the compressed archive size is ≤ 10 MB And the overhead introduced by proofs, manifest, keys, and verifier is ≤ 30% of the ledger JSONL size And the archive format is a single .zip or .tar.gz file that can be uploaded to standard client portals without additional tooling
Matter Audit Timeline UI
"As a solo attorney and my paralegal, I want a clear, printable timeline of ledger events so that we can quickly answer who-did-what-when and produce a court-ready audit summary."
Description

Add a read-only, filterable timeline within each matter that renders ledger events with clear labels (who/what/when), signature status, and the current integrity anchor. Provide filters by event type, actor, and time window; support quick actions to copy the chain head, download an audit PDF, or generate a verifiable export. The UI must be mobile-friendly, accessible (WCAG AA), and localized for time zones and formats. Include an on-demand verification check that recomputes hashes client-side or via a secure endpoint and displays a tamper status badge. Ensure the view respects access control, never allows edits, and redacts any sensitive fields not required for audit.

Acceptance Criteria
Read-Only Timeline Rendering of Ledger Events
Given a matter with at least 10 ledger events across intake edit, consent capture, version save, e-sign, payment, and access When a permitted user opens the Matter Audit Timeline UI for that matter Then the timeline lists all events in reverse chronological order And each event displays who (actor name or service ID), what (event type label), and when (timestamp localized to the user's time zone and format) And events that include signatures display signature status (e.g., pending, completed, failed) And the current integrity anchor (chain head hash) is visible on the screen And no fields are editable and no edit/delete controls are rendered
Filter Events by Type, Actor, and Time Window
Given a matter with events by multiple actors, types, and dates over at least 30 days When the user applies event type filters (multi-select) And applies actor filters (multi-select) And sets a time window (start and end date/time) Then the timeline shows only events that match all selected filters And the count of results updates to reflect the filtered set And clearing filters restores the full event list And if no events match, an empty-state message is shown
Quick Actions: Copy Chain Head, Audit PDF, Verifiable Export
Given the Matter Audit Timeline is loaded When the user clicks "Copy chain head" Then the current chain head hash is copied to clipboard and a confirmation is shown When the user clicks "Download audit PDF" Then a PDF is downloaded listing the currently visible events, the matter ID, a generation timestamp, and the chain head hash When the user clicks "Generate verifiable export" Then a downloadable export package is produced containing the ledger events, the per-matter integrity anchor, and an offline verifier And the export includes instructions to run the verifier to confirm the chain and integrity anchor
On-Demand Verification and Tamper Status Badge
Given the Matter Audit Timeline is open When the user initiates "Verify ledger" Then the system recomputes the chain hashes for the matter either client-side or via a secure verification endpoint And compares the recomputed head to the displayed integrity anchor And displays a tamper status badge with one of: "Valid" (match), "Tampered" (mismatch), or "Error" (verification failure) And the badge includes the verification timestamp And verification runs without transmitting sensitive field values to third parties
Access Control and Redaction Enforcement
Given a user with read-only audit permissions opens the timeline for an authorized matter Then the timeline loads and displays audit metadata only Given a user without access attempts to view the timeline Then access is denied with a 403 response and no event data is rendered And sensitive fields flagged as non-audit in the schema are redacted or masked in all rendered events and exports And any attempt to modify, delete, or append events via the UI is impossible and corresponding API endpoints are not exposed or return 405
Mobile-Friendly Layout and Localization
Given a mobile viewport of 375x667 and 320x568 When the timeline is viewed and scrolled Then there is no horizontal scrolling, text is legible, and controls have minimum 44x44px touch targets And long hashes are truncated with a copy action available And timestamps are formatted per the user's locale and profile time zone, with browser time zone used as fallback
WCAG 2.1 AA Accessibility Compliance
Given the timeline and all its controls Then all interactive elements are reachable via keyboard (Tab/Shift+Tab) in a logical order with a visible focus state And non-text contrast and text contrast meet WCAG AA (>= 3:1 for UI components, >= 4.5:1 for text) And screen readers announce each event's actor, type, timestamp, signature status, and the current tamper status badge via accessible names/roles And functionality does not rely on color alone; all status indicators include text And content reflows without loss at 320px width and at 400% zoom And motion respects prefers-reduced-motion settings
Access Controls and PII Minimization
"As a privacy-conscious attorney, I want the ledger to capture only what’s necessary and restrict who can see it so that auditability doesn’t increase my client’s exposure risk."
Description

Enforce strict, role-based access to ledger data (matter owner, assigned staff, audit roles) and implement least-privilege scopes for API/exports. Minimize PII within events by storing hashes and references instead of raw contents; apply field-level encryption where identifiers are unavoidable. Provide jurisdiction-aware data residency and retention controls (e.g., WORM retention for 7 years, configurable). Enable privacy-preserving external sharing by generating exports that omit sensitive fields while preserving verifiability of the sequence and anchors. Log all ledger reads as separate events without exposing the contents of prior events. Support data subject access and deletion workflows by demonstrating that ledger integrity is preserved while sensitive payloads remain out-of-band.

Acceptance Criteria
Role-Based Ledger Access Controls (Owners, Staff, Auditors)
Given an authenticated user who is the Matter Owner or Assigned Staff of Matter M, When they request GET /matters/M/ledger, Then the response is 200 and only events for Matter M are returned. Given an authenticated user without membership on Matter M and without Audit role, When they request any ledger endpoint for Matter M, Then the response is 403 and the body does not confirm Matter M existence. Given a user with Audit role, When they request GET /matters/M/ledger, Then the response is 200 and event payload fields are redacted (metadata, hashes, and references only), and no mutation endpoints are available. Given a user’s assignment to Matter M is revoked, When they attempt access within 60 seconds of revocation, Then the response is 403.
Least-Privilege API Token Scopes for Ledger and Exports
Given an API token scoped to ledger:read:matter:M, When it calls GET /matters/M/ledger, Then the response is 200; When it calls GET /matters/Other/ledger, Then the response is 403. Given an API token without ledger:export scope, When it calls POST /exports/chainseal for any matter, Then the response is 403. Given an API token scoped to ledger:export:matter:M with profile=privacy, When it calls POST /exports/chainseal?matter=M, Then a 202 Accepted export job is created and the resulting export omits sensitive fields while preserving cryptographic verifiability.
PII Minimization via Hashing and Field-Level Encryption
Given an event with PII-bearing payload is persisted, When inspecting the ledger record, Then raw PII is not stored; only payload_hash, content_type, and opaque reference_id are present. Given identifiers that must be stored, When inspecting the record at rest, Then values are field-level encrypted (ciphertext with algorithm and key_id) and never plaintext. Given the original payload, When computing SHA-256 and comparing to the stored payload_hash, Then the values match.
Jurisdiction-Aware Data Residency and WORM Retention
Given tenant residency is set to Region R and WORM retention to 7 years, When new ledger events are written, Then underlying objects reside in Region R and are object-locked as immutable. Given any attempt to modify or delete a ledger event before retention expiry, When executed, Then the operation is rejected (HTTP 423 or equivalent) and no data changes occur. Given retention expiry is reached, When the retention job runs, Then out-of-band payloads eligible for deletion are removed while ledger hashes, references, and chain integrity remain intact.
Privacy-Preserving External Export with Verifier
Given a matter with events containing sensitive fields, When a privacy-preserving export is generated, Then exported records exclude sensitive fields and include hashes, chain links, and the per-matter integrity anchor. Given the included verifier is run against the export bundle, When it validates the sequence and anchors, Then it reports the chain as intact and unaltered. Given an export consumer compares event counts, When they check counts, Then the number of exported events equals the number of internal ledger events for the selected scope.
Read Access Logging Without Content Exposure
Given any successful or failed read of ledger data for Matter M, When the read completes, Then a READ event is appended capturing actor_id, scope, timestamp, and hashes/pointers to accessed items without including prior event contents. Given retrieval of READ events, When an auditor queries them, Then they can see who accessed what and when, but cannot recover any prior event payloads from the READ events themselves. Given excessive read attempts by an unauthorized actor, When they trigger rate limits, Then each attempt is logged as a READ event (denied) without leaking sensitive content.
Data Subject Access and Deletion While Preserving Integrity
Given a verified data subject access request for Subject S, When the report is generated, Then it lists all matters and event metadata referencing S using hashed identifiers and timestamps only, with no plaintext PII. Given an approved deletion for Subject S, When out-of-band payloads containing S’s PII are removed, Then corresponding ledger entries remain with hashes and references, and the chain hash/anchor remains unchanged and verifiable. Given a post-deletion export is generated, When the verifier is run, Then it confirms sequence integrity and indicates that payload references for deleted items are unavailable (e.g., HTTP 410) without breaking the chain.

TimeScope Replay

Reconstruct exactly what each participant saw and agreed to at any moment in time. View point‑in‑time screens with the active template version, conditional text states, timestamps, and locale. Defuses “I didn’t see that clause” disputes, speeds ethics responses, and helps attorneys validate that client‑facing language matched policy when consent was given.

Requirements

Immutable Event Capture
"As a solo consumer-law attorney, I want every client-facing screen state to be captured immutably so that I can prove exactly what my client saw when they provided information or consent."
Description

Implement an append-only, tamper-evident event ledger that records every user-visible state during intake and signing sessions. Each event stores template/version IDs, resolved conditional text states, field values at time of display, server/client timestamps, timezone and locale, session and participant identifiers, device/browser and viewport metrics, IP, and action type (viewed, scrolled, acknowledged, consented). Events are persisted with write-once storage and sequence guarantees for accurate ordering. Integrates with the questionnaire renderer and e‑sign flow via middleware to capture before/after render states and consent triggers. Provides data classification tags to support downstream redaction and access controls. Enables precise reconstruction and defensible auditability across high-volume matters without degrading user experience.

Acceptance Criteria
Point-in-Time Screen Reconstruction
- Given a completed intake or signing session with at least one view/acknowledge/consent event, When a reviewer selects a timestamp within that session in TimeScope Replay, Then the system renders the template and version captured at that moment with the exact conditional text resolutions and field values recorded. - And the replay applies the recorded locale and timezone so that dates, numbers, and text direction match the original rendering. - And the replay uses the recorded device type and viewport width/height to apply identical responsive layout breakpoints. - And the rendered textual content and control labels match the historical snapshot; the computed content hash of the replayed screen equals the stored event content hash. - And the event metadata shown includes the action type and both server and client timestamps for that moment.
Append-Only, Tamper-Evident Ledger
- Given the event ledger API, When attempting to update or delete an existing event, Then the request is rejected (non-2xx) and an audit entry with reason "immutable" is recorded. - Each new event contains: eventId, sessionId, sequenceNumber, payloadHash (SHA-256), previousPayloadHash (per session). Verifying the hash chain for any session yields no breaks. - Events are persisted to a write-once storage class with immutability enabled; attempts to alter or delete stored objects are rejected by the storage provider and logged. - A scheduled integrity job verifies hash chains and storage immutability at least daily and raises a High-severity alert within 60 seconds upon any failure.
Complete Event Payload Capture
- For every captured event, the following fields are present and non-null: templateId, templateVersionId, conditionalTextState snapshot, fieldValues snapshot at display time, serverTimestamp (UTC ISO 8601), clientTimestamp, timezone, locale, sessionId, participantId, deviceType, browserNameVersion, viewportWidth, viewportHeight, ipAddress, actionType ∈ {viewed, scrolled, acknowledged, consented}. - Action-specific: scrolled events include scrollDepthPercent; acknowledged events include controlId and value; consented events include consentArtifactId and before/after field snapshots; viewed events include page/screen identifier. - Field presence rate is ≥ 99.9% across a rolling 30-day window; missing/invalid fields trigger retry and are flagged for review.
Renderer and E‑Sign Middleware Hooks
- Given the questionnaire renderer, When a screen is about to render, Then a "pre-render" event is captured with input data; When rendering completes, Then a "post-render" event is captured with resolved content; both share a correlationId and have consecutive sequence numbers. - Given the e‑sign flow, When a participant performs a consent/accept action, Then a "consented" event is captured including the exact text presented, template/version IDs, and the UI control used (checkbox/signature). - If the client is offline, events are queued locally encrypted and flushed in order upon reconnect; idempotency keys prevent duplicates and preserve at-least-once delivery.
Ordering and Clock Skew Handling
- The server assigns monotonically increasing sequenceNumber per session; persisted sequence numbers are strictly increasing without gaps or duplicates. - Client and server timestamps are both recorded; if client-server skew exceeds 5 seconds, the event is flagged but ordered by server sequence in timeline views. - For matters with multiple participants, per-session order is preserved; cross-participant timeline merges by serverTimestamp and highlights concurrent events. - Detection of out-of-order submissions triggers automatic reconciliation and an audit alert.
Data Classification and Redaction Controls
- Each event payload carries field-level data classification tags (e.g., PII, financial, confidential, public). - Access policies enforce redaction/masking in TimeScope Replay according to viewer role; unauthorized viewers cannot access redacted fields via UI or API. - Exports default to redacted content based on the viewer's privileges; overrides require elevated role and capture justification in an audit event. - Tests verify that an attorney role sees full payload, support staff sees masked sensitive fields, and external auditor sees only metadata.
Performance and UX Non‑Degradation
- Event capture adds ≤ 30 ms median and ≤ 100 ms p95 overhead to render and consent actions on mid-tier mobile devices. - Ledger writes are ≤ 200 ms p95 and occur asynchronously; UI thread remains responsive with scroll capture maintaining ≥ 50 fps. - The system sustains ≥ 200 concurrent sessions at 10 events/sec each with end-to-end capture success rate ≥ 99.9% over 15 minutes and zero data loss. - If capture fails, the UI proceeds; events retry with exponential backoff; operators observe failures via dashboards with SLOs and alerts.
Point-in-Time Replay Renderer
"As an attorney responding to a dispute, I want to replay the exact screen my client saw at a specific timestamp so that I can verify the clauses and wording presented at that moment."
Description

Create a deterministic replay engine that renders the exact UI a participant saw at a specific timestamp using the captured event snapshot. The renderer resolves the referenced template version, conditional visibility logic, locale/time formatting, and responsive layout using stored viewport metrics to mirror mobile vs. desktop breakpoints. Supports pixel-accurate screenshot generation and an interactive step-through mode within the TimeScope Replay UI. Archives static assets referenced by past renders to avoid drift and provides fallback logic when assets are deprecated. Exposes an API for programmatic replay and a service-level test suite to verify fidelity parity across environments.

Acceptance Criteria
Deterministic Point‑in‑Time Render From Snapshot
- Given a stored event snapshot with timestamp T and participant P, When the renderer is invoked with T and P, Then it renders the exact UI state captured in the snapshot deterministically across repeated runs (serialized DOM hash identical). - Given the snapshot references template version V, When rendering, Then the engine loads V exclusively and does not fetch newer template content. - Given conditional visibility rules dependent on snapshot inputs and system flags, When rendering, Then all conditionally visible/hidden components match the recorded states in the snapshot. - Given no network connectivity to live services, When rendering from snapshot, Then the output is identical to a connected run (no live calls influence the result).
Template Version and Conditional Visibility Resolution
- Given a snapshot referencing template version V and feature flags F, When the renderer resolves the template, Then only artifacts from V are used and flags F influence conditional blocks exactly as recorded. - Given a dynamic clause controlled by rule R, When the recorded input satisfies R in the snapshot, Then the clause is included; otherwise it is excluded, matching the original render. - Given a late-bound merge field, When rendering, Then the field value equals the value captured at snapshot time without re-evaluating current data sources.
Locale and Timezone Formatting Fidelity
- Given snapshot locale L and timezone Z, When rendering any date/time or localized string, Then the formatted output matches the original render byte-for-byte (text content hash equality). - Given a timestamp within a daylight saving transition, When rendering, Then the displayed offset matches the snapshot’s recorded offset. - Given a right-to-left locale, When rendering, Then directionality (dir attribute) and punctuation shaping match the snapshot state.
Responsive Layout Parity Using Stored Viewport Metrics
- Given stored viewport width W, height H, device pixel ratio DPR, and user agent UA, When rendering, Then breakpoint selection and component layout match the original (CSS computed-style hashes for tracked selectors are equal). - Given a width exactly at a breakpoint threshold, When rendering, Then the same rounding and measurement logic is applied as in the original environment, producing identical layout decisions. - Given content that overflows and triggers scrolling, When rendering, Then scroll positions and pagination match the snapshot metadata.
Pixel‑Accurate Screenshot Generation
- Given a rendered point‑in‑time view, When a screenshot is requested, Then the generated image matches the baseline within ≤0.1% pixel difference using perceptual diff, and dimensions equal W×H×DPR. - Given high‑DPI DPR>1, When rendering the screenshot, Then vector text and archived fonts are used to avoid raster fallback and the image matches baseline thresholds. - Given a missing system font, When rendering, Then the archived font resource is used and the result passes the same diff threshold.
Interactive Step‑Through Playback in TimeScope UI
- Given a session with N≥2 snapshots, When the user clicks Next/Previous, Then the renderer advances to the adjacent snapshot and completes render in ≤150 ms average for N≤50. - Given the user drags the timeline scrubber to timestamp T, When released, Then the nearest snapshot to T is rendered and visibly marked as active. - Given the user toggles Diff View, When comparing step i to step i+1, Then only changed regions are highlighted based on DOM/text diffs and the highlight count matches computed diff metadata.
Asset Archival and Deprecation Fallback
- Given a referenced asset A (CSS/JS/image/font) with archived content‑addressable ID, When rendering, Then the archived asset is loaded and integrity hash matches the stored value. - Given asset A is missing from the archive, When rendering, Then the system loads the last known compatible fallback, emits a WARN log with asset ID, and sets render metadata assetFallback=true. - Given an asset integrity mismatch, When rendering, Then the render aborts with error code REPLAY_ASSET_INTEGRITY and no screenshot is produced.
Consent Snapshot Hashing
"As an ethics reviewer, I want a tamper-evident fingerprint of what was agreed to so that I can attest the consent matched policy at the exact time of agreement."
Description

At each consent event (e.g., checkbox acceptance, signature submit), compute a cryptographic hash of the rendered view (DOM and normalized text plus screenshot) and bind it to the event metadata (participant, timestamps, locale, IP, device). Store the hash in the event ledger and embed a reference in the e‑sign envelope audit trail; optionally notarize via a trusted timestamping service. Provide verification endpoints to validate the hash against exported evidence, ensuring tamper-evident linkage between what was displayed and what was agreed to. Integrates with existing e‑sign providers and retainer generation to cross-reference consent artifacts.

Acceptance Criteria
Hash Computation on Consent Event
Given a participant finalizes a consent action (checkbox acceptance or e-sign submit) in Briefly When the consent event is triggered Then the system generates a canonical snapshot using canonicalizationVersion >= 1 that produces deterministic bytes for: (a) canonicalized DOM, (b) normalized visible text after conditional resolution, and (c) a full-page PNG screenshot at recorded viewport; excludes non-deterministic values from the canonicalized DOM And then computes contentDigest = SHA-256(canonicalized DOM + normalized text bytes) and screenshotDigest = SHA-256(screenshot PNG bytes) and rootDigest = SHA-256(contentDigest || screenshotDigest) And persists an append-only ledger record with eventId, participantId, eventType, isoTimestamp with timezone, locale, ip, userAgent, deviceFingerprint, viewport, templateVersionId, canonicalizationVersion, hashAlgorithm="SHA-256", contentDigest, screenshotDigest, rootDigest And rejects any attempt to update or delete the persisted record (immutability enforced) And completes end-to-end capture and persistence within 1.5 seconds P95 and 3.0 seconds P99 under baseline load
Evidence Bundle Export and Verification
Given an existing consent event ledger record with rootDigest When a client requests an evidence export for that event Then the system returns a bundle containing canonicalContent.html, normalizedText.txt, screenshot.png, metadata.json, and digests.json with rootDigest, contentDigest, screenshotDigest, hashAlgorithm, canonicalizationVersion, templateVersionId, and eventId; bundle size <= 20 MB When the bundle is submitted to POST /verify or the eventId is provided to GET /verify/{eventId} Then the service recomputes contentDigest and screenshotDigest from the bundle, derives rootDigest, and returns 200 with verified=true when all digests match the ledger record; includes mismatch details when verified=false And the verification endpoint responds within 1.0 second P95 for bundles <= 10 MB and enforces authentication and rate limiting (HTTP 429 on limits)
Hash Binding in E-sign Provider Audit Trail
Given a consent event occurs within an e-sign process managed by a supported provider When the envelope/audit trail is created or updated for that consent Then the provider audit trail contains Briefly eventId, rootDigest (hex), and a retrieval URL to the verification endpoint And the Briefly ledger record stores provider envelopeId and provider event timestamp And cross-reference validation shows the provider timestamp and Briefly isoTimestamp differ by no more than 5 seconds And exporting the provider audit report (PDF/JSON) shows the exact rootDigest and eventId values present and machine-readable
Trusted Timestamping (Optional Notarization)
Given tenant-level setting "Trusted Timestamping" is enabled with a configured RFC 3161 TSA When a ledger record with rootDigest is created Then the system submits rootDigest to the TSA and stores the returned Time-Stamp Token (TST) and tsaCertificateChain on the ledger record with tsaStatus=Stamped And TSA submission failures do not block consent; the ledger records tsaStatus=Pending and retries with exponential backoff until Stamped or timeToLive exceeded (then Failed) with reason And the verification endpoint validates the TST signature and time, returning notarized=true with tsaTime when valid; returns notarized=false when tsaStatus is Pending/Failed or TSA validation fails
Locale and Conditional Content Capture
Given a template with conditional text and multilingual content When a participant completes intake with locale L and inputs that resolve specific conditional branches Then the canonical snapshot contains only the resolved text for that locale and branch set; canonicalContent.html and normalizedText.txt reflect L and branches And recomputing the snapshot using the same templateVersionId, inputs, viewport, and locale yields identical contentDigest and rootDigest And using a different locale or different conditional answers yields a different contentDigest and rootDigest
Verification API Error Handling and Integrity
Given a verification request with missing files, malformed metadata, or unsupported canonicalizationVersion When POST /verify is called Then the API returns 422 with a machine-readable list of validation errors; 404 for unknown eventId; 401 for missing/invalid auth; 413 for bundles > 50 MB And if any file in the bundle is altered from the ledger-backed digests, the endpoint returns 200 with verified=false and mismatch detail per component (content, screenshot) And all verification requests are audit-logged with requestId, caller, and outcome; PII in error messages is redacted
Versioned Template Registry
"As a template administrator, I want accurate version history and resolution by time so that replays reflect the exact language in force when the client viewed it."
Description

Establish a registry for all client-facing templates (retainers, questionnaires, disclosures) with semantic versioning, effective date windows, locale variants, and deprecation status. Store diffs and change metadata (author, reason, approvals) and expose resolution APIs that, given a timestamp and locale, return the authoritative template version for replay. Enforce referential integrity between events and template versions to prevent drift. Integrates with Briefly’s document automation pipeline so assembled drafts and replays align. Provides audit logs for regulatory inquiries and facilitates rollbacks without affecting historical replays.

Acceptance Criteria
Resolve authoritative template by timestamp and locale
Given the registry holds multiple template versions with effective windows and locale variants When the Resolution API is called with templateKey, timestamp T, and locale L Then it returns HTTP 200 with the single authoritative templateVersionId, semanticVersion, locale, effectiveStart, effectiveEnd (nullable), deprecationStatus, and checksum And the selected version satisfies effectiveStart <= T < effectiveEnd (or no end) and the highest-precedence locale (exact L, else language-only, else configured default) And deprecated versions are excluded if a non-deprecated candidate exists; otherwise the matching deprecated version is returned with deprecationStatus=deprecated And p95 response time for cached lookups is <= 200 ms with ≥10k versions
Prevent overlapping effective windows and enforce semantic versioning
Given a create or update request for a template version When validating the payload Then version must match MAJOR.MINOR.PATCH (SemVer) And effectiveStart is required; effectiveEnd is optional and must be greater than effectiveStart And no effective window may overlap any existing version for the same templateKey and locale; overlaps are rejected with HTTP 409 and errorCode=TEMPLATE_WINDOW_OVERLAP And effectiveStart and semanticVersion are immutable after creation; content is immutable; only deprecationStatus and effectiveEnd may be set post-create via explicit endpoints
Persist diffs and change metadata
Given a new version is created from prior version V-1 for the same templateKey and locale When the version is saved Then a structured diff (added/removed/modified sections) is computed and persisted And metadata fields authorId, reason, and approvals[>=1] are required and persisted And the Change History API returns the diff and metadata for any version with HTTP 200 And content and rendered-output checksums (SHA-256) are stored for integrity verification
Enforce referential integrity between events and template versions
Given an intake submission, consent, or assembly event occurs at timestamp T with locale L When persisting the event Then the event must store the resolved templateVersionId And if templateVersionId does not exist or is not valid for T and L, the write is rejected with HTTP 422 and errorCode=INVALID_TEMPLATE_REFERENCE And template versions referenced by any event cannot be hard-deleted; attempts result in HTTP 409 And historical replays always render using the stored templateVersionId regardless of later changes
Align automation pipeline and replay resolution
Given a draft is assembled by the document automation pipeline at timestamp T and locale L When the pipeline selects template content Then it must call the same Resolution API used by TimeScope Replay And the generated draft metadata includes templateVersionId, semanticVersion, locale, and content checksum And a nightly job samples ≥1% of drafts and replays them; any checksum mismatch creates a P1 alert and an audit log entry
Rollback without affecting historical replays
Given an erroneous template release is identified When performing a rollback Then a new version with a higher semanticVersion is created with effectiveStart >= now and optionally deprecates the erroneous version And no existing event records are modified; their templateVersionId remains unchanged And replays for events before rollback remain byte-identical; events after rollback resolve to the rollback version
Audit logging and queryability for regulatory inquiries
Given any create, update, deprecate, resolve, or rollback action occurs When querying audit logs by actorId, templateKey, date range, locale, or eventId Then results include timestamp (UTC), action, actorId, templateKey, templateVersionId, semanticVersion, diffChecksum, reason, approvals, and requestId And audit records are append-only and immutable; edit/delete attempts are rejected and logged And audit logs are retained ≥7 years and exportable as CSV and JSON with UTC timestamps
Timeline Navigator & Diff View
"As a practitioner handling a client complaint, I want an intuitive timeline to jump to the moment in question and see what changed so that I can prepare a fast, accurate response."
Description

Deliver a timeline UI that visualizes all events within a session, with filters by participant, event type, and screen. Enable quick jumps to key moments (e.g., first view of retainer, consent submitted) and provide a side-by-side diff that highlights textual or conditional changes between adjacent views or template versions. Include breadcrumbs, keyboard navigation, and search by clause heading. Optimize for large sessions with virtualized rendering and lazy loading. Integrates with the replay renderer to open directly at a selected timestamp and supports copying permalinks to exact moments.

Acceptance Criteria
Timeline Visualization & Filtering
Given a session containing at least 1,000 events across two or more participants and three or more screens, When the Timeline Navigator loads, Then events render in strict chronological order with timestamp, participant label, event type icon, and screen name visible for each row. Given the timeline is loaded, When the user applies filters for Participant, Event Type, and Screen, Then only events matching the intersection of selected filters are displayed and the total visible count updates accordingly. Given one or more filters are active, When the user clears all filters in a single action, Then the full, unfiltered event list is restored without page reload within 500 ms. Given the user scrolls through filtered results, When new items enter the viewport, Then the selection state and scroll position are preserved and no duplicate events appear. Given a filter results in zero matches, When the list is refreshed, Then a zero-state message "No events match the selected filters" is shown with a one-click "Clear filters" action.
Quick Jumps to Key Moments
Given a recorded session with identifiable key moments (e.g., First view of retainer, Consent submitted, Signature requested, Signature completed), When the user opens the Quick Jumps menu, Then only key moments present in the session are enabled and show their timestamps. Given a key moment is selected, When the user clicks it, Then the timeline scrolls to and selects the corresponding event, centers it in view, and loads its details within 300 ms. Given no "Consent submitted" event exists, When viewing the Quick Jumps menu, Then that item is disabled with a tooltip "No event in this session." Given the user navigates via Quick Jumps, When they press Back, Then the previous scroll position and selection are restored. Given multiple key moments of the same type exist, When the user expands that group, Then each instance is listed with sequence number and timestamp.
Side-by-Side Diff of Adjacent Views/Versions
Given two adjacent document views or consecutive template versions are selected, When the user opens Diff, Then a side-by-side comparator renders with Left = previous and Right = current within 1,000 ms for documents up to 50,000 characters. Given textual differences exist, When the diff renders, Then insertions are highlighted in green, deletions in red with strikethrough, and modified lines show yellow highlights; a legend explains the colors. Given conditional sections differ in visibility, When the diff renders, Then each affected section displays a state badge (Shown/Hidden) and the change is listed in a summary panel. Given the "Ignore whitespace" toggle is on by default, When differences are whitespace-only, Then they are suppressed; turning the toggle off reveals them. Given the user clicks "Swap sides," When the action completes, Then the previous/current panes swap without re-computing the diff and the highlights persist. Given the user enables "Show only changes," When active, Then unchanged sections collapse with a count of hidden lines and can be expanded on demand.
Breadcrumbs & Keyboard Navigation
Given the Timeline Navigator is open, When a specific event is selected, Then breadcrumbs display Session name > Participant > Screen > Event timestamp, each crumb is clickable, and navigation occurs without a full reload. Given any breadcrumb label exceeds available width, When rendered, Then it truncates with an ellipsis and shows the full value on hover/focus tooltip. Given focus is on the timeline, When the user presses Left/Right Arrow, Then the selection moves to the previous/next event respectively and the selected row is scrolled into view. Given focus is on the timeline, When the user presses Home/End, Then the first/last event becomes selected. Given an event is selected, When the user presses D, Then the Diff view toggles for that event; when the user presses Enter, Then the event details panel toggles. Given the user presses /, When shortcuts are enabled, Then focus moves to the Search input for clause headings; pressing ? opens the shortcuts help overlay. Given the user navigates entirely via keyboard, When performing any supported action, Then all controls are reachable with visible focus and ARIA roles/labels meet WCAG 2.1 AA.
Search by Clause Heading
Given a document with clause headings is associated to events, When the user enters a query into the Search input and submits, Then results return clause heading matches case-insensitively within 500 ms for sessions with up to 10,000 events. Given matches exist, When search results are shown, Then the first match is selected, the timeline scrolls to the corresponding event, and the matching heading is highlighted. Given multiple matches exist, When the user clicks Next/Previous in the search controls, Then navigation steps through matches in chronological order and updates the selection and highlight. Given no matches exist, When the search completes, Then a "No clauses found" message is displayed and the previous selection is preserved. Given the user clears the search, When input is emptied, Then highlights are removed and the timeline returns to the prior view without reloading.
Performance: Virtualized Rendering & Lazy Loading
Given a session with 10,000 or more events, When the timeline first loads, Then the initial visible list renders within 2,000 ms on a reference device (8 GB RAM, 4-core CPU) and remains responsive to input. Given the user scrolls continuously through the list, When new rows are virtualized in, Then frame rate remains at or above 55 FPS and at most 200 event row DOM nodes exist at any time. Given event details or diff data are not yet viewed, When the corresponding row becomes visible, Then only metadata is fetched; details/diff payloads are lazy-loaded on demand. Given the user opens 100 distinct event details within a session, When navigating, Then memory usage attributable to the Timeline Navigator stays under 300 MB via LRU cache eviction, and previously evicted details are re-fetched on access. Given a network latency of 200 ms, When lazy-loading subsequent pages of events, Then prefetching retrieves at least the next 50 events before the user reaches the bottom 10% of the current buffer.
Replay Integration & Permalinks to Exact Moments
Given an event is selected in the timeline, When the user clicks "Open in Replay," Then the Replay renderer opens to the event’s timestamp within ±250 ms, using the recorded templateVersionId and locale to render point-in-time content. Given an event is selected, When the user clicks "Copy permalink," Then a URL containing sessionId, eventId (or timestamp), participantId, templateVersionId, and locale is copied to the clipboard and a success toast confirms. Given a valid permalink is visited by an authorized user, When the page loads, Then the Timeline Navigator selects and scrolls to the exact event, applies the correct locale and template version context, and the URL remains stable after load. Given a permalink refers to a deleted or unauthorized session, When visited, Then an error state is shown with no data leakage and guidance to request access. Given the Replay service is temporarily unavailable, When "Open in Replay" is invoked, Then an error notification appears and the user can retry; the timeline remains usable.
Role-Based Access & Redaction
"As a firm owner, I want to control who can view and share replay data and ensure sensitive details are redacted so that we meet ethics and privacy obligations."
Description

Implement RBAC to restrict TimeScope Replay access by organization, matter, and role (owner, attorney, paralegal, auditor, external reviewer). Support expiring, watermarkable, view-only share links with scope-limited access. Apply automatic redaction rules based on data classification (PII/financial/health) and export context, with just-in-time decryption for authorized viewers. Log all access with IP and timestamp for audit trails. Provide jurisdictional controls (e.g., geo/IP restrictions) and configurable retention windows to meet ethics and privacy obligations.

Acceptance Criteria
RBAC Enforcement by Organization, Matter, and Role
Given a user with a specific role (owner, attorney, paralegal, auditor, external reviewer) and organization membership, When they attempt to access a TimeScope Replay for a matter, Then access is granted only if the user’s organization matches the matter’s organization and the role has explicit permission for replay viewing. Given a user without access to a matter, When they try to access a replay via UI navigation or direct URL, Then the system returns 403 Forbidden and does not reveal any sensitive metadata (e.g., matter title, participant names). Given a role-permissions matrix managed by the owner, When role permissions are updated, Then changes take effect within 60 seconds for new sessions and upon token refresh for active sessions, and the update event is logged. Given an external reviewer is granted access scoped to specific matter(s), When they sign in, Then they can only see and open replays for the scoped matters and no organization-wide data. Given an auditor role, When they view replays, Then they can see replay metadata and redacted content per policy, and export actions are blocked unless explicitly enabled by policy.
Scope-Limited View-Only Share Links with Expiry and Watermark
Given an owner creates a view-only share link scoped to a specific replay (and optional participant), with expiry time and max-views set, When the link is opened, Then the viewer sees a view-only interface with dynamic watermark (viewer email or link ID, IP, timestamp) and all download/copy/export actions are disabled. Given a share link with expiry T and max-views N, When current time exceeds T or total views reach N, Then the link returns 410 Gone and no content is rendered. Given a share link is explicitly revoked by its creator, When it is opened, Then access is denied and a revocation event is recorded in the audit log with actor, time, and reason. Given a share link locks template version, locale, and conditional text state, When opened at any later date, Then the replay renders exactly the locked version/locale/states regardless of current defaults or updates. Given a share link configured with a single-IP restriction, When accessed from a different IP, Then access is blocked and the attempt is logged with mismatch details.
Automatic Redaction by Data Classification and Export Context
Given fields are tagged with classifications (PII, financial, health) and a redaction policy is configured, When a replay is viewed by a role without clearance, Then classified values are masked with category labels (e.g., [PII]) and no reveal controls are shown for those fields. Given an export is initiated with a specified context (PDF, CSV, screenshot, API), When the export completes, Then redaction transforms are applied per context (e.g., masking in PDF/screenshots, field removal in CSV/API) consistent with policy, and the applied policy version is recorded. Given an attorney role with “view unredacted” permission, When they choose to reveal a specific field, Then only that field is decrypted for the current session view, and the audit log records user, field identifier, time, IP, and reason (if required by policy). Given a redaction policy is updated, When an existing replay is reopened, Then the latest policy is applied unless the session or share link is locked to a prior policy version, and the effective policy version is displayed and logged.
Just-in-Time Decryption for Authorized Viewers
Given sensitive fields are encrypted at rest, When an authorized user views a replay, Then decryption occurs just-in-time per field using per-tenant keys in an HSM, and plaintext is never persisted to storage. Given an unauthorized role attempts to view encrypted fields, When the replay loads, Then no decryption requests are issued and the content remains redacted. Given a session is inactive for 10 minutes, When the user returns and attempts to reveal additional fields, Then re-authentication is required before any further decryptions occur. Given a transient network error occurs during decryption, When retry policy is applied, Then up to 3 retries with exponential backoff are attempted and failures display a non-fatal redacted placeholder while being logged with error details.
Access Logging and Audit Trail Integrity
Given any access attempt to a replay or share link, When the request is processed, Then the system logs user or link ID, role, organization ID, matter ID, action (view, export, reveal, revoke), timestamp (UTC), IP address, user agent, outcome (success/failure), and effective policy/version. Given a logs retention window of N days is configured, When records exceed N days, Then logs are purged or archived per policy with a tamper-evident hash chain maintained and the purge event recorded. Given an auditor queries logs by matter and date range, When the dataset contains up to 10,000 records, Then results are returned within 2 seconds and can be paginated for larger sets. Given an authorized user exports the audit log to JSON or CSV, When the export completes, Then it excludes sensitive field values while including field identifiers and redaction reasons, and the export action is itself logged.
Jurisdictional Controls and Geo/IP Restrictions
Given a matter is configured for California-only access, When an access attempt originates from a non-CA IP, Then access is blocked with a policy message and the event is logged; an override requires an owner action with justification. Given both organization-level and matter-level allow/deny lists are configured, When they conflict, Then matter-level rules take precedence and the applied rule source is recorded in the log. Given high-risk networks (e.g., Tor, known VPN egress) are configured to be blocked, When an access attempt is detected from such a network, Then access is denied and the event is flagged as high-risk in the audit log. Given a temporary travel-based exception window is configured for a user, When the user accesses from the permitted country within the window, Then access is allowed; after the window expires, access is denied until policy is updated.
Configurable Data Retention for Replays and Exports
Given a retention window is set for replays and export artifacts, When the window expires, Then the replay and artifacts are deleted or tombstoned, share links return 410 Gone, and deletions are logged with proof (e.g., deletion receipt or cryptographic proof) where supported. Given a legal hold is placed on a matter, When retention jobs run, Then items under hold are exempt from deletion and are tagged with hold reason, placing user, and timestamp. Given retention settings are updated by an authorized user, When saved, Then the new settings apply to newly created content immediately and to existing content at the next scheduled retention job, and the UI displays the next job run time and scope.
Court-Ready Audit Export
"As an attorney preparing an ethics response, I want a court-ready evidence package of the replay so that I can submit authoritative proof without manual compilation."
Description

Provide a one-click export that assembles selected replay screenshots, a chronological timeline, full metadata (timestamps, locale, IP, device, session), template version references, and consent hashes into a paginated PDF plus machine-readable JSON. Include a cover sheet with matter info, organization seal, checksums, and validation instructions. Ensure exports are reproducible and verifiable against stored hashes. Attach the export automatically to the matter file and link it to the e‑sign envelope. Support branding, Bates numbering, and optional inclusion of change diffs for court or ethics board submissions.

Acceptance Criteria
One-Click Export Produces Court-Ready PDF and JSON
Given a matter with completed consent and replay events exist And the user selects specific replay steps for inclusion When the user clicks "Export Audit (PDF+JSON)" in TimeScope Replay Then the system generates two files: a paginated PDF and a machine-readable JSON And the PDF includes a cover sheet with matter ID, client name, organization name, organization seal, export timestamp (UTC ISO 8601), checksum manifest, and validation instructions And the PDF body includes each selected replay screenshot with its timestamp, locale, template version ID, and conditional text state labels And the PDF includes a chronological timeline section of the included events And the JSON includes an array of events with timestamps, locale, IP address, device user agent, session ID, template version IDs, and consent hash values And the export completes within 30 seconds for up to 50 included steps
Metadata Completeness and Cross-Source Consistency
Given a matter with known values for timestamps, locale, IP, device, session ID, template version IDs, and stored consent hashes When an audit export is generated Then the JSON contains all required metadata fields for each event with non-empty values And each metadata value matches the corresponding value stored in the system of record And the PDF displays the same metadata values and matches the JSON And missing or unmapped fields cause the export to fail with a descriptive error, not silently omit data
Reproducibility and Hash Verification
Given identical inputs (matter data unchanged, same replay selection, same branding and export options) When two exports are generated at different times Then the JSON manifest includes a canonical SHA-256 content hash computed over ordered events, template references, and consent hashes And generating the export twice with identical inputs yields the same canonical content hash And recomputing SHA-256 on the JSON and PDF files matches the checksums printed on the PDF cover sheet and in the JSON manifest And each consent hash in the export equals the stored consent hash recorded at the time of consent
Automatic Attachment to Matter and E-Sign Envelope Linking
Given a successfully generated export When the export completes Then the PDF and JSON are attached to the originating matter record And a link to the export is added to the associated e-sign envelope or audit trail And the matter timeline records an "Audit Export" entry with actor, timestamp, and export options And if attachment or linking fails, the system retries up to three times and surfaces an actionable error without losing the files
Branding and Bates Numbering Configuration Applied
Given an organization with branding enabled and Bates numbering configured with prefix "ACME-" and 7-digit zero padding When an audit export is generated Then the PDF cover sheet and headers/footers display the organization's logo/seal and colors And every page displays a Bates number in sequence across the entire document starting at the configured seed (e.g., ACME-0000001) And the Bates numbers are unique within the export and included in the JSON manifest And disabling branding or Bates numbering in export options removes them from the PDF
Optional Inclusion of Template Change Diffs
Given a matter whose timeline spans template versions V12 to V14 And the user enables "Include change diffs" When an audit export is generated Then the PDF includes a section per adjacent version pair (V12→V13, V13→V14) showing added, removed, and modified clauses with line-level diff markers And the JSON includes a machine-readable diff summary per version pair And when "Include change diffs" is disabled, no diff pages or summaries are present
Locale, Timestamps, and Timezone Presentation
Given a matter captured in locale "en-US" with client timezone "America/New_York" When an audit export is generated Then each event in the PDF shows both local time (America/New_York) and UTC in ISO 8601 with timezone offset And the locale code (en-US) is displayed with each event and included in the JSON And screenshots reflect locale-conditional text states corresponding to the event locale And date/time formatting is consistent across PDF and JSON and validates against ISO 8601

Consent Diff

Automatic redline of consent, disclosure, and fee language across revisions, linked to who accepted which version and when. Highlights material changes, prompts for re‑consent when thresholds are met, and bundles rationale with rule citations in the audit packet. Ensures informed consent is provable and compliant across evolving templates.

Requirements

Clause Versioning & Metadata
"As a solo attorney, I want clause language versioned with clear metadata so that I can trace what changed and why across templates and matters."
Description

Implement a centralized repository to manage consent, disclosure, and fee clauses as atomic, versioned components. Each clause version must store rich metadata (jurisdiction, matter type, language/locale, effective dates, authorship, change rationale, linked rule citations, risk/materiality tags). Provide APIs to reference clause versions from templates and matters, support deprecation and supersedence chains, and maintain immutable hashes for evidentiary integrity. Include migration tooling to import existing templates and extract clauses, plus governance controls (review/approval workflow) to publish new versions.

Acceptance Criteria
Clause Version Creation with Required Metadata and Immutable Hash
Given a user with Clause Editor role provides clause text and required metadata (jurisdiction, matterType, language/locale, effectiveStart, authorship, changeRationale, ≥1 ruleCitation, risk/materiality tags) When they click Save Then the system persists a new clause version with a unique versionId and monotonically increasing sequence, computes a SHA-256 hash over canonicalized clause text + metadata, and returns 201 Created with versionId and immutableHash And the saved version is read-only; any edit attempt to text or metadata returns 409 Conflict instructing to create a new version
Supersedence and Deprecation Chain Enforcement
Given an Approved clause version A exists for a clause identity in a specific jurisdiction, matterType, and locale When a new version B for the same identity/metadata is approved with supersedes=A Then A transitions to Deprecated with deprecationDate=approvalTimestamp, B transitions to Approved with effectiveStart ≥ approvalTimestamp, and the supersedence chain A <- B is stored And GET /clauses/current resolves B for effectiveOn ≥ B.effectiveStart while A is only returned when requested by versionId And attempts to supersede across mismatched jurisdiction/matterType/locale are rejected with 422 Unprocessable Entity
API Retrieval of Clause Versions by Filters and ID
Given approved clause versions exist across multiple jurisdictions and locales When a client calls GET /clauses?jurisdiction=CA&matterType=Debt&effectiveOn=2025-09-01&locale=en-US Then the API returns 200 with exactly one current Approved version whose effectiveStart ≤ effectiveOn and greatest among matches, including versionId, immutableHash, canonical text, and full metadata And when a specific versionId is requested via GET /clauses/{versionId}, that version is returned even if Deprecated And when no match exists, the API returns 404 with errorCode=CLAUSE_NOT_FOUND And all responses include ETag equal to immutableHash
Governance Workflow for Publishing Clause Versions
Given a Draft clause version with required metadata exists When an Author submits it for review Then only a user with Reviewer/Approver role can Approve or Reject; approval requires a non-empty reviewNote, and the system records approverId and timestamps And publish is blocked unless ruleCitations (≥1) and changeRationale are present And status transitions follow: Draft -> In Review -> Approved or Rejected, with each transition captured in an immutable audit log entry containing actor, action, timestamp, and previous/new status
Migration Tool Extracts and Imports Clauses from Legacy Templates
Given a legacy template file (DOCX, PDF, or Markdown) is uploaded with the extraction profile set to Consent/Disclosure/Fee When the migration tool runs Then the tool identifies candidate clauses, deduplicates exact text matches, creates Draft clause versions for new items, and links each to its source template And preliminary metadata (jurisdiction, matterType, language/locale) is inferred from template tags; items with confidence < 0.80 are flagged for human review And the tool outputs an import report with counts: filesProcessed, clausesCreated, duplicatesFound, flaggedForReview, errors; no clause versions are published automatically
Locale and Jurisdiction Validation and Retrieval Behavior
Given clause versions exist for en-US and es-US locales under the same jurisdiction and matterType When a matter with locale=es-US requests the current clause Then the API returns the es-US version; if unavailable and fallback=true, returns en-US; if fallback=false, returns 404 And on creation/update, locale must conform to IETF BCP 47 and jurisdiction must exist in the configured registry; violations return 422 with field-level errors
Redline Diff Engine
"As an attorney, I want automatic redlines that highlight material changes so that I can quickly assess what requires re-consent."
Description

Deliver an automated redline engine that compares clause-to-clause and document-to-document revisions, producing human-readable diffs suitable for legal review on desktop and mobile. Support word- and sentence-level granularity, formatting-aware comparisons, and inline highlights for additions, deletions, and moved text. Provide accessibility-compliant coloration, export to PDF/HTML, and an embeddable component within Briefly’s questionnaire and document viewer. Expose a service API that outputs both visual and machine-readable diff artifacts with stable anchors to clause/version IDs.

Acceptance Criteria
Clause-to-Clause and Document-to-Document Diff Anchoring
Given two versions of a document with clause_id and version_id metadata When the diff is generated for the entire document Then each clause present in both versions with the same clause_id is aligned 1:1 and output includes a stable anchor composed of clause_id and version_id And clauses present only in the new version are marked as added with new anchors And clauses present only in the old version are marked as deleted with old anchors preserved And reordered clauses are marked as moved, including from_anchor and to_anchor references And each anchor is a stable UUID and unique within the document And the alignment summary includes counts for added, deleted, moved, and unchanged clauses
Word- and Sentence-Level Granularity Controls
Given diff settings support "word" and "sentence" granularities with default "sentence" When the user toggles granularity Then the engine recomputes highlights at the selected granularity without altering clause anchors And punctuation-only changes are ignored at sentence granularity but shown at word granularity when characters differ And whitespace and hyphenation normalization does not create false positives And for documents up to 20,000 characters, the API responds within 2 seconds p95 and the UI updates within 500 ms p95 on desktop and mobile
Formatting-Aware and Moved-Text Detection
Given two versions where textual content and/or formatting differ (bold, italic, underline, heading levels, list styles) When a formatting-aware diff is executed with "show style changes" enabled Then style-only changes are labeled as formatting-change without marking text as added or deleted And when "show style changes" is disabled, formatting-only changes are suppressed And when a contiguous block of 15+ characters is relocated within the same clause, it is marked as moved with source and destination offsets and from/to anchors And pure whitespace, soft line breaks, and auto-renumbering of lists do not appear as material changes
Accessibility-Compliant Visualizations
Given the diff is displayed in the UI When a user navigates with a keyboard and/or screen reader Then added, deleted, and moved segments expose ARIA labels/roles announcing the change type and summary And all color indicators for change types meet WCAG 2.1 AA contrast (>= 4.5:1 for normal text) and include non-color cues (patterns/icons) And focus order is logical, focus is visible, and shortcuts exist to jump to next/previous change And in high-contrast mode, all change indicators remain perceivable and unambiguous
Export to PDF and HTML with Diff Fidelity
Given a generated diff for a document up to 30 pages When exporting to PDF Then the PDF preserves inline highlights for added/deleted/moved, includes a legend, embeds fonts, and provides bookmarks linked to clause anchors And the PDF is generated within 5 seconds p95 and is under 10 MB for documents under 30 pages When exporting to HTML Then the HTML preserves anchors as id/data attributes, includes a legend, and renders consistently in the latest two versions of Chrome, Safari, and Firefox And both exports include document_id, old_version_id, new_version_id, and timestamp metadata
Embeddable Diff Component in Questionnaire and Document Viewer
Given the diff component is embedded within Briefly’s questionnaire flow and document viewer When initialized with a pair of versions Then above-the-fold content renders within 500 ms on desktop and 800 ms on mobile at 360x640, and remains responsive down to 320 px width And the component exposes events (changeSelected, clauseFocused) and methods (scrollToAnchor, setGranularity) to host contexts And deep links of the form /docs/{doc_id}/diff/{old_id}..{new_id}#clause-{anchor} scroll and highlight the clause And it functions on the latest two releases of Chrome, Edge, Safari, and Firefox
Diff Service API and Machine-Readable Artifacts
Given the service API endpoint POST /diff with inputs of two document references or payloads and diff options When the request is valid Then the response includes a visual HTML fragment and a JSON artifact enumerating changes with type (add, delete, move, format), clause anchors, character offsets, and before/after snippets And the JSON schema is versioned (schema_version) and published via OpenAPI And responses are idempotent for identical inputs, include ETag headers, and are cacheable And p95 latency is <= 2 seconds for inputs <= 20,000 characters, with 429 and Retry-After returned on rate limit exceedance
Materiality Rules & Thresholds
"As a compliance-focused attorney, I want configurable materiality thresholds tied to rules so that re-consent is prompted only when required."
Description

Create a configurable rules engine to classify changes as material or immaterial based on clause type, jurisdiction, and firm policy. Seed with a curated rule library and citations (e.g., fee percentage changes > X%, arbitration clause addition, scope-of-services narrowing). Allow per-jurisdiction overrides, effective dating, simulation/testing (what-if) mode, and audit logs of rule evaluations. Output a deterministic materiality score and reason codes that downstream workflows (re-consent, alerts) can consume.

Acceptance Criteria
Deterministic Scoring and Reason Codes
Given a fixed rule set version "v1.0", jurisdiction "NY", and firm policy profile "Default" And a defined set of clause deltas for a retainer update When the engine evaluates the same input 10 consecutive times Then the materiality score is identical across all runs And the output includes a non-empty reasonCodes array And each reasonCode contains fields: code, message, ruleId, ruleVersion, jurisdiction, policyProfile And the output includes evaluationMetadata with ruleSetVersion = "v1.0"
Seed Rule Library with Citations
Given the seeded library includes rule "R-FEE-THRESHOLD" with at least one citation And the configured fee-change threshold is 5 percentage points When a fee clause changes from 25% to 33% Then the evaluation includes reasonCodes containing ruleId "R-FEE-THRESHOLD" And the corresponding citations array is present and non-empty with fields: citationId, source, reference, urlOrText And the materiality score reflects the application of "R-FEE-THRESHOLD" (score > 0) And the evaluationMetadata includes librarySeedVersion
Jurisdiction Overrides and Precedence
Given a global rule sets the fee-change threshold at 10 percentage points And a California (CA) override sets the fee-change threshold at 3 percentage points When a fee clause changes by 5 percentage points for jurisdiction "CA" Then the CA override rule is applied And the evaluation marks the change as material (score exceeds the configured trigger threshold for CA) And reasonCodes include the CA-specific ruleId and jurisdiction = "CA" When the same change is evaluated for jurisdiction "TX" Then the global rule is applied And the evaluation marks the change as immaterial under the global threshold And reasonCodes reference the global ruleId and jurisdiction = "TX"
Effective Dating and Temporal Evaluation
Given rule "R-ARB-ADD" (adding an arbitration clause) is effective starting 2025-09-01 And the current rule set contains a prior version without this rule When the evaluation date is 2025-08-15 Then "R-ARB-ADD" is not applied And reasonCodes do not include "R-ARB-ADD" When the evaluation date is 2025-09-15 Then "R-ARB-ADD" is applied And reasonCodes include "R-ARB-ADD" with ruleVersion effective on 2025-09-15 And evaluationMetadata.effectiveDate equals the requested evaluation date
Simulation Mode (What-If) Without Side Effects
Given what-if simulation mode is enabled for the evaluation And an identical evaluation is available in normal mode for comparison When the engine evaluates the input in simulation mode Then no audit log entry is persisted in the production audit store And no alerts, tasks, or re-consent workflows are created And the response contains mode = "simulation" and an evaluationTrace of applied rules and calculations When the engine evaluates the same input in normal mode Then side effects (audit log persistence and any triggered workflows) occur per configuration
Audit Logging of Rule Evaluations
Given an authenticated user initiates a normal-mode evaluation When the evaluation completes Then an audit log entry is created with fields: evaluationId (UUID), timestamp (ISO 8601 UTC), actorId, inputsHash, jurisdiction, policyProfile, ruleSetVersion, effectiveDate, appliedRules[], reasonCodes[], materialityScore, durationMs And the entry is tamper-evident (contains a cryptographic integrity signature) And the entry is retrievable via the Audit API by evaluationId And the entry is included in the generated audit packet for the matter
Downstream Re-Consent Trigger Consumption
Given the re-consent trigger threshold is configured at 70 And a workflow event bus is available When an evaluation returns materialityScore = 72 and reasonCodes include "R-ARB-ADD" Then a "ReConsentRequired" event is emitted within 2 seconds And the payload includes: evaluationId, score, triggerThreshold, reasonCodes[], citations[], jurisdiction, policyProfile, ruleSetVersion, effectiveDate, idempotencyKey And no event is emitted when materialityScore = 65 (below threshold) And duplicate event emissions are prevented for the same evaluationId via idempotencyKey
Acceptance Attribution & Evidence
"As a practitioner, I want incontrovertible evidence of which version a client accepted and when so that informed consent is provable."
Description

Capture and bind each acceptance to a specific clause/document version with signer identity, timestamp, IP/device fingerprint, geo (where permitted), and cryptographic hash of the content. Integrate with Briefly’s e-sign to embed consent checkpoints and produce a write-once evidence record stored immutably. Provide verification screens, tamper-evident receipts, and APIs to retrieve the acceptance trail for any matter. Ensure data retention and privacy controls comply with jurisdictional requirements.

Acceptance Criteria
Clause-Linked Acceptance Capture and Binding
Given a signer is presented with a consent checkpoint for a clause version in the e-sign flow When the signer explicitly accepts the clause Then the system records and binds: clause_id, clause_version_id, document_version_id, matter_id, signer_id/name/email/role, acceptance_id (UUIDv4), timestamp (UTC ISO 8601), IP address, device fingerprint (hashed), geo (if permitted), and content_hash (SHA-256 of exact clause text and formatting) And then geo collection occurs only if jurisdiction settings allow and the signer has consented to geo collection; otherwise geo fields are null and a reason_code is stored And then the acceptance write succeeds atomically; if any required field is missing or invalid, no record is stored and the signer sees a clear error message And then the acceptance is linked to the session and e-sign envelope ID for traceability
Write-Once Immutable Evidence Record
Given an acceptance is captured When it is persisted Then it is written to append-only storage with object lock enabled (WORM) and a stored record_hash (SHA-256 of the serialized evidence record) And then any attempt to update or delete the stored acceptance via UI or API returns HTTP 409 Conflict with error_code "IMMUTABLE_RECORD" and is audit-logged with actor, timestamp, and reason And then recomputing record_hash from persisted data matches the stored record_hash And then the audit log includes a create event with the same record_hash
Verification Screen and Tamper-Evident Receipt
Given a matter with at least one acceptance When a user opens the verification screen Then it displays per acceptance: signer identity and role, clause_id and version, document version, acceptance_id, timestamp (UTC), IP, device fingerprint summary, geo (if present), content_hash, record_hash, and verification status And then the verification status is "Verified" only if the content_hash and record_hash recompute successfully and storage immutability checks pass; otherwise "Failed" with reason And then the user can download a receipt PDF that includes all acceptance metadata, the content_hash and record_hash, a digital signature/seal, and a verification QR code/URL And then altering any byte of the receipt causes the public verification endpoint to return "Invalid Receipt" with HTTP 422
API Retrieval of Acceptance Trail
Given an authenticated and authorized client with scope "acceptance.read" When it requests GET /api/v1/matters/{matter_id}/acceptances with optional filters (date range, signer_id, clause_id, version) Then the API returns HTTP 200 with a paginated JSON list conforming to schema acceptanceTrail.v1, ordered by timestamp asc And then records include all required metadata fields plus links to receipt download and verification endpoint And then the API enforces access control so only owners or administrators of the matter can retrieve records; unauthorized requests return HTTP 403 And then when no records match, the API returns an empty list with pagination metadata, not an error And then each API call is audit-logged with client_id, matter_id, and filter parameters
Consent Checkpoints Embedded in E-Sign Flow
Given a document template contains clauses marked "requires_acceptance" When the signer proceeds through the e-sign flow Then the UI renders explicit consent checkpoints for each such clause with clear, unambiguous language and an affirmative control (e.g., checkbox) And then the final signature action remains disabled until all required clause acceptances are captured and validated And then each checkpoint binds acceptance to the exact clause version rendered by matching and storing its content_hash (SHA-256) and version_id And then if a clause version has changed since the signer’s prior acceptance and the materiality threshold requires re-consent, the signer is prompted to re-accept and a new acceptance record is captured and linked to the new version
Jurisdictional Privacy and Retention Controls
Given the matter’s jurisdiction and firm policy settings When an acceptance is captured Then data collection toggles (geo, device fingerprint granularity, IP masking) are enforced per jurisdiction, and the policy version is recorded with the acceptance And then retention metadata (retention_category and expiry_at UTC) is set according to jurisdictional schedules And then upon expiry, personal data fields (IP, device fingerprint, geo, email) are deleted or irreversibly anonymized while retaining non-personal proofs (content_hash, record_hash, timestamps) where legally permitted; actions are audit-logged And then a data subject erasure request against a signer results in the same anonymization behavior within SLA (e.g., 30 days) unless a legal hold is present, in which case the request is recorded and deferred with reason
Multi-Signer Attribution and Role Separation
Given a document requires multiple signers When each signer completes consent checkpoints Then acceptances are recorded separately per signer_id and role and do not satisfy other signers’ requirements And then the verification screen and API show per-signer acceptance status and allow filtering by signer role And then the envelope cannot be finalized until all required signers have provided required clause acceptances; the UI indicates which signer(s) are pending
Re-Consent Trigger & Workflow
"As an intake coordinator, I want automated re-consent requests sent to clients when language changes so that matters stay compliant without manual follow-up."
Description

When a material change is detected, automatically initiate a re-consent workflow: generate client-friendly summaries of changes with redlines, request acknowledgment/e-sign via SMS/email, and block downstream filing/assembly steps until resolved or appropriately overridden. Include SLA timers, automated reminders, multilingual templates, and a staff dashboard to monitor status, escalate, or document overrides with rationale and approvals. Support mobile-first flows with one-tap consent and fallback to voice consent capture where permitted.

Acceptance Criteria
Trigger Re-Consent on Material Change
Given a client has previously consented to version Vn of consent/disclosure/fee terms on matter M And a new revision Vn+1 is published with a materiality score greater than or equal to the configured threshold for M's practice area When Vn+1 is selected for assembly or the library is updated to make Vn+1 active for M Then the system generates a client-friendly summary with inline redlines between Vn and Vn+1 And sends re-consent requests via SMS and email containing a secure deep link And blocks downstream filing/assembly steps for M with status "Awaiting Re-Consent" And records the re-consent request with unique ID linked to client, matter, Vn/Vn+1 IDs, initiator, and timestamps
SLA Timers, Reminders, and Escalations
Given a re-consent request is created at t0 When the request is sent Then an SLA countdown begins (default 48 hours; configurable 1–168 hours) And automated reminders are sent at t0+24h and t0+44h, up to a maximum of 3 attempts per channel And channel failures (bounce, delivery error) are detected and retried via the alternate channel When the SLA expires without consent Then the request status updates to "SLA Breached" and an escalation task is created and assigned to the matter owner And staff are notified via dashboard alert and email
Multilingual Consent Content Delivery
Given a client's preferred language L is known and supported When generating the re-consent summary and redlines Then the content is rendered in L using the corresponding template set And all UI strings and e-sign prompts are displayed in L And if L is unsupported, English is used and the fallback is logged on the consent record And locale-specific date, time, and number formats are applied
Mobile One-Tap Consent Flow
Given a client opens the secure re-consent link on a mobile device When the consent page loads Then the client can view a condensed summary with option to expand full redlines And a single "Agree & E‑Sign" action captures consent without typing And the system records timestamp, IP, device info, and applies OTP verification if enabled And the page meets WCAG 2.1 AA tap-target and language requirements And upon consent, the matter unblocks within 5 seconds and status updates to "Consent Received"
Voice Consent Fallback (Jurisdiction-Permitted)
Given the matter's jurisdiction permits voice consent capture And the client cannot complete e-sign When staff initiates the voice consent workflow Then the approved script is presented in the client's language where available And the call audio is recorded, with explicit yes/no confirmations to each material clause and a final affirmation And an automated transcript with timestamps is generated and linked to the consent record And if the jurisdiction does not permit voice consent, the workflow is blocked and staff are notified
Staff Dashboard: Monitor, Escalate, Override
Given a user with the Consent Manager role opens the dashboard When viewing re-consent items Then they can filter by status, SLA time remaining, channel health, language, and assignee And send manual reminders or switch delivery channels And escalate items to a supervisor And perform an override only by entering rationale, selecting or entering rule citations, and obtaining a second approver And an approved override unblocks downstream steps and logs both approvers, rationale, citations, and timestamps
Audit Trail and Compliance Packet
Given a re-consent is completed or overridden When generating the audit packet Then it includes the Vn→Vn+1 redline, client-friendly summary version, consent method (e-sign or voice), delivery channel, timestamps, user IDs, device/IP, and version IDs And includes override rationale and rule citations if applicable, plus approval chain And the packet is immutable, versioned, downloadable as PDF and JSON, and attached to the matter And entries are searchable by client, matter, date, and version
Audit Packet with Rationale & Citations
"As an attorney facing an audit, I want a ready-made packet proving informed consent with rule citations so that I can demonstrate compliance quickly."
Description

Generate a comprehensive audit packet per matter that bundles: complete redline history, clause/version lineage, change rationales, evaluated materiality rules with citations, acceptance attribution evidence, and timestamps. Export as court-ready PDF and machine-readable JSON, with digital signatures and hash proofs. Store alongside the matter record and enable secure share links with access logs. Provide one-click generation from the matter, and include configurable templates to tailor the packet to jurisdictional requirements.

Acceptance Criteria
One-Click Audit Packet Generation from Matter
Given a user with permission "Generate Audit Packet" is viewing a matter with at least one finalized consent cycle When the user clicks "Generate Audit Packet" Then the system generates an audit packet including all required sections without additional input And a success notification displays with a direct link to the packet And generation completes within 30 seconds for matters with <= 200 consent revisions Given a matter is missing any required component (redline history, lineage, rationale, citations, acceptance evidence, or timestamps) When packet generation is requested Then the system blocks generation and lists the missing components and remediation steps And no packet or partial artifacts are stored Given packet generation is in progress When the user navigates away from the page Then generation proceeds server-side And a link to the completed packet appears in the matter activity feed within 60 seconds of completion
Packet Contents Completeness
Given a generated audit packet When the packet is opened Then it contains the complete redline history for all consent, disclosure, and fee clauses And it contains clause and version lineage for each clause instance And it contains change rationales linked to their corresponding revisions And it contains evaluated materiality rules with their citations And it contains acceptance attribution evidence (acceptor identity, version accepted, timestamp, device/IP if available) And it contains normalized UTC timestamps for all relevant events Given the redline history section When inspecting any diff entry Then the before and after texts are present And insertions and deletions are highlighted consistently And the entry references the clause ID, version, editor, and timestamp
Export Formats, Digital Signatures, and Hash Proofs
Given an audit packet is generated When the user exports it Then the system produces a court-ready PDF and a machine-readable JSON file And both files include a SHA-256 content hash and a platform digital signature verifiable with the platform public certificate And the PDF passes a PDF/A compliance check with no errors And the JSON validates against the published schema version referenced in the file metadata Given the export files When verifying integrity Then the stored hash values in the matter record match the computed hashes of the files And the digital signatures verify successfully
Storage and Association with Matter Record
Given a packet is successfully generated When stored Then it is associated with the originating matter record And it appears under the matter's Audit section with a version number and generated-at timestamp And the stored artifacts (PDF, JSON, hashes, signatures) are immutable and read-only Given a user with proper permissions When downloading the packet from the matter record Then the download succeeds within 5 seconds on a 20 Mbps connection for files <= 25 MB And the file names follow the pattern {MatterID}_AuditPacket_v{N}_{UTC-Timestamp}.{ext} Given an unauthorized user When attempting to access the stored packet Then access is denied and is logged as a security event
Secure Share Links with Access Logs
Given a user with share permissions When creating a secure share link for a packet Then the user can set an expiration between 1 and 365 days and an optional password And the generated link token has at least 128 bits of entropy And the link can be revoked at any time by the creator or an admin Given a shared link is accessed When a viewer opens or downloads the packet Then an access log entry is recorded with event type (view/download), timestamp (UTC), IP, and user-agent And access logs are viewable to firm admins within the matter And access to an expired or revoked link returns 410 Gone and is logged
Jurisdictional Template Configuration Applied
Given jurisdiction-specific audit packet templates are configured (including mandatory sections and citation styles) When generating a packet for a matter with jurisdiction J Then the template for J is applied And all required sections for J are present And citation formatting matches the configuration And the template version ID is recorded in the packet metadata Given no template exists for jurisdiction J When generating a packet Then the system uses the default template And surfaces a non-blocking notice to admins about the missing jurisdictional template Given a template has missing required fields When an admin attempts to save it Then validation fails with a list of missing fields and examples
Regeneration and Versioning After Revisions
Given a packet (version N) exists for a matter When new consent revisions or acceptance events occur Then a user can regenerate the packet And the new packet is stored as version N+1 without altering version N And the new packet's contents include the additional revisions and events Given multiple packet versions exist When comparing versions N and N+1 Then the metadata shows the generator, timestamp, and change summary And downloads for prior versions remain available and unchanged
Template Lineage & Impact Analysis
"As a managing attorney, I want to see which active matters are affected by a clause update so that I can proactively obtain re-consent where needed."
Description

Track template-to-clause dependencies and matter usage to compute impact when a clause or template is updated. Surface a real-time impact report listing active matters affected, required re-consent actions, and risk levels by jurisdiction. Support batch initiation of re-consent, rollback to prior approved versions, and dry-run simulations before publishing changes. Provide notifications to stakeholders and integrate with sprint planning by exposing counts of affected matters and estimated remediation effort.

Acceptance Criteria
Lineage Graph Accuracy and Completeness
Given an environment with existing templates, clauses, and matters, and lineage recomputation enabled When a template, clause, or mapping is created, updated, or deleted Then the lineage graph updates within 10 seconds and reflects 100% of known dependencies without orphaned references Given the lineage graph When queried for any template or clause ID Then it returns parent templates, child clauses, and matter usages with stable unique IDs and last-modified timestamps Given a known fixture dataset (e.g., 10 templates, 45 clauses, 120 matters) When the integrity check runs nightly Then referential integrity passes and coverage equals 100% with zero errors logged
Real-Time Impact Report for Clause Update
Given a published clause version is updated to a new draft or published version When the user opens the Impact Report for that clause or its parent template Then the system computes and displays within 5 seconds: total affected active matters, list of matter IDs, clients, jurisdictions, current consent version, required re-consent action, and impact severity Given the Impact Report When filters are applied by jurisdiction, practice area, or re-consent status Then counts and lists update correctly and export to CSV produces matching rows
Jurisdictional Risk Assessment on Impact Report
Given jurisdictional rules with thresholds and citations are configured When the impact report is generated Then each matter row includes a computed risk level (Low/Medium/High/Unknown), the rule ID, and citation; Unknown appears only when no rule exists Given two matters in different jurisdictions with equivalent clause change magnitude When the report renders Then risk levels reflect jurisdiction-specific thresholds as defined Given a change that crosses a material-change threshold for a jurisdiction When the report is generated Then the matter is flagged Re-consent Required with the triggering rule reference
Batch Re-Consent Initiation and Tracking
Given an Impact Report with selected affected matters When the user initiates batch re-consent for N matters Then N re-consent jobs are queued, deduplicated by matter, and each matter status transitions to Re-Consent Pending within 15 seconds Given the batch run When a job fails due to delivery error Then the job is retried up to 3 times with exponential backoff and surfaced in a failure report with actionable error codes Given the batch When the user views batch progress Then the UI shows counts sent, pending, failed, completed, and average time to completion; totals equal N
Rollback to Prior Approved Version with Audit Trail
Given a template with published versions V and V+1 When an authorized user triggers rollback to V and confirms Then new matters created after rollback use V, an audit entry records who, when, why, and diff summary, and the action completes within 60 seconds Given existing matters consented to V+1 When rollback occurs Then those matters are not auto-changed; the Impact Report reflects no new re-consent required unless selected manually Given rollback When the user views the audit packet Then the rollback event includes rationale and rule citations linked to the change
Dry-Run Simulation and Comparison Before Publish
Given draft changes in a template or clause When the user runs a dry-run simulation Then the system computes projected affected matters, re-consent requirements, and jurisdictional risk without notifying clients and returns results within 10 seconds Given a dry-run result saved with an ID When the corresponding change is later published Then the first post-publish Impact Report matches the dry-run within ±2% on counts and flags any variance beyond the threshold
Stakeholder Notifications and Sprint Planning Metrics
Given an impact event (publish, rollback, or saved simulation) When triggers fire Then notifications are sent to configured stakeholders within 60 seconds containing summary counts, jurisdictions, risk distribution, and estimated remediation effort Given the planning integration endpoint When a GET impact summary API call is made with a template or clause ID Then the response includes affected matter counts by jurisdiction, estimated remediation hours based on configurable per-matter multipliers, and batchable groups Given a webhook subscription for sprint tools When an impact event occurs Then a webhook is delivered with an idempotency key, payload schema v1, and retries on 5xx with exponential backoff

Provenance Tags

Field‑level origin tracking shows where each data point came from (client, delegate, OCR/ID scan, import), how it was captured (device, channel, liveness/ID result), and confidence scores. One‑tap “Why we trust this data” summaries reduce back‑and‑forth, speed corrections, and strengthen evidence in disputes or audits.

Requirements

Field-Level Provenance Capture
"As an attorney, I want each field to automatically record where it came from and how it was collected so that I can quickly assess trustworthiness and resolve disputes during intake and review."
Description

Implement a data model and capture pipeline that records, for every field, the source (client, delegate, OCR/ID scan, import), capture method (device type, browser/app, channel, IP, approximate geo, liveness/ID verification result), timestamps, collector identity, and form/template version. Support multi-source merges, retaining lineage for each contribution and subsequent edits. Integrate with mobile/web questionnaires, OCR and ID verification services, import connectors, and manual entry, including offline capture with queued sync. Provide idempotent writes, retry logic, and versioning to prevent data loss. Secure sensitive metadata with encryption and enforce least-privilege access. Expected outcome is reliable, queryable provenance attached to each data point across the intake-to-assembly flow.

Acceptance Criteria
Mobile/Web Questionnaire Capture
Given a client or delegate completes and submits a questionnaire field via web or mobile When the submission is persisted Then the field’s provenance includes: source in {client, delegate}, device_type, app_or_browser, channel, ip_address, approximate_geo, timestamp (UTC ISO 8601 with ms), collector_identity, form_id, template_version And the provenance is retrievable for that field via the provenance query API And ip_address and approximate_geo are stored encrypted at rest and decrypted only on authorized access
OCR/ID Scan Ingestion with Confidence and Liveness
Given an OCR or ID verification provider extracts a value for a mapped field When the provider result is received and processed Then the field’s provenance records: source=OCR/ID_scan, provider_name, provider_version, confidence_score (0.0–1.0), liveness_result in {pass, fail, not_performed}, device_type if available, channel=ocr_service, timestamp, collector_identity (initiator), form_id, template_version And repeated callbacks with the same provider event id or idempotency key do not create duplicate contributions And multiple extractions for the same field are stored as separate, ordered contributions with their individual confidence scores
Multi-Source Merge and Edit Lineage
Given a field receives contributions from multiple sources over time (client, delegate, import, OCR/ID, manual) When a user requests the field provenance Then an ordered event history is returned where each event contains: source, value_before, value_after, timestamp, editor/collector_identity, capture_method metadata, and event_id And the current field value equals the value of the latest non-retracted event per version rules And users can filter the history by source type and time range And retracting or rolling back a contribution preserves the original event and adds a new retraction event without destroying prior records
Offline Capture with Queued Sync and Idempotent Writes
Given a mobile user enters field values while offline When connectivity is restored and the client syncs Then events are uploaded with their original client timestamps and collector_identity And each event uses a stable client-generated id so that automatic retries do not create duplicates And server applies optimistic concurrency/version checks and responds with a conflict when the local base version is stale, including merge guidance And after simulated intermittent connectivity with three drops, no captured field values or provenance events are lost
Import Connector and Manual Entry Provenance
Given a supported import connector maps external data into fields When an import job runs Then each populated field records provenance: source=import, connector_name, connector_version, import_job_id, timestamp, and mapping reference And staff manual edits via admin UI record: source=manual_entry, collector_identity, device/browser, channel, ip_address, approximate_geo, timestamp And imported and manual events are distinguishable via source and are filterable in provenance queries
Access Control and Encryption of Sensitive Metadata
Given a user without Provenance.ViewSensitive permission requests a field’s provenance When the response is returned Then ip_address is redacted to subnet granularity and approximate_geo is rounded to city-level, and device identifiers are masked And a user with Provenance.ViewSensitive sees full values And sensitive metadata is encrypted at rest with managed keys and every access is audit-logged with user id, timestamp, and purpose And permission checks are enforced consistently in API and UI
End-to-End Queryability Across Intake-to-Assembly
Given a field captured during intake is referenced in document assembly When a retainer or first-draft document is generated Then the assembled variable retains a link to the source field’s provenance id And the provenance for that variable is retrievable and shows all contributions used to derive the final value And template version upgrades preserve a mapping so provenance remains intact across template changes And exporting a matter audit report includes the field value, contributions timeline, sources, and confidence scores for that field
Confidence Scoring Engine
"As a paralegal, I want visible confidence scores with contributing factors so that I can prioritize review on low-trust items and speed up clean cases."
Description

Compute and persist a per-field confidence score derived from source type, verification outcomes (liveness/ID match), OCR quality metrics, device signals, edit history, and conflict resolution events. Allow configurable weighting and firm-level policies to tune scoring per matter type. Provide thresholds that trigger warnings, required reviews, or auto-requests for correction. Aggregate to section- and record-level trust scores for dashboards. Expose scores and contributing factors via UI and API for downstream logic (e.g., assembly rules, e-sign gating).

Acceptance Criteria
Per-field Score Calculation and Persistence on Data Change
Given a field with captured data and provenance attributes (source type, device, channel, verification outcomes, OCR quality metrics, edit history, conflict events) And active firm default weights are configured When the field is created or updated by any source (client, delegate, OCR/ID scan, import, staff) Then the engine computes a deterministic confidence score in the range 0–100 using the active weights And persists the score, contributing factor values, applied weights version, and a UTC timestamp with the field record And appends a prior-score snapshot to an immutable audit log including actor and reason And the updated score is available to UI and API consumers within 300 ms of the update event
Weighting Configuration and Firm Policy Overrides by Matter Type
Given an admin configures weight sets per matter type and a global default When a matter is assigned a matter type Then the engine applies that matter type’s weight set to all score computations for that matter And if any factor weight is missing, the global default for that factor is applied And the sum of weights validates to 100% and each weight is within allowed bounds; otherwise the configuration save is rejected with a descriptive error And changes to weight sets are versioned; new versions apply only to subsequent computations, leaving historical scores unchanged
Threshold-Based Warnings, Reviews, and Auto-Correction Requests
Given thresholds T_warn > T_review > T_fix are configured for the matter type When a field score is < T_warn and >= T_review Then a non-blocking warning is displayed in the UI and a low_trust flag is set in API responses for that field When a field score is < T_review and >= T_fix Then the field is marked requires_review and submission of the assembled packet is blocked until a reviewer approves When a field score is < T_fix Then a single automated correction request is sent to the data contributor via their last active channel with rate limiting (max 1 per 24h) and retry policy (up to 3 attempts) And all triggered events are logged with timestamp, threshold type, and actor; clearing occurs automatically when the score rises above the relevant threshold
Aggregated Section and Record Trust Scores for Dashboards
Given per-field scores exist for a matter When computing a section trust score for N fields Then the section score is the weighted average using section configuration; if none is set, fields are equally weighted and fields missing mandatory provenance are excluded When computing a record-level trust score Then the record score is a weighted aggregation of section scores according to dashboard configuration And section and record scores update within 1 second of any constituent field score change And dashboard widgets display 0–100 scores with color bands by thresholds and support filtering by threshold bands and matter type
UI Exposure of Scores and Contributing Factors
Given a permitted user views a field in the intake editor When they open “Why we trust this data” Then the UI shows the numeric score (0–100), confidence band label (High/Medium/Low), and a breakdown of factors: source type, verification outcomes (liveness/ID match), device/channel signals, OCR quality metrics, edit history, conflict resolution events And each factor displays its raw measurement and weight contribution (+/−) to the final score And the panel is accessible (keyboard navigable, screen-reader labels) and localizes numbers and dates And the display updates within 300 ms after a score recalculation without a full page reload
API Exposure and E-sign Gating Integration
Given an authenticated client requests GET /v1/provenance/{recordId} Then the response includes per-field scores, section and record scores, contributing factors, active weight version, thresholds, and trust flags, conforming to the published schema And the endpoint supports fields= and min_score= query parameters for server-side filtering When a client requests POST /v1/esign/{recordId} Then the API returns 409 (LOW_TRUST) if any required field is below the configured e-sign threshold for that matter type; otherwise 201 is returned And all provenance and e-sign endpoints meet P95 latency <= 500 ms on records up to 1,000 fields and are idempotent
Edit History and Conflict Resolution Impact on Scores
Given a field has multiple edits from different actors or sources When a manual edit overrides an OCR/extracted value without supporting verification Then the score is reduced by the configured manual_override penalty within allowed bounds When a reviewer resolves a conflict with documented approval Then the score is increased by the reviewer_approval boost capped by max_after_review And the audit log records before/after scores, deltas, reason codes, actor IDs, and timestamps for each change
One-Tap Trust Summary
"As an attorney on mobile, I want a one-tap explanation of a field’s trust signals so that I can answer client or opposing counsel questions without digging through logs."
Description

Deliver a contextual UI affordance on each field and in document previews that opens a concise, human-readable explanation of why the data is trusted, including source, capture context, verification results, and confidence score breakdown. Provide quick actions to request a correction, re-run verification, or annotate with a rationale. Ensure mobile-first interaction (single tap), accessibility compliance, and copy-to-clipboard sharing for email or filings. Localize text and support templated phrasing aligned to firm tone.

Acceptance Criteria
Mobile One‑Tap Trust Summary on Field
Given a mobile device with viewport width ≤ 480px and a form field that has provenance When the user taps the Trust icon once Then the Trust Summary opens as a modal within 300 ms and is dismissible by tapping outside or using the system back action, returning focus to the Trust icon And the modal height is ≤ 90% of the viewport and content is vertically scrollable And if network latency is up to 1 s, a skeleton loader appears within 100 ms until content is rendered, with time to first content ≤ 1.2 s on 4G
Content Completeness: Source, Context, Verification, Confidence
Given a field with provenance recorded When the Trust Summary is opened Then it displays: source type (client, delegate, OCR/ID scan, import), capture method (device, channel), verification results (e.g., liveness/ID match pass/fail), timestamp (ISO 8601), last actor (user/system), and a confidence score breakdown (0–100) by component And if multiple sources contributed, the summary shows each source’s percentage contribution and the final weighted score And if no verification has run, the Verification section states "Not run" and shows a call to action to run verification And numerical scores are displayed with 2 significant digits and scores below the firm threshold are visually flagged
Quick Actions: Request Correction, Re‑Verify, Annotate
Given the Trust Summary is open for a field When the user taps Request Correction Then a message composer opens prefilled with field label, current value, and provenance excerpt, and on send the status is recorded as "Correction Requested" with a success toast within 2 s When the user taps Re‑run Verification Then the system triggers verification, shows progress, and on success updates verification results and timestamp in the summary; on failure shows an actionable error and Retry within the same modal When the user adds an Annotation with a rationale of at least 5 characters Then the annotation is saved with author and ISO timestamp, visible in the summary, and editable for 10 minutes after creation
Accessibility Compliance: WCAG 2.1 AA (Mobile‑First)
Given a screen reader is enabled When focus reaches the Trust icon Then its accessible name is "Why we trust this data for [Field Label]", role=button, and it exposes a hint to "double‑tap to open" When the modal opens Then focus moves to the modal header, the title is announced, focus is trapped within the modal, and closing returns focus to the originating icon And touch targets are ≥ 44×44 dp, text and icon contrast ratios are ≥ 4.5:1, all icons have accessible labels, images have alt text, and dynamic status updates use an ARIA live region (polite) And all actions are operable via keyboard (Tab/Shift+Tab/Enter/Escape) on devices with hardware keyboards
Copy‑to‑Clipboard Share from Trust Summary
Given the Trust Summary is open When the user taps Copy to Clipboard Then a plain‑text summary containing field label, value, source, capture context, verification results, confidence breakdown, and ISO timestamp is copied, delimited by new lines, with total length ≤ 2000 characters And a confirmation toast "Copied" appears within 1 s And any UI redactions are preserved in the copied text and no additional PII beyond the field value and provenance descriptors is added And if the platform blocks clipboard access without a gesture, the user is prompted with an inline instruction to tap to allow and the copy only proceeds after the tap
Localization and Firm Tone Templates
Given the firm default language and tone template are configured When the Trust Summary is opened Then all static text renders in the selected language (en, es, fr) using the firm’s tone templates with resolved placeholders for field labels/values and localized dates/numbers And switching language updates all strings without page reload within 500 ms and missing translations fall back to English while logging a missing key event And template edits published by an admin are reflected in the UI within 5 minutes and variables are validated so that unresolved placeholders are not shown to end users
Document Preview: Trust Summary on Merged Fields
Given a document preview showing merged field values When the user taps the Trust icon overlay adjacent to a merged value Then the Trust Summary opens anchored to the preview and displays the provenance of the underlying field mapping And for merged values composed from multiple fields, the summary lists each contributing field with its provenance and confidence, and allows navigation between them And when the preview is zoomed or scrolled, the Trust icon overlay remains positioned relative to the value and remains accessible via tap and keyboard focus
Tamper-Evident Audit Export
"As a litigator, I want an exportable, defensible audit trail for any field so that I can substantiate data origin and handling if challenged."
Description

Generate a time-ordered, tamper-evident audit log per field capturing source events, device/channel metadata, verification results, edits with reason and actor, and pre/post values. Provide export to PDF and JSON with cryptographic hashing, detached signature, and chain-of-custody metadata. Enable selective redaction of sensitive details while preserving integrity proofs. Attach exports to retainers and court-ready drafts, and store as immutable artifacts for disputes or audits.

Acceptance Criteria
Field-Level Audit Log Generation
Given a matter field with at least three provenance events from different sources (client, delegate, OCR/ID scan, import) When I generate the tamper-evident audit log for that field Then the log is returned strictly time-ordered (ascending sequence) with contiguous sequence numbers starting at 1 and no gaps And each event includes: origin type, actor ID, actor role, channel (web/mobile/API/import), device metadata (device type, OS, app/browser version), IP address, verification results (liveness/ID outcome and confidence), RFC 3339 timestamp with timezone, pre-value, post-value, and edit reason And the total event count equals the count in the system of record for the field And timestamps are monotonic non-decreasing; ties must have increasing sequence numbers And generation completes in ≤ 2 seconds for up to 100 events
JSON and PDF Export With Detached Signature
Given I request an audit export for a matter When the export completes Then two files are produced: <matterId>-audit.json and <matterId>-audit.pdf And a detached signature file <matterId>-audit.json.sig is produced using Ed25519 over the SHA-256 hash of the canonical JSON And the PDF embeds the JSON SHA-256 hash and detached signature metadata and displays an integrity summary page And the export includes chain-of-custody metadata: exportId (UUIDv4), generator version, requester userId and role, request timestamp, requester IP, and device fingerprint And verifying the signature with the published public key returns Valid for the unmodified JSON and Invalid after any single-byte modification
Selective Redaction With Integrity Preservation
Given I select specific fields or patterns (e.g., SSN, DOB) to redact before export When the export is generated Then redacted values in PDF are replaced with [REDACTED] and in JSON with a placeholder object {"redacted": true, "reason": <text>} And the canonical hash and signature are computed over the full unredacted JSON plus a redaction manifest containing per-field cryptographic commitments (salted SHA-256 digests of original values) And the export includes a redaction log with actor, reason, timestamp, and scope of redaction And attempting to redact protected fields (exportId, signatures, event sequence, timestamps) is rejected with an error And third-party verification can confirm that redacted fields existed by validating commitments without revealing content
Attachment to Retainer and Court-Ready Drafts
Given a matter with a generated audit export When a retainer agreement or court-ready first draft is assembled Then the latest audit export is attached to the document package as a separate file and referenced by exportId within document metadata And the attachments are included in the e-sign envelope sent to the client And the document viewer shows a Why we trust this data link that opens the export integrity summary And removing or altering the attachment after sending is blocked by the system
Immutable Artifact Storage and Retention
Given an audit export is generated When it is stored Then it is written to immutable, content-addressable storage keyed by the JSON SHA-256 hash with object lock enabled And it cannot be overwritten, edited, or deleted by non-admin users; admin deletion requires dual authorization and is logged as an audit event And a minimum retention policy of 7 years is set and visible in artifact metadata And retrieving the artifact by hash returns bytes identical to the original export
Third-Party Verification and Public Key Distribution
Given a third party has <matterId>-audit.json and <matterId>-audit.json.sig When they fetch the current verification public key from the well-known endpoint over HTTPS Then running the provided verification command outputs Valid signature and displays exportId, matterId, generator version, and timestamp And altering either file or using a mismatched key outputs Invalid with a reason code And the public key endpoint exposes keyId, createdAt, and expiresAt to support rotation
Document Provenance Badges
"As a reviewer, I want unobtrusive origin markers in assembled drafts so that I can spot fields needing verification before sending for e-sign."
Description

Render origin indicators for populated fields within assembled documents (inline badges, margin callouts, or footnotes) showing concise source labels such as “Client mobile”, “ID OCR”, or “Imported from CRM”, with hover/tap to view details. Provide template-level configuration to toggle visibility per field/section and to choose presentation style. Ensure badges do not disrupt pagination or e-sign anchors and are excluded or minimized in final filings when configured.

Acceptance Criteria
Inline Badge Rendering With Hover/Tap Details
- Given an assembled document with fields populated from multiple sources, When the presentation style is set to Inline, Then each populated field displays a concise provenance badge label matching its source (e.g., "Client mobile", "ID OCR", "Imported from CRM"). - Given a badge is visible, When the user hovers (desktop) or taps (mobile), Then a popover shows source entity, capture method (device, channel), verification result (e.g., liveness/ID), confidence score (0–100), and timestamp. - Given the popover is open, When the user dismisses it via Esc, tap outside, or close control, Then the document layout does not reflow and focus returns to the originating field. - Given a field lacks provenance, When the document renders, Then no badge is shown. - Given a badge is rendered, When read by a screen reader, Then the badge exposes an accessible name announcing the label and an action to "show details".
Template-Level Visibility Toggle Per Field and Section
- Given a template with Section-level default = Off and Field-level override = On for Field A, When assembling, Then only Field A shows a badge in that section. - Given a template with Section-level default = On and Field-level override = Off for Field B, When assembling, Then Field B shows no badge while other fields in that section show badges. - Given conflicting settings, When both Section and Field levels are configured, Then Field-level override takes precedence. - Given visibility settings are changed, When the template is saved and reopened, Then the settings persist and apply to subsequent assemblies.
Presentation Style Selection: Inline, Margin Callouts, Footnotes
- Given a template, When the presentation style is set to Margin, Then badges render as margin callouts aligned with their source fields without obscuring body content. - Given a template, When the style is set to Footnotes, Then superscript markers appear at fields and corresponding footnotes are generated at the bottom of the same page. - Given multiple fields on a page, When Footnotes style is used, Then footnote numbering is sequential per page and resets on each new page. - Given the style is changed, When the document is reassembled, Then the selected style applies consistently to all fields configured as visible.
Pagination and Layout Stability
- Given a baseline assembly with badges disabled, When badges are enabled in Inline or Margin style, Then the total page count, paragraph line breaks, and table row pagination are identical to the baseline (0 difference). - Given Footnotes style, When badges are enabled, Then main body pagination remains identical to the baseline and only the footnote area is utilized; if footnotes overflow the page, they continue on the next page without shifting main content. - Given badges are rendered, When exporting to PDF and DOCX, Then the exported pagination matches the on-screen pagination exactly.
E‑Sign Anchor Integrity
- Given a template containing e‑sign anchors (by ID or text tags), When badges are enabled in any style, Then the anchors’ page numbers, coordinates, and associations remain unchanged compared to an assembly with badges disabled. - Given an e‑sign preview, When the document is uploaded to the e‑signature provider, Then all anchors are detected and mapped exactly as in the baseline (100% match). - Given badges are toggled on/off, When comparing the generated e‑sign manifest, Then no additional anchors are introduced and none are removed.
Final Filing Export: Exclude or Minimize Badges
- Given export mode Final Filing and template option Exclude Badges, When exporting to PDF/DOCX, Then no inline labels, margin callouts, superscripts, or provenance footnotes appear, and no hidden annotations are present in the file. - Given export mode Final Filing and template option Minimize Badges, When exporting, Then inline and margin badges convert to numbered footnotes containing only the concise source labels; no popover details are included. - Given minimized output, When reviewing page layout, Then minimized footnotes do not alter main body pagination and do not exceed one line per badge; if overflow occurs, the system consolidates duplicate labels per page into a single footnote entry.
Provenance-Aware Integrations API
"As an operations lead, I want integrations that preserve and transmit provenance so that trust signals are maintained across systems."
Description

Expose APIs/webhooks and SDK helpers that accept and emit provenance metadata alongside field values for imports from CRMs, data providers, and prior matters. Provide mapping utilities, schema validation, and safe defaults when external sources lack complete provenance. Support backfill migration of historical records with partial provenance and clearly flag inferred versus asserted metadata. Enforce authentication, scoping, and rate limits to protect sensitive data.

Acceptance Criteria
Inbound Import with Complete Provenance
- Given a valid API key with scope "imports:write" When the client POSTs to /v1/imports with fieldValues[] each including provenance.source.type in {client, delegate, ocr_scan, id_scan, import, prior_matter}, provenance.capture.{method,device,channel}, provenance.verification.idCheck.result in {pass, fail, unverified, unknown}, provenance.confidence.score between 0.0 and 1.0 inclusive, and provenance.timestamp in ISO-8601 UTC Then the API responds 202 Accepted with importId and stores each field with the exact provided provenance values - Given the created record id When the client GETs /v1/records/{id}?include=provenance Then the response returns each field with value and identical provenance as submitted
Partial Provenance Defaults on Import
- Given a valid API key with scope "imports:write" When the client POSTs /v1/imports with fieldValues[] missing provenance entirely Then the API stores the fields with provenance defaults: source.type="external", capture.channel="api", capture.device="unknown", capture.method="unknown", verification.idCheck.result="unknown", confidence.score=null, and provenance.flags.inferred=true - Given a payload with partial provenance (e.g., only source.type provided) When POST /v1/imports Then provided provenance attributes are preserved, missing attributes are defaulted as above, and provenance.flags.inferred=true only for attributes that were defaulted - Given a payload with structurally invalid provenance (wrong types, out-of-range scores, invalid enums) When POST /v1/imports Then the API responds 422 Unprocessable Entity with code "PROV_SCHEMA_INVALID", per-field error pointers, and no partial write occurs
Outbound Webhooks Emit Provenance
- Given a webhook subscription with eventType=record.updated, include=provenance, and a valid signing secret When a record field is created or updated via any channel (API, import, OCR/ID scan) Then the delivered webhook contains only the changed fields with their current values and full provenance metadata; the X-Briefly-Signature header verifies the payload; the event includes eventId and occurredAt timestamps - Given include=provenance is not set on the subscription When a record changes Then the webhook payload omits provenance metadata
Mapping Utilities and SDK Helpers for Provenance
- Given a mapping configuration that maps external source fields to Briefly schema fields and provenance paths When the mapping is validated Then validation passes only if all target fields exist, enum values are valid, transforms compile, and required provenance paths are well-formed; otherwise a report is returned with codes {MAP_FIELD_UNKNOWN, MAP_ENUM_INVALID, MAP_TRANSFORM_ERROR} - Given the official SDK (JavaScript/TypeScript and Python) When a developer constructs a RecordImport using SDK types Then compile-time or runtime validation enforces provenance schema (enums, ranges, ISO-8601) and helper defaults match API defaults for any missing attributes - Given a mapping preview request with a sample payload When executed through the mapping utility Then the preview displays the resulting field values and provenance per field without writing data
Historical Backfill with Partial Provenance
- Given a backfill job is created with a batch file (CSV or NDJSON) containing records with optional provenance When the job runs Then records are imported asynchronously, missing provenance attributes are defaulted per policy, and each affected field is tagged with provenance.flags.backfill=true - Given the job completes When the client GETs /v1/backfills/{jobId} Then the response includes counts for imported, failed, and skipped records, and a downloadable error report with line numbers and validation codes for failures - Given a backfill record conflicts with an existing record and the conflict policy is "skip" When the job processes that record Then the existing record remains unchanged and the conflict is logged with code "BACKFILL_CONFLICT_SKIPPED"
Inferred vs Asserted Flagging and Auditability
- Given a field imported with explicitly provided provenance When retrieved via GET /v1/records/{id}?include=provenance Then provenance.assertion="asserted", provenance.flags.inferred=false, and provenance.reasonCodes includes "PROV_ASSERT_EXTERNAL" where applicable - Given a field where any provenance attribute was defaulted or derived by the system When retrieved Then those attributes have provenance.assertion="inferred" and provenance.reasonCodes include specific causes such as {"PROV_DEFAULT_MISSING","PROV_DERIVED_CHANNEL"} - Given an audit log request for a record When GET /v1/records/{id}/audit?include=provenance Then the response shows a chronological history of value and provenance changes with who, when, source, and before/after diffs
Authentication, Scoping, and Rate Limits for Provenance Endpoints
- Given an API key lacking the "records:read:provenance" scope When requesting include=provenance on any read endpoint Then the API responds 403 Forbidden with code "INSUFFICIENT_SCOPE" - Given an API key with scopes {"imports:write","records:read:provenance"} When calling write and read endpoints Then writes succeed and provenance is only returned when include=provenance is explicitly set - Given the client exceeds 600 requests per minute per API key or 50 concurrent imports per tenant When additional requests are sent Then the API responds 429 Too Many Requests with a Retry-After header and no mutation occurs on throttled write requests - Given a webhook subscription attempt from an org without "webhooks:provenance" permission When include=provenance is specified Then creation fails with 403 Forbidden and code "INSUFFICIENT_PERMISSION"
Privacy & Access Controls for Provenance
"As a firm administrator, I want fine-grained controls over who can see provenance details so that we protect client privacy and remain compliant."
Description

Implement role- and matter-based access controls that govern visibility of provenance details (e.g., device, IP, geo, liveness results) for internal staff, clients, and external parties. Provide client consent capture and policy-driven retention for sensitive metadata. Add export redaction presets and audit access logging with alerts for anomalous viewing. Ensure encryption at rest/in transit and alignment with applicable privacy regulations for the firm’s jurisdictions.

Acceptance Criteria
Internal Role- and Matter-Based Access Enforcement
- Given a staff user is assigned to Matter A with Role "Attorney", when they open a client's provenance panel for Matter A, then all provenance fields permitted to Role "Attorney" are visible and fields outside their permission set are redacted with labels. - Given a staff user is not assigned to Matter A, when they attempt to access provenance for Matter A by URL or API, then access is denied with 403 and no field values are returned. - Given a staff user’s role is changed or they are added/removed from a matter, when permissions are updated, then provenance visibility reflects the change within 60 seconds across UI and API. - Given any provenance access decision is made, when the page loads, then the decision is enforced at field level and the decision is logged with user, role, matter ID, and field IDs.
Client Consent and Portal Visibility Gating
- Given a client has not granted consent to view sensitive provenance metadata, when they open "Why we trust this data" in the client portal, then only non-sensitive summaries are shown and IP, device, geo, and liveness details are hidden. - Given a client grants consent via e-sign of the provenance consent form, when they return to the same view, then sensitive provenance details become visible according to firm policy immediately and an audit entry records consent version, timestamp, and IP. - Given a client revokes consent, when they save the revocation, then sensitive details are hidden within 5 minutes across UI and API, and downstream exports use the "No Sensitive Provenance" preset by default.
Export Redaction Presets and Preview
- Given a staff user initiates an export for a matter, when they select the "Court Filing" preset, then exported files contain no IP address, exact geo, device ID, or liveness raw images/videos and these fields are removed or tokenized per preset definition. - Given a staff user selects "Opposing Counsel" or "Client Copy" preset, when they preview the export, then redactions are visually indicated and the preview matches the final exported documents and JSON. - Given a custom preset is created by an admin, when it is applied, then only fields included by the preset appear in the export and the preset name and hash are recorded in the audit log. - Given any export completes, when the download link is generated, then an audit entry with user, matter, preset, field counts redacted, and timestamp is recorded and retained per audit policy.
Policy-Driven Retention and Legal Holds
- Given a firm retention policy of 180 days for sensitive provenance metadata is configured for Jurisdiction X, when a metadata item reaches 181 days with no legal hold, then it is purged from primary storage and search indices automatically. - Given backups exist, when purge executes, then the item is also scheduled for deletion from backups within 30 days and this is recorded in a purge report. - Given a legal hold is applied to a matter, when the purge job runs, then items under hold are not deleted and are marked "On Hold" with reason and date. - Given retention policies vary by jurisdiction and matter type, when a matter is tagged with Jurisdiction Y and Type Z, then the correct retention schedule is applied and visible to admins in policy reports.
Audit Logging and Anomalous Viewing Alerts
- Given any user views, searches, or exports provenance fields, when the action occurs, then an immutable audit log entry is created containing user ID, role, matter ID, client ID, field IDs, action, timestamp (UTC), IP, device, channel, and success/failure. - Given a user views more than 50 provenance records across 5 distinct matters within 10 minutes, when this threshold is exceeded, then a high-severity alert is sent to security admins within 2 minutes via email and in-app notification. - Given a user accesses provenance from an atypical geo or outside firm business hours, when the access occurs, then a medium-severity alert is created and visible in the security dashboard with recommended actions. - Given alert thresholds are updated by an admin, when changes are saved, then new thresholds take effect within 60 seconds and are versioned in the audit log.
Encryption In Transit/At Rest and Key Management
- Given provenance data is stored, when it is written to databases, object storage, and logs, then it is encrypted at rest with AES-256 using a managed KMS and per-tenant keys are supported and configurable by firm. - Given provenance data is transmitted, when API or web/mobile clients connect, then TLS 1.2+ is enforced with strong cipher suites, HSTS is enabled for web, and weak ciphers/protocols are disabled. - Given key rotation is scheduled annually or upon incident, when rotation occurs, then access to existing data continues without downtime and rotation events are logged with key IDs and timestamps. - Given backups and search indices exist, when audited, then they are confirmed encrypted with the same or stronger standards as primary storage.
Regulatory Alignment and Data Subject Rights
- Given a firm operates in configured jurisdictions (e.g., GDPR/EU, CCPA/CPRA/CA), when a data subject access request is submitted, then the system can export all provenance data about the subject within 7 days in a machine-readable format excluding protected attorney work product. - Given a deletion request is valid and no legal hold applies, when it is processed, then sensitive provenance metadata is deleted within 30 days across primary and backup systems, with an auditable certificate of deletion. - Given consent is required under applicable law, when consent is captured, then the record includes purpose, scope, jurisdiction, versioned policy text, timestamp, and IP, and is retrievable for audits. - Given EU data localization is enabled for a firm, when provenance is stored, then all EU client provenance is kept in EU regions and cross-border transfers are blocked unless appropriate safeguards are configured.

Regulator Pack

One‑click, pre‑indexed export purpose‑built for bar and ethics inquiries: a PDF/A binder with Bates‑style pagination plus machine‑readable JSON, checksums, and a lightweight verifier. Includes a matter timeline, key consents, versioned drafts, payment authorizations, and access history—organized to answer common questions in minutes, not days.

Requirements

One-Click Regulator Export Orchestration
"As a solo consumer-law attorney, I want to generate a regulator-ready export in one click so that I can respond to bar/ethics inquiries within minutes without manual collation."
Description

Orchestrate end-to-end generation of the Regulator Pack for any selected matter: collect all relevant artifacts (retainer, signed consents, version history, payment authorizations, messages, attachments, and access logs), normalize metadata, build the PDF/A binder and canonical JSON manifest, compute checksums, and package everything into a tamper-evident archive. Run as an asynchronous background job with progress indicator, error surfaced toasts, retry/resume on transient failures, and idempotency to prevent duplicates. Provide web, mobile, and API entry points, with completion notifications and a secure, expiring download link. Record export details in the matter’s audit log, including scope, redactions applied, and the bundle checksum.

Acceptance Criteria
Web One‑Click Export with Progress and Expiring Link
Given an authenticated attorney user with access to a specific matter When the user clicks "Export Regulator Pack" in the web app Then an asynchronous export job is enqueued exactly once for that matter And a progress indicator becomes visible within 1 second and updates at least every 5 seconds from 0% to 100% And on completion the UI displays a success notification and a secure download link And the download link is signed, single-use, and expires after the configured TTL (default 72 hours) And attempting to reuse the link or access it after expiry returns HTTP 403 and is recorded in the audit log
Mobile Export Start and Resume after App Background
Given an authenticated user initiates an export from the mobile app When the app is backgrounded or the device briefly loses connectivity during export Then the server-side job continues without user intervention And reopening the app shows the current job progress without creating a new job And the user receives an in-app notification (and push if enabled) on completion with the same secure expiring link And download succeeds from mobile within the link's TTL
API Idempotent Export Request
Given a client sends POST /api/matters/{matterId}/regulator-export with an Idempotency-Key header and identical payload When the request is retried within 24 hours due to client or network retries Then the API returns 200 with the original jobId and status without creating a duplicate export And concurrent submissions with the same Idempotency-Key yield a single job across all instances And if a duplicate request arrives without an Idempotency-Key while an identical job is in-progress for the same matter, the API returns 202 with the existing jobId And all responses include a stable job status endpoint for polling
Complete Artifact Collection and Metadata Normalization
Given a matter contains a retainer, signed consents, versioned drafts, payment authorizations, messages, file attachments, and access logs When the Regulator Pack export runs Then all available artifact classes are included in the output And any missing artifact class is listed in the manifest under missingArtifacts with a reason And metadata is normalized to the canonical schema: ISO 8601 UTC timestamps, MIME types for files, UUIDs for principals, and normalized filenames And Bates-style pagination is applied sequentially and zero-padded across the entire PDF/A binder And configured redactions are applied consistently and enumerated in the manifest
Tamper‑Evident Archive, PDF/A Binder, and Manifest Integrity
Given the export job completes When the produced archive is validated with the lightweight verifier Then the PDF binder validates as PDF/A compliant and includes a table of contents and bookmarks to major sections And a canonical JSON manifest (schema version 1.0.0) is present and validates against its JSON Schema And SHA-256 checksums are present for every contained file and match recomputation And an archive-level SHA-256 checksum is recorded in the manifest and matches recomputation And the verifier exits with code 0 on success and nonzero with a diagnostic message on any integrity failure
Retry/Resume on Transient Failures with User Feedback
Given an export job encounters a transient error (e.g., HTTP 5xx, network timeout, or rate limit) When the error occurs during any step (collection, normalization, rendering, packaging, or upload) Then the system retries the failed step with exponential backoff up to 5 attempts without duplicating artifacts And progress and partial results are checkpointed so the job resumes from the last successful step And the user sees a non-blocking toast on first retry and a descriptive error with retry option on terminal failure And a manual retry within 24 hours resumes the same job context rather than starting from scratch
Audit Log Records Export Scope, Redactions, and Checksums
Given an export job completes successfully or fails terminally When the system writes the audit entry for the matter Then the audit log records: timestamp, actor, matterId, jobId, scope (artifact classes included/excluded), redactions applied, manifest schema version, bundle checksum, download link id (if created), and outcome (success/failure) And access to view the audit entry is restricted to authorized roles And failure entries include an error code and correlation id for troubleshooting
PDF/A Binder with Bates Pagination and Index
"As a responding attorney, I want a clearly paginated, standards-compliant binder so that reviewers can locate evidence quickly and accept the file without format issues."
Description

Generate a single PDF/A-2b compliant binder containing a cover page, scope statement, table of contents, section dividers, bookmarks, and continuous Bates-style pagination across all pages. Support configurable Bates prefix and zero-padded width, page headers/footers with matter ID and export date, and an index mapping each document to its Bates page range. Render included items (retainer, consent artifacts, versioned drafts with diffs, payment authorizations, and correspondence excerpts) with standardized layouts and embedded source metadata. Validate PDF/A compliance and embed XMP metadata linking to the JSON manifest and bundle checksums.

Acceptance Criteria
Generate Single PDF/A-2b Binder for Regulator Export
Given a matter containing a retainer, consent artifacts, versioned drafts, payment authorizations, and correspondence excerpts When the user initiates the Regulator Pack export Then a single file {MatterID}_Regulator_Binder.pdf is created And the file conforms to PDF/A-2b as verified by veraPDF with 0 errors and 0 warnings And the binder contains a cover page, scope statement, table of contents, section dividers, and bookmarks And all fonts are embedded and no external content references or transparency violations exist
Continuous Bates Pagination With Configurable Prefix and Width
Given Bates prefix "BRF" and zero-padded width 7 are configured When the binder is generated Then every page displays a Bates number in the format BRF-0000001, BRF-0000002, ... in the page footer And numbering starts at 1 on the first page and increments by 1 across the entire binder without resets, gaps, or duplicates And changing the configured width to 6 results in BRF-000001 formatting across all pages And if no prefix is provided, the default system prefix is applied
Matter ID and Export Date in Page Headers/Footers
Given Matter ID "M-12345" and export timestamp "2025-08-18T14:05:00Z" When the binder is generated Then each page header or footer contains "Matter: M-12345" and "Exported: 2025-08-18T14:05:00Z" in ISO 8601 UTC And the same values appear consistently on every page of the binder And headers/footers do not overlap document content and remain within printable margins
Document Index Maps Each Included Item to Bates Page Range
Given the binder includes multiple items producing N pages When the index is generated Then the index lists each included item with its title, type, created timestamp, and Bates range (e.g., BRF-000010–BRF-000025) And for each item, the recorded start and end Bates numbers match the actual first and last page of that item in the binder And no two items share any Bates page within their recorded ranges And only included items are indexed; front matter (cover, scope, TOC, dividers) is excluded from the index
Standardized Rendering and Embedded Source Metadata for Included Items
Given each included item has source metadata (source filename, source identifier, created by, created at, SHA-256) When the binder is generated Then each item uses the standardized layout for its type (retainer, consents, versioned drafts with diffs, payment authorizations, correspondence excerpts) And versioned drafts render the latest version followed by redline diffs against the immediately prior version(s) And each item's first page displays Source Filename and SHA-256, and the same values are embedded as PDF metadata for that item's page range And all included items render without truncation, with correct page breaks and readable fonts
Bookmarks and Table of Contents Navigate to Correct Pages
Given section dividers exist for Retainer, Consents, Drafts, Payments, and Correspondence When the binder is opened in a PDF viewer Then the bookmarks panel shows a top-level entry for each section divider and child entries for each included item And selecting any bookmark navigates to the exact first Bates page of that section or item And the table of contents lists each section and item with the correct starting page number that matches the binder's pagination
XMP Metadata Links Binder to JSON Manifest and Checksums
Given a JSON manifest and bundle checksums are generated for the export When the binder is generated Then the PDF includes XMP metadata with pdfaid:part=2 and pdfaid:conformance=B And dc:identifier equals the Matter ID, and xmp:CreateDate equals the export timestamp in UTC And briefly:manifestUri points to the JSON manifest location (or embedded filename) and briefly:bundleSha256 equals the bundle's SHA-256 checksum And the XMP extension schema for the "briefly" namespace is defined and passes PDF/A validation And XMP values exactly match the JSON manifest and computed checksums
Canonical JSON Manifest and Checksums
"As a compliance officer, I want a structured manifest with checksums so that I can programmatically verify completeness and integrity of the exported evidence."
Description

Produce a versioned, machine-readable JSON manifest enumerating all bundle contents with canonical IDs, source references, timestamps, authors, and Bates page ranges. Include SHA-256 checksums for each included file and the final binder, plus an overall bundle checksum. Provide JSON Schema for validation and embed both the schema and the manifest inside the archive. Ensure deterministic ordering and stable identifiers to enable automated verification, deduplication, and chain-of-custody auditing.

Acceptance Criteria
Deterministic Re-Export Produces Identical Manifest and Bundle Checksum
Given the same input matter state and configuration When the Regulator Pack is exported twice at different times Then manifest.json bytes are byte-for-byte identical across exports And the binder PDF/A bytes are byte-for-byte identical across exports And the overall bundle checksum value is identical across exports And manifest entries are ordered lexicographically by canonical_id with no deviation And all canonical_id values are unchanged across exports
Stable Canonical IDs Across Exports
Given an existing exported bundle and a subsequent export where no underlying files have changed When generating the new manifest.json Then every unchanged item retains the same canonical_id And every unchanged item retains the same version value And every unchanged item retains the same sha256 checksum And any changed item retains the same canonical_id but has an incremented version and a new sha256 checksum
Per-Item Metadata Completeness and Bates Continuity
Given a completed export When inspecting manifest.json entries Then each entry includes canonical_id, source_reference, author, created_at (UTC ISO 8601), updated_at (UTC ISO 8601), mime_type, size_bytes, bates_start, bates_end, and sha256 (64-char lowercase hex) And bates_start and bates_end are present and numeric for all paginated items And bates ranges across all paginated items are contiguous, non-overlapping, and start at the first binder page And the final bates_end equals the total number of pages in the binder
Checksums for Entries, Binder, and Overall Bundle
Given the exported archive When recomputing SHA-256 for each included file listed in manifest.json Then each recomputed checksum matches the sha256 recorded in the manifest When recomputing the SHA-256 of the binder PDF/A Then it matches the binder_sha256 recorded in the manifest When recomputing the overall bundle checksum according to manifest.meta.bundle_checksum.algorithm Then the result matches manifest.meta.bundle_checksum.value exactly And all checksum fields are 64-character lowercase hexadecimal strings
Manifest Validates Against Embedded JSON Schema
Given the embedded JSON Schema at /manifest/schema.json And the manifest at /manifest/manifest.json with $schema pointing to the embedded schema When validating manifest.json with JSON Schema Draft 2020-12 Then validation completes with zero errors and zero warnings And schema_version in the manifest matches the embedded schema version And the embedded schema’s sha256 matches schema_sha256 recorded in the manifest
Embedded Artifacts and Deterministic Archive Structure
Given the exported archive When listing its contents Then manifest.json is present at /manifest/manifest.json And schema.json is present at /manifest/schema.json And the binder is present at /binder/binder.pdf And all file paths and names follow the documented deterministic convention And archive entry ordering is deterministic and stable across exports with identical inputs And archive entry timestamps are normalized to a fixed UTC value to ensure byte-for-byte reproducibility
Provenance, Versioning, and Chain-of-Custody Links
Given a prior exported bundle exists When generating a new export Then manifest.meta includes export_id, generator_name, generator_version, generated_at (UTC ISO 8601), and previous_bundle_checksum And previous_bundle_checksum equals the prior bundle’s checksum And all changed items record updated_at and author fields reflecting the change And unchanged items retain their prior metadata except updated_at and version remain unchanged
Lightweight Offline Verifier Utility
"As an investigator, I want a small verifier I can run without internet so that I can trust the package’s integrity within my secure environment."
Description

Deliver a cross-platform, offline verifier (CLI and minimal GUI) that validates Regulator Pack integrity: verify bundle and per-item checksums, JSON Schema compliance, PDF/A conformance, and Bates continuity (no gaps/duplicates). Produce a signed human-readable report (HTML/PDF) detailing pass/fail and anomalies. Operate entirely offline with no data exfiltration, support Windows, macOS, and Linux, target <10 MB download, and publish reproducible build and code-signing details. Provide simple drag-and-drop UX and a CI job to self-verify nightly builds.

Acceptance Criteria
Offline Verification Execution and No Network Egress
Given a workstation with all network interfaces disabled (offline) and default settings When the verifier is executed against a valid Regulator Pack with an explicit output directory Then all verification steps complete successfully without any outbound network or DNS attempts (as observed via OS network monitor) And no data is written outside the specified output directory and OS-designated temporary directory And the process exits 0 for a fully valid pack and nonzero for any detected failure
CLI Integrity Verification (Bundle and Per-Item Checksums)
Given a Regulator Pack containing a manifest of bundle and per-item checksums with declared algorithms When the CLI is run as: briefly-verify --input <pack> --checksums Then the computed checksum of the entire bundle matches the manifest value And the computed checksum of each listed item matches its manifest value And any mismatch is reported with item path, expected hash, actual hash, and algorithm used And the summary includes total items checked, matches, mismatches And the process exits nonzero if any mismatch is found
Content Compliance: JSON Schema, PDF/A, and Bates Continuity
Given the pack includes machine-readable JSON with supported $schema identifiers When the verifier runs with --schema-validate Then each JSON file validates against the embedded schema set, reporting violations with JSON Pointer path and error message, and a summary of valid/invalid counts Given the pack includes a PDF/A binder with a declared conformance level When the verifier runs with --pdfa-validate Then the binder validates offline to the declared PDF/A profile, listing non-conformances with rule ID and page reference, and a pass/fail summary Given the pack declares a Bates numbering sequence When the verifier runs with --bates-validate (implicit in default run) Then page and attachment indices form a continuous, non-duplicated sequence starting at the declared start value And any gaps or duplicates are listed with expected vs observed numbers and locations
Signed Human-Readable Report (HTML and PDF)
Given verification has completed When the verifier is invoked with --report html,pdf --sign --out <dir> Then an HTML and a PDF report are written to <dir> And each report includes: overall pass/fail, per-check results, anomalies, timestamps, tool version, platform, and the input bundle checksum And the HTML report is accompanied by a detached signature file (.sig) and the PDF is produced with an embedded digital signature And running briefly-verify --verify-report <report> validates the signature offline and exits 0 on success, nonzero on failure And the report displays the signer public key fingerprint matching the published fingerprint
Minimal GUI Drag-and-Drop Verification Flow
Given the GUI is launched When the user drags and drops a Regulator Pack file or folder onto the window Then verification starts automatically, showing phase-based progress (checksums, JSON, PDF/A, Bates, report) And upon completion, the same signed HTML/PDF reports as the CLI are saved to a user-selected location and can be opened via a View Report action And invalid input surfaces a clear, actionable error with retry, and the app remains responsive And the GUI operates fully offline and does not prompt for network access or external dependencies
Cross-Platform Artifacts, Size Budget, Code Signing, and Reproducible Build
Given a release is published When downloading platform-specific bundles (Windows x64, macOS universal, Linux x64) Then each compressed artifact size is <= 10,000,000 bytes And the Windows binary validates offline via Authenticode (signtool verify /pa) with the published certificate chain And the macOS app/binary validates offline via codesign --verify --deep --strict with hardened runtime enabled And the Linux binary validates offline via a detached signature (e.g., minisign/openssl) using the published public key And the release notes include: exact source commit, build container image digest, build commands, and dependency lockfiles And reproducing the build in the documented container yields byte-identical binaries (matching SHA-256)
Nightly CI Self-Verification of Builds
Given a nightly schedule in CI When the pipeline runs Then it builds the verifier for all supported platforms and executes it against two canonical test packs: one fully valid and one with seeded failures (checksums, schema, PDF/A, Bates) And the job archives the generated signed reports as artifacts with at least 30 days retention And the job fails if any check on the valid pack fails or if expected failures on the invalid pack are not detected And the verification steps run in an environment with outbound network blocked and still complete successfully
Automated Matter Timeline Composer
"As a responding attorney, I want an automatically generated timeline so that I can answer ‘who did what when’ without manual reconstruction."
Description

Assemble an authoritative chronology of the matter from intake through engagement and filings by extracting events such as initial contact, identity checks, consent capture, retainer e-sign, draft revisions, approvals, payments, filings, and access events. Normalize time zones, annotate each entry with its source, actor, and Bates references, and include both a readable timeline section in the PDF binder and a sortable JSON array. Provide filters for common regulatory scopes and include an optional access history appendix for full audit detail.

Acceptance Criteria
Compose Unified Matter Timeline from Multi-Source Events
Given a matter contains events from intake, identity verification, consent capture, retainer e-sign, draft revisions, approvals, payments, court filings, and access logs When the Regulator Pack export is generated Then the timeline includes every available event with no duplicates and no omissions, as verified by a source event count parity check And the timeline is strictly ordered by event timestamp ascending And each timeline event has a unique stable event_id (UUIDv4) and event_type from the approved enumeration And generation completes within 2 seconds for up to 500 events on a standard workspace
Normalize Timestamps to Matter Time Zone with UTC Reference
Given events originate from multiple time zones and daylight saving transitions When the timeline is composed Then each event includes occurred_at_utc (ISO 8601 Z) and occurred_at_local (ISO 8601 with offset) plus local_tz (IANA ID) And the occurred_at_local corresponds to the matter's primary time zone and correctly reflects DST rules And the JSON array is sorted by occurred_at_utc ascending And the PDF displays local date/time and the time zone abbreviation
Annotate Entries with Source, Actor, and Bates References
Given source systems (Intake, E-Signature, Payments, DMS, Filing) and produced documents receive Bates pagination in the binder When the timeline is composed Then each event includes source_system, source_record_id, actor_id, actor_display_name, and actor_type (user/system/client) And events referencing documents include bates_start and bates_end where applicable, or null when not applicable And all referenced Bates ranges exist in the binder index and are unique, continuous within the range, and clickable from PDF timeline entries And missing or invalid Bates references cause export to fail with a descriptive error
Readable Timeline Section in PDF Binder
Given a completed export to PDF/A When the binder is opened Then a top-level section titled "Timeline" appears in the table of contents with page numbers And each event row shows local date/time, event_type, actor_display_name, summary, and Bates reference (if any) And events appear in chronological order matching the JSON timeline And internal links from timeline entries navigate to the first page of the referenced Bates range And the PDF/A-2b validation passes with no errors
Sortable Machine-Readable JSON Timeline
Given the export includes a JSON payload When the JSON is validated against the timeline schema Then the root contains timeline array with N events and metadata with matter_id and export_id And each event object includes: event_id, occurred_at_utc, occurred_at_local, local_tz, event_type, source_system, source_record_id, actor_id, actor_type, actor_display_name, summary, bates_start, bates_end, and metadata And the timeline array is sorted ascending by occurred_at_utc and stable for ties by event_id And the file name follows pattern {matter_id}_{export_id}_timeline.json
Regulatory Scope Filters
Given predefined scopes: "Engagement & Consent", "Trust/Funds & Payments", "Filings & Service", and "Access/Audit" When a scope filter is selected for export Then only events matching the selected scope appear in both PDF and JSON outputs And the applied scope is recorded in export metadata and PDF "Timeline" header And the total event count reflects the filter and matches between PDF and JSON And clearing the filter restores the full timeline without regenerating source data
Optional Access History Appendix
Given the "Include Access History Appendix" option is toggled on When the export is generated Then the binder includes an appendix titled "Access History" listing view/download events with actor_id, actor_display_name, role, ip_address, user_agent, occurred_at_local, and occurred_at_utc And the JSON includes an access_history array with the same fields and chronological order And links from timeline access events navigate to the corresponding appendix entries And when the option is off, neither the appendix section nor access_history array is present
Consent, Signature, and Payment Evidence Pack
"As a bar investigator, I want clear proof of client consent and payment authorization so that I can confirm informed engagement and authorized charges."
Description

Collect and present all consent and authorization evidence in regulator-friendly layouts: retainer acceptance, scope amendments, e-sign certificates, IP/device fingerprints, OTP verification logs, payment authorization tokens, and receipts. Cross-link each artifact to its Bates page range and original source within Briefly, and include the raw artifacts in the JSON manifest. Standardize presentation to clearly show timestamps, signer identity, and chain-of-custody details.

Acceptance Criteria
PDF/A Binder with Bates Pagination for Consent and Payment Evidence
Given a matter containing retainer acceptance, scope amendments, e-sign certificates, IP/device fingerprints, OTP logs, payment authorizations, and receipts When the user generates the Regulator Pack Then a single PDF/A-2b compliant binder is produced And every page displays Bates pagination in the format BRF-{MatterID}-{000001} starting at 000001 and incrementing by 1 with no gaps And the binder includes a table of contents listing each artifact with its Bates page start and end And each artifact’s first page includes a standardized cover sheet identifying the artifact and its Bates range And the binder passes automated PDF/A validation with no errors using industry-standard validators
Machine-Readable JSON Manifest with Raw Artifacts and Checksums
Given a generated Regulator Pack When manifest.json is created Then the manifest includes a top-level version, generated_at (ISO 8601 UTC), matter_id, and package_sha256 And for every artifact included in the binder, the manifest contains: artifact_id, type, title, source_url, created_at (ISO 8601 UTC), updated_at (if any), signer_identities, bates_start, bates_end, mime_type, size_bytes, sha256 And for every artifact, raw_content is included as base64-encoded data whose decoded byte length equals size_bytes and whose SHA-256 equals sha256 And the manifest includes a deterministic ordering (by bates_start ascending) And running the lightweight verifier against the binder and manifest returns OK with zero failed checks
Cross-Linking Between Binder Pages, Manifest, and Briefly Source
Given a user with permission to view the matter When they open the binder’s table of contents Then each artifact entry hyperlinks to its first page (bates_start) within the binder And scanning the artifact cover sheet QR/link opens the source_url for that artifact And requesting source_url while authenticated returns HTTP 200 and displays the original record in Briefly And for every artifact, the bates_start and bates_end in manifest.json exactly match the Bates numbers on the binder pages And any manifest entry without a valid source_url is flagged and causes the verifier to fail
Standardized Chain-of-Custody Presentation
Given artifacts are rendered into the binder When a reviewer opens an artifact’s cover sheet Then it presents standardized fields: Artifact Title, Artifact ID, Version/Hash, Collected By, Collected At (UTC), Signer Identity (name, email, phone), Authentication Factors (OTP, IP, Device Fingerprint), Certificate/Provider IDs, and Bates Range And a chronological event timeline lists creation, view, OTP challenge, OTP verification, signature, payment authorization, and any amendments with ISO 8601 UTC timestamps And all timestamps are normalized to UTC with Z suffix and are non-decreasing across the event sequence And IP address, user agent, and device fingerprint hash are displayed where recorded And no required field is blank; if unavailable, the value is shown as Unknown with a reason code
E‑Sign Certificate Integrity and Matching
Given a signed retainer or amendment is included When the binder and manifest are generated Then the vendor e-sign certificate is included and readable in the binder adjacent to the signed document And the certificate’s document hash matches the hash recorded for the signed document on the cover sheet and in manifest.json And the signer identity (name/email/phone) on the certificate matches the signer identity shown on the cover sheet And the certificate event timestamp is within ±2 seconds of the signature event timestamp in the chain-of-custody timeline And manifest.json records certificate_id and certificate_sha256 for each e-sign artifact And the verifier reports Pass for all certificate-to-document hash matches
Payment Authorization Evidence and Redaction Compliance
Given one or more payments are authorized within the matter When the Regulator Pack is generated Then the binder includes payment authorization details: provider, token/reference, masked PAN (last4 only) or masked account (ACH last4), brand/type, expiration (MM/YY if card), authorization code, amount, currency, and UTC timestamp And receipts are included showing amount (two decimal places), currency, payer identity, transaction_id, and outcome And no full PAN, CVV, secret keys, or bank account numbers beyond last4 appear anywhere in the binder or manifest And manifest.json records payment_provider, token/reference, transaction_id, receipt_sha256, and amount/currency And automated redaction checks report zero PII violations
OTP Verification Logs and Identity Proofing Evidence
Given OTP was used to verify signer identity for consent or signature When the Regulator Pack is generated Then the binder includes OTP logs per session: delivery channel (SMS/Email), obfuscated destination, sent_at (UTC), verified_at (UTC), attempts_count, and outcome (Success/Failure) And the manifest records otp_session_id, delivery channel, obfuscated destination, and a salted hash of the OTP code (not the raw code) And each consent/signature event references its linked otp_session_id And attempts_count does not exceed 5 and a successful verification precedes the recorded acceptance event And IP/device context is captured at both challenge and verification events
Configurable Scope and Redaction Presets
"As a solo attorney, I want to tailor what’s included and safely redact sensitive data so that I meet inquiry needs without over-disclosing confidential information."
Description

Provide UI and API to define export scope (date ranges, document categories, communications, attachments) and apply redaction rules (mask SSNs, account numbers, third-party PII, internal notes) with real-time preview. Support named presets (e.g., ‘Ethics Inquiry Standard’), auto-generate a scope statement for the binder, and produce an exclusions appendix listing withheld items with reasons. Persist the chosen configuration with the export for reproducibility and include it in the manifest.

Acceptance Criteria
Define and Save Named Export Preset (UI)
Given I have selected scope filters (date range, document categories, communications, attachments) and redaction rules (SSNs, account numbers, third-party PII, internal notes) When I click Save as Preset and enter a unique name "Ethics Inquiry Standard" Then the preset is saved with a unique identifier, visible in the preset picker, and can be applied to a new matter with identical settings And when I update the preset name or rules, the system creates a new version and preserves prior versions And attempts to create a duplicate name are blocked with a validation error and a suggestion to choose a different name
Apply Redaction Rules with Real-Time Preview
Given a 25-page PDF and a 200-message communication thread loaded in preview When I enable SSN and account-number masking Then all pattern matches are visually masked in the preview, with redaction chips indicating count by type And the preview refreshes within 1500 ms after toggling a rule And masked content cannot be copied via clipboard or text selection from the preview And hovering a redaction shows the rule name and reason And a banner warns "No matches found" if a rule is enabled but finds zero matches
Scope Selection by Date Range and Categories
Given a matter containing documents, messages, and attachments across multiple dates and categories When I select a closed date range and specific categories Then the item counts by type update to reflect in-scope items only And attachments inherit scope from their parent communications/documents unless explicitly deselected And timezone handling uses the matter's configured timezone and endpoints are inclusive And the preview list displays only in-scope items and none outside the filters
Auto-Generated Scope Statement in Binder
Given I initiate an export using a preset or custom configuration When the binder is generated Then a PDF/A "Scope Statement" section is included before the contents index And it enumerates selected scope filters, redaction rules, preset name and version (if any), export timestamp (UTC), and the user who initiated the export And the Scope Statement text exactly matches the manifest configuration fields
Exclusions Appendix with Withheld Items and Reasons
Given some items are withheld due to scope filters, privilege/internal notes, or third-party PII policies When the export completes Then the binder includes an "Exclusions Appendix" listing each withheld item with identifier, type, date, title/subject, and reason code And the appendix totals withheld counts by reason and type And if no items are withheld, the appendix states "No exclusions" And the appendix entries reconcile with the manifest exclusions array one-to-one
Persisted Configuration in Export Manifest
Given an export is created When I open the manifest.json Then it contains the exact scope filters, redaction rules, preset name and version, and a configurationHash And repeating the export on the same dataset with the same configuration yields the same configurationHash And the manifest includes references to the Scope Statement section and the Exclusions Appendix
API Support for Preset Application and Export
Given I have API credentials with export:create scope When I POST /v1/exports with presetId and optional overrides Then I receive 201 Created with exportId, status, and a manifestUrl And invalid presetId or conflicting overrides return 400 with field-level errors And GET /v1/exports/{id}/manifest returns the same configuration captured in the UI And an audit log event records who created the export, which preset was used, and any overrides

Anomaly Sentinel

Real‑time detection and alerting for risky audit patterns: mass downloads, unusual hours, unfamiliar devices, geo mismatches, or repeated failed auth. Auto‑applies safeguards (session revokes, step‑up verification) and records the response trail. Helps solos prove diligent supervision and shrink exposure without babysitting logs.

Requirements

Unified Security Event Pipeline
"As a solo attorney administering Briefly, I want all security-relevant events normalized in real time so that Sentinel can reliably detect risky patterns across my entire workflow."
Description

Implement a real-time ingestion and normalization pipeline that captures authentication attempts, session changes, device fingerprints, file and matter downloads, retainer/e-sign actions, and API activity across Briefly’s web and mobile clients. Map heterogeneous sources (app logs, auth provider, storage, e-sign, questionnaire flows) to a common security event schema with <2s end-to-end latency, at-least-once delivery, idempotency, and backpressure handling. Provide PII minimization/redaction, tenant scoping, and clock sync guarantees. Expose a vetted event stream to Anomaly Sentinel for detection while integrating with existing observability and error reporting tools.

Acceptance Criteria
Unified Schema Mapping Across All Sources
Given events from authentication provider, application/web logs, storage subsystem, e‑sign provider, questionnaire flows, and API gateway When the pipeline ingests these events Then each event is normalized to SecurityEvent v1 with required fields present: event_id, event_type, tenant_id, user_id, session_id (if applicable), device_id (if available), source, source_timestamp, ingest_timestamp, ip_address (pseudonymized), outcome, and metadata And schema validation passes for 100% of sampled events (≥1,000 per source) with 0 validation errors And unknown source fields are captured in metadata.extra without blocking ingestion And event_type is one of: auth_attempt, session_change, device_fingerprint, file_download, matter_download, retainer_action, esign_action, api_call, questionnaire_action
Sub-2s Latency and Clock Sync Guarantees
Given a sustained mixed workload of 1,500 events/sec across all sources When events are emitted Then the p95 end-to-end latency (source_timestamp to availability on the vetted stream) is ≤ 2.0s and p99 ≤ 3.0s And the maximum clock skew between source_timestamp and ingest_timestamp is ≤ 500ms for 99.9% of events And per-user-session event ordering is preserved (non-decreasing source_timestamp for events with the same session_id)
At-Least-Once Delivery and Idempotent Replays
Given simulated broker outages, worker restarts, and network partitions lasting up to 5 minutes When the pipeline recovers Then no events are lost as verified by source vs sink counts (discrepancy = 0 over 1,000,000 events) And duplicate deliveries may occur but each event includes a stable event_id and dedup_key; reprocessing the same batch produces no additional unique events to consumers that deduplicate by dedup_key And replaying from a checkpoint reproduces the same ordered sequence per partition without gaps
Backpressure and Graceful Degradation
Given a burst load of 10,000 events/sec for 10 minutes When the pipeline applies backpressure Then no events are dropped (drop rate = 0) and the system remains responsive (ingestion endpoints return 2xx) And the backlog is drained to steady-state within 15 minutes after the burst ends And CPU stays below 80% and memory below 75% on ingest workers And automatic rate limiting and batching are engaged as evidenced by metrics and logs
PII Minimization and Redaction at Ingestion
Given events containing direct identifiers (full name, email, phone, postal address, government IDs, date of birth, payment tokens) and free-text fields When events are normalized Then all direct identifiers are excluded from the vetted stream or irreversibly hashed with per-tenant salt; free-text fields are redacted to remove PII patterns And IP addresses are stored only in truncated or hashed form And only the approved allowlist of fields is present in the vetted stream; a nightly DLP scan finds 0 unapproved PII instances across a 24-hour sample And raw payloads with PII are not persisted in the pipeline beyond transient buffers; disk persistence contains only redacted forms
Tenant Scoping and Isolation
Given tenants A and B with active events When a consumer authorized for tenant A subscribes to the vetted stream Then only tenant A events are delivered; cross-tenant leakage is 0 in audit And any attempt to request tenant B events returns 403 and is logged And storage and stream partitions are keyed by tenant_id and access-controlled; penetration test verifies isolation
Anomaly Sentinel Stream and Observability Integration Contract
Given Anomaly Sentinel subscribes to the vetted stream via the agreed interface When the pipeline emits events Then Anomaly Sentinel receives all event types with contract-compliant schema v1 and processes them without runtime schema errors over a 24-hour soak test And schema changes are versioned; introducing v2 maintains backward compatibility for v1 consumers and publishes a deprecation notice And each event carries trace_id and correlation_id linking to OpenTelemetry traces; event and pipeline errors are exported to the existing error reporting tool with correlation to event_id And dashboards expose throughput, latency, error rate, and consumer lag with alerting thresholds configured and test alerts firing successfully
Baseline Learning & Anomaly Rules Engine
"As a security-conscious solo attorney, I want Sentinel to learn my normal patterns and apply clear rules so that alerts are accurate and I’m not overwhelmed by noise."
Description

Create a detection engine that combines per-user/tenant behavioral baselines with configurable rules to flag mass downloads, unusual login hours, unfamiliar devices, geo-velocity mismatches, and repeated failed authentication. Support tunable thresholds, quiet hours, allow/deny lists, and exception windows (e.g., court deadlines). Provide policy versioning, dry-run/simulation mode, and preview impact before enforcing. Ensure low false-positive rates via seasonal/weekly patterns, device trust scores, and adaptive thresholds. Expose a policy API and UI for admins to author, test, and deploy rules without code.

Acceptance Criteria
Baseline Learning with Weekly Seasonality
Given a tenant with at least 21 days of user activity data When the baseline job runs at 02:00 tenant-local daily Then for each user the engine stores a baseline that includes: (a) per-weekday login-hour distribution with 95% coverage windows, (b) median and 95th percentile download rates per 10-minute interval, (c) top 5 geo clusters with centroid and variance, and (d) device trust score distribution by device fingerprint And the baseline incorporates weekly seasonality and adjusts for DST transitions And the baseline is retrievable via API GET /policies/baselines/{userId} returning the above fields with a lastTrainedAt timestamp And baseline training completes within 30 minutes for tenants up to 1,000 users And dry-run evaluation over the last 14 days yields <2% anomalies for users with stable patterns (no configuration changes)
Mass Download Rule with Tunable Thresholds and Quiet Hours
Given a policy with threshold=200 documents per 10 minutes and quietHours=22:00-06:00 local with sensitivityMultiplier=0.5 When a user downloads more than 200 documents within any 10-minute rolling window during normal hours Then an anomaly event with type="mass_download" is emitted within 60 seconds and policyVersion is recorded And when the same occurs during quiet hours, the effective threshold is reduced to 100 and alerts fire accordingly And when the user is on an allowlist, no alert is emitted And in simulationMode=true, the system produces preview counts and impacted users for the last 30 days without enforcement And administrators can update threshold and quiet hours via UI and API PATCH /policies/{id} and changes take effect within 2 minutes and are versioned
Unusual Login Hours with Exception Windows (Court Deadlines)
Given a user baseline whose 95% login window on weekdays is 08:00-18:00 local And a policy defining exceptionWindow named "Court Deadline" from 18:00-23:59 on a specific date When the user logs in at 22:15 on that date Then no alert is generated and the event is tagged with exceptionWindowId When the same user logs in at 22:15 on a non-exception date Then an anomaly event with type="unusual_hours" is emitted within 60 seconds and includes baselineWindow and localTimezone And denylisted users always trigger alerts regardless of exception windows And allowlisted service accounts never trigger alerts for this rule And admins can create, edit, and delete exception windows in UI and via API POST/DELETE /policies/{id}/exceptions
Unfamiliar Device Trust with Step-Up Verification and Response Trail
Given deviceTrustThreshold=70 and stepUpAction=MFA When a login originates from a device with trustScore < 70 not seen in the last 90 days Then an anomaly event with type="unfamiliar_device" is emitted within 60 seconds and step-up verification is required before access And if step-up succeeds within 5 minutes, the session is issued and the device fingerprint is added with updated trustScore And if step-up fails 3 times or times out, all active sessions for the user are revoked and future attempts require step-up for 24 hours And the response trail records action, actor=system, timestamps, and outcome linked to the anomalyId and policyVersion And admins can review the response trail in UI and via API GET /anomalies/{id}/responses
Geo-Velocity Mismatch with Location Allow/Deny Lists
Given geoVelocityMaxKph=900 and timeSkewTolerance=10 minutes And an allowlist of CIDRs for firm VPN endpoints When a user successfully authenticates from New York and then 20 minutes later from London with no VPN allowlist match Then an anomaly event with type="geo_velocity" is emitted within 60 seconds including calculated velocity and locations And if the second login originates from an allowlisted VPN CIDR, no alert is emitted And a denylisted country always triggers an alert regardless of velocity And remediation action=stepUp is executed for geo_velocity events unless the user passed stepUp in the last 60 minutes And all calculations use tenant-configured timezone and account for timeSkewTolerance
Repeated Failed Authentication with Adaptive Thresholds
Given a policy with failedAuthThreshold=5 within window=10 minutes and lockoutDuration=15 minutes When a user account experiences 5 failed authentication attempts within any 10-minute rolling window Then an anomaly event with type="failed_auth" is emitted within 60 seconds and the account is placed into step-up-required state for 15 minutes And if the attempts exceed 10 within the same window, all active sessions are revoked immediately And allowlisted service accounts are exempt but still logged And adaptiveThresholds=true increases threshold by 50% for users with high historical failure rates over the last 30 days (95th percentile) And audit logs capture username hash, IPs, userAgent hashes, and policyVersion without storing plaintext credentials
Policy Versioning, Dry-Run Preview, and No-Code Authoring UI/API
Given an admin creates a new rule in the UI and saves as Draft v1.0 When the admin requests Preview Impact for the last 30 days Then the system returns hit counts, affected users, and projected actions within 10 seconds for tenants up to 100k events/day When the admin toggles Simulation Mode and publishes v1.1 Then enforcement remains off, events are tagged simulation=true, and the change log records author, timestamp, diff When the admin promotes v1.1 to Enforced Then enforcement begins within 2 minutes with zero downtime and prior versions remain available for rollback And via API, POST/GET/PATCH /policies supports schema validation with descriptive errors and ETag-based concurrency control And rollback to any prior version completes within 2 minutes and is fully auditable
Real-time Alerts & Notification Routing
"As a Briefly user, I want timely alerts via my preferred channel with enough context to act quickly so that I can contain risk without stopping my work."
Description

Deliver immediate, actionable alerts with severity scoring and context (who, what, where, device, IP, geo, related sessions). Support in-app banners, mobile push, email, SMS, and Slack/Teams with per-user preferences, escalation paths, and on-call schedules. Implement alert de-duplication, throttling, and grouping to reduce noise. Provide an Alert Center with acknowledge/snooze/resolve actions, deep links to affected matter or retainer, and recommended next steps. Localize timestamps/timezones and log all alert lifecycle events.

Acceptance Criteria
Critical Alert: Multi-Channel Delivery with Full Context
Given an anomaly with severity score >= 90 is detected When the alert is generated Then an in-app banner is shown to users with Security Admin role within 5 seconds And a mobile push and an email are delivered to the primary on-call within 10 seconds And, if Slack/Teams is connected, a message is posted to the configured incident channel within 10 seconds And the alert payload for every channel includes: actor user ID and name, action type, affected resource (matter/retainer IDs), device type and fingerprint, IP address, geolocation (city, region, country), related session IDs, severity score, and detection timestamp in UTC and localized time And each delivery contains a link to view the alert in the Alert Center
User Notification Preferences and Quiet Hours
Given a user has per-channel notification preferences with minimum severity thresholds and quiet hours (local time) When an alert with severity 70 occurs during quiet hours Then only channels allowed by quiet-hours rules (e.g., email) are used and push/SMS are suppressed When an alert with severity >= 90 occurs during quiet hours and the user has enabled critical overrides Then push (and SMS if enabled) are sent despite quiet hours When a user disables SMS in preferences Then no SMS is sent for any alert regardless of severity And changes to preferences take effect within 60 seconds for subsequent routing decisions
Escalation and On-Call Schedule
Given an on-call schedule with primary and secondary responders and an escalation interval of 5 minutes When an alert is not acknowledged within 5 minutes Then the system escalates to the next step in the path (e.g., from push to SMS) for the primary When still unacknowledged after 10 minutes Then the system escalates to the secondary responder and posts to the configured Slack/Teams channel And once any responder acknowledges the alert, further escalations stop immediately And off-call users do not receive escalations And each escalation attempt records timestamp, channel, recipient, and outcome
De-duplication, Throttling, and Grouping
Given multiple identical events (same actor and resource context) occur within 60 seconds When the first event triggers an alert Then subsequent identical events within that window are de-duplicated (no new notifications) Given a burst of related events (e.g., repeated failed auth for the same principal or IP) within 5 minutes When grouping rules match Then a single incident is created with an incrementing counter and consolidated summary And notifications are throttled to a maximum of 1 per channel per 5-minute window per incident And a severity increase of >= 20 or a change in actor/resource context breaks throttling and starts a new notification/group
Alert Center Actions and Deep Links
Given an alert is visible in the Alert Center When a permitted user clicks Acknowledge Then the alert status changes to Acknowledged and all pending escalations are cancelled When a user Snoozes an alert for 15 minutes Then notifications for that incident pause until snooze expiry, unless severity upgrades to critical When a user Resolves an alert and selects a reason (false positive, mitigated, test) Then the alert status becomes Resolved and the incident is closed to new notifications And recommended next steps are displayed based on alert type with one-click actions (e.g., open session list, require step-up verification) And deep links to the affected matter or retainer open the correct record with context filters applied And alert state changes sync across web and mobile within 2 seconds
Localization: Timestamps and Timezones
Given the organization default timezone and a user-specific timezone preference When an alert is displayed in any channel and in the Alert Center Then all timestamps are shown in the user’s local timezone with offset, with UTC ISO 8601 available in details And daylight saving transitions are correctly handled (no duplicate or missing hour) And if a user has no timezone set, the organization default is used And searches and filters by time operate consistently using UTC under the hood
Alert Lifecycle Audit Logging
Given any alert and its notifications When any lifecycle event occurs (create, deliver-per-channel, delivery-failure, view, acknowledge, snooze, unsnooze, escalate, resolve, recommendation-click, deep-link-open) Then an immutable audit record is written with: alert_id, incident_id, event_type, timestamp (UTC ISO 8601), actor_user_id (or system), target_user_id (if applicable), channel, ip, user_agent, and outcome And audit logs are queryable by time range, severity, actor, channel, and exportable as CSV and JSON And logs are append-only with verifiable checksums and retained for at least 365 days
Automated Protective Actions
"As a solo attorney, I want Sentinel to automatically apply protective actions when something looks risky so that exposure is reduced even when I’m away from my desk."
Description

Automatically apply safeguards when high-severity anomalies trigger: revoke active sessions and refresh tokens, force step-up verification (MFA) on next action, temporarily pause bulk downloads/exports, lock sensitive matters, and require supervisor approval for specific actions. Map actions to policy conditions with configurable cooldowns and exemptions. Ensure reversibility with explicit approvals, audit every decision, and provide a safety valve to prevent lockout storms. Integrate with Briefly’s auth flows, e-sign, and document access control to minimize user disruption while reducing exposure.

Acceptance Criteria
Immediate Session Revocation on High-Severity Anomaly
- Given a high-severity anomaly is detected for a user, within 5 seconds (p95) all active web/mobile sessions for that user are revoked and all refresh tokens are invalidated. - The user is forced to re-authenticate on the next request; any request using a revoked session returns 401 with error code ANOMALY_SESSION_REVOKED. - An audit record is created with fields: userId, policyId, anomalyId, action="revoke_sessions", severity, timestamp (UTC ISO 8601), correlationId, and outcome (success|failure). - If revocation fails for any session, the system retries up to 3 times with exponential backoff and logs each attempt and final outcome.
Step-Up Verification on Next Action Post-Detection
- After detection of a high-severity anomaly, the system sets a requires_step_up flag for the user for the policy-defined cooldown or until supervisor clearance. - When the user attempts any protected action (login, document access, matter change, export), they are prompted for configured MFA; on success within 120 seconds the action proceeds, on failure/timeout it is blocked with 403 ANOMALY_STEP_UP_REQUIRED. - The step-up is single-use per session per protected-action category within a 10-minute grace window, unless policy.enforce_every_action=true. - All MFA prompts and outcomes are recorded to the audit trail with method, success/failure, timestamp, and correlationId.
Bulk Download/Export Pause with Cooldown and Exemptions
- When a high-severity anomaly is active for a user, bulk downloads/exports above policy.threshold (e.g., >50 documents or >100MB) are paused/blocked for policy.cooldown minutes. - Blocked attempts return 429 ANOMALY_BULK_PAUSED with a Retry-After equal to remaining cooldown. - Exemptions can be configured by userId, role, deviceId, or IP CIDR; exempt users bypass the pause but still undergo step-up. - After 3 blocked attempts within 10 minutes, the event is escalated to supervisor notification (audited) without leaking details to the user. - All pause events include policyId, thresholds, cooldown, matched exemption (if any), and are audited.
Auto-Lock Sensitive Matters and Supervisor Approval for Unlock
- On high-severity anomaly, matters tagged sensitive=true for the affected user transition to state=Locked within 10 seconds. - While Locked, the following actions are blocked: document view/download, export, matter sharing changes, retainer edits, and e-sign envelope creation; read-only metadata is permitted only if policy.allow_metadata_view=true. - Unlock requires supervisor approval via in-app flow capturing approverId and reason; upon approval, state transitions to Unlocked and the action is audited. - Any attempt to modify a Locked matter is denied with 423 MATTER_LOCKED and logged with correlationId.
Policy-to-Action Mapping with Cooldowns and Exemptions
- Admins can define policies mapping conditions (severity, anomaly types, device reputation, geo mismatch, time-of-day) to actions {revokeSessions, requireStepUp, pauseBulk, lockMatters, requireSupervisorApproval}. - Evaluation is deterministic and idempotent; the same event for the same user within an action's cooldown does not duplicate the action. - Each action supports an independent cooldown (in minutes) and an exemption list; changes propagate within 2 minutes and are versioned with 90-day retention. - A policy test harness can simulate events and displays the actions that would fire; results match production evaluation for the same inputs. - All policy creations/edits require explicit approver acknowledgement and are fully audited.
Safety Valve to Prevent Organization-Wide Lockout Storms
- A circuit breaker engages when anomaly-triggered protections would affect ≥5 distinct users within 60 seconds or ≥10% of active users (whichever is smaller). - While engaged, the system downgrades protections to requireStepUp only; session revocations and matter locks are suppressed except for users with riskScore ≥ policy.maxRiskThreshold. - Circuit breaker status is visible to admins, auto-resets after 15 minutes below threshold, and supports manual override by a supervisor with audit. - No user is fully locked out of login; re-authentication with MFA remains available during circuit breaker mode.
Non-Disruptive Integration with Auth, E‑Sign, and Document Access
- Protective actions do not invalidate an in-progress e-sign envelope; if triggered mid-signing, allow completion, then require step-up before any further document access. - Auth flows honor protective flags: login requires MFA if requires_step_up is set; refresh token rotation is blocked and a full re-auth is required if tokens were invalidated. - Document access control enforces pauses and locks consistently across web and mobile; attempts to export during pause or access a Locked matter return standard errors defined above. - End-to-end tests show intake-to-engagement remains completable under protections with added MFA and adds ≤2 minutes at p95 compared to baseline.
Device, Network, and Geo Intelligence
"As a Briefly user, I want Sentinel to recognize trusted devices and detect suspicious ones so that I get fewer prompts on my own gear and more scrutiny on risky access."
Description

Implement device fingerprinting with a trusted-device registry, IP reputation checks, ASN/business vs. residential classification, VPN/Tor detection, and impossible-travel/geo-mismatch logic. Allow office IP allow-lists and travel modes with auto-expiry. Provide privacy-preserving techniques (e.g., hash-based fingerprints), minimize storage of raw network data, and support mobile clients and low-connectivity environments. Feed trust scores into detection and policy decisions, and surface device enrollment and review flows in-app.

Acceptance Criteria
Device Fingerprint Enrollment on First Login
Given a user authenticates from an unrecognized device, when they successfully complete step-up verification, then a privacy-preserving device fingerprint (salted hash of non-PII attributes) is generated and the device is added to the user's trusted-device registry. Given a device has been enrolled as trusted, when the user logs in again from the same device without material attribute changes, then the device is recognized as trusted within 2 seconds and no additional step-up is required unless other risk policies trigger. Given an enrolled trusted device undergoes material attribute changes (e.g., browser reinstall or cleared storage), when the user next logs in, then the fingerprint no longer matches and the device is treated as unrecognized requiring step-up. Given a device is enrolled, when the enrollment completes, then the UI displays the device label, OS, browser family, first-seen, and last-seen timestamps.
Trusted Device Registry Management Flow
Given a logged-in user opens Security > Devices, when the page loads, then they see a list of their trusted devices including device label, last seen time, last IP country, and trust status. Given a device is selected from the list, when the user clicks Revoke trust and confirms, then the device is removed from the trusted registry within 30 seconds and the next login from that device requires step-up. Given a device entry is displayed, when the user clicks Rename and saves a new label, then the updated label is persisted and visible on refresh. Given more than 10 devices are present, when the list is viewed, then pagination or lazy loading allows access to all devices without timeouts or rendering errors. Given a device trust is revoked, when the action completes, then an audit entry is recorded with actor, hashed device identifier, timestamp, and reason.
IP Reputation, ASN, and VPN/Tor Detection
Given a login attempt occurs, when the source IP is evaluated, then the system retrieves reputation score, ASN, and business vs residential classification within 500 ms and attaches them to the event. Given the source IP matches known VPN, proxy, or Tor exit data, when the login is attempted, then the event is tagged with reason "VPN/Tor" and the policy engine can require step-up prior to session creation. Given the IP reputation score is below the configured threshold, when authentication completes, then the trust score is reduced by the configured weight and the event is marked for review. Given the ASN indicates a hosting provider (data center), when combined with an untrusted device, then a high-risk composite flag is set for the policy engine to enforce stronger controls. Given an ASN is classified as residential, when an office IP allow-list exists, then office treatment is only applied if the IP matches the allow-list entry.
Impossible Travel and Geo Mismatch Detection
Given a last successful login at location A with timestamp T1, when a new login at location B occurs at T2 such that implied speed exceeds 500 mph, then the event is flagged as "impossible travel", trust score is reduced, and step-up verification is required before granting full access. Given a geo mismatch is detected (country change without impossible travel), when the device is trusted and Travel Mode is inactive, then the user is prompted for step-up and the event records the geo-mismatch reason. Given step-up succeeds after an impossible-travel flag, when the session is established, then an audit entry records the flag, verification method, and outcome. Given multiple logins from the same new location occur within 24 hours on the same trusted device, then duplicate impossible-travel alerts are suppressed while all events are logged.
Office IP Allow-List and Travel Mode
Given a user opens Security > Network, when they add and save an office IP or CIDR block, then subsequent logins from those IPs are labeled "office" and bypass geo-mismatch prompts while still requiring device trust and other risk checks. Given an IP or CIDR is removed from the allow-list, when the next login occurs from that network, then office treatment no longer applies and standard policies evaluate the event. Given a user enables Travel Mode with a defined start and end time (max 30 days), when logins occur during that window from non-office IPs and new geos, then geo-mismatch and impossible-travel flags do not auto-revoke sessions but require at least one step-up per device during the window. Given the Travel Mode end time elapses or the user toggles it off, then Travel Mode is immediately deactivated and normal geo policies resume.
Trust Score Computation and Policy Integration
Given a login event is received, when device, IP reputation, ASN, VPN/Tor, and geo signals are collected, then a trust score from 0 to 100 is computed within 200 ms and attached to the event. Given the computed trust score is below the configured threshold, when session creation is attempted, then the policy engine enforces the configured action (step-up or session revoke) and records the decision with contributing factors. Given an event is viewed in Security > Events, when details are expanded, then the trust score, top contributing factors, and policy decision are displayed in human-readable form. Given a user completes a step-up challenge required by policy, when the challenge succeeds, then the session is granted and the event reflects the successful challenge in its factors without inflating the original trust score. Given the trust scoring model version changes, when new events are processed, then the model version is recorded per event to support audit reproducibility.
Privacy-Preserving Fingerprinting and Low-Connectivity Support
Given a device fingerprint is generated, then it is produced as a salted hash of non-PII attributes; no raw canvas, audio, or full user-agent strings are persisted beyond in-memory processing. Given network metadata (IP, ASN, reputation) is collected, when events are stored, then only normalized scores and coarse geo (country/region) are retained; raw network payloads are retained no longer than the configured retention (default 30 days). Given a mobile client experiences intermittent connectivity during device enrollment, when connectivity is restored within 15 minutes, then the enrollment request is retried automatically and completes without requiring the user to re-enter data. Given the client detects low bandwidth (<150 kbps), when risk lookups are required, then non-critical lookups are deferred to server-side and the UI remains responsive, with final risk evaluation completing server-side post-auth without blocking initial form submission. Given a user account is deleted, when deletion processing completes, then all stored device fingerprints and normalized network metadata linked to the user are purged within 24 hours and no longer retrievable via UI or API.
Immutable Audit Trail & Compliance Reporting
"As a solo attorney, I want a complete, tamper-evident record of incidents and my responses so that I can prove diligent supervision to clients and regulators."
Description

Maintain a tamper-evident, append-only log of anomalies, alerts, actions taken, acknowledgements, and outcomes with precise timestamps, actor identities, and reasons. Provide exportable evidence packs (PDF/CSV) that summarize incidents and response timelines to demonstrate diligent supervision. Support retention policies, legal hold, and data subject access requests. Offer a compliance dashboard with filters by matter, user, severity, and date range, plus one-click generation of regulator/client-ready reports.

Acceptance Criteria
Immutable Append-Only Security Event Logging
Given an anomaly, alert, safeguard action, acknowledgement, or outcome occurs When the event is written to the audit log Then the entry is appended with fields: event_id, event_type, incident_id, matter_id (nullable), severity, reason_code, actor_id (or system), actor_role, client_ip, device_fingerprint, geo, timestamp_utc_ms, request_id, outcome, signature And the log computes a chained hash (SHA-256) linking to the previous entry; entry stores prev_hash and hash And any attempt to edit or delete an existing entry via UI/API is blocked with HTTP 409 and an audit event "write_denied" is recorded And a read of the same event returns identical payload and hash across repeated calls And timestamps are normalized to UTC with millisecond precision and monotonic ordering per incident
Recorded Response Trail for Safeguards and Acknowledgements
Given Anomaly Sentinel triggers a safeguard (session revoke or step-up verification) When the safeguard executes Then an audit entry records action_type, target_user_id, target_session_id, reason_code, initiated_by (system|user_id), timestamp_utc_ms, outcome (success|fail) And when a human acknowledges an alert in the UI Then an audit entry records acknowledgement with actor_id, timestamp_utc_ms, note/reason, and links to incident_id And all events related to the same incident share a common incident_id and render as a chronological timeline
Compliance Dashboard Filtering and Performance
Given the compliance dashboard has 10,000+ events When the user filters by matter_id, user_id, severity >= High, and a date range (last 30 days) Then only matching events are displayed and aggregate counts reflect the filtered set And the first page of filtered results loads within 2 seconds on a standard broadband connection And clearing filters restores the unfiltered view within 2 seconds And results are sortable by timestamp_utc_ms, severity, and user with sort applied within 1 second And pagination supports page sizes 25/50/100 and navigates without data loss
One-Click Evidence Pack Export (PDF and CSV)
Given the user selects a date range and optional filters (matter, user, severity) When the user clicks "Generate Evidence Pack" Then a PDF summary and CSV detail are generated for all matching incidents and events And the export completes within 60 seconds for up to 5,000 events and is available for download with a unique export_id And the PDF includes: cover page (firm name, date range, filters), KPIs (counts by severity, MTTA, MTTR), and per-incident timelines with actor identities and timestamps And the CSV includes one row per event with headers: event_id, incident_id, timestamp_utc_ms, event_type, severity, matter_id, user_id, action, outcome, reason_code, hash, prev_hash And the export action is recorded in the audit log with actor_id, export_id, filters, and checksum And the PDF displays a SHA-256 checksum that matches the value stored in the audit log
Retention Policies and Legal Hold Enforcement
Given a retention policy of 365 days is configured When events exceed the retention period and are not under legal hold Then the system purges those events on schedule, writes a "retention_purge" audit entry with a batch digest (Merkle root or hash), and removes raw entries from active storage And when a legal hold is placed for a matter, user, or date range Then purge is suspended for matching events and a "legal_hold_applied" audit entry is recorded And when the legal hold is released Then purge resumes and executes within 24 hours per schedule with a corresponding "legal_hold_released" and "retention_purge" audit entry And changes to retention or legal hold settings are RBAC-protected and logged And purged data is unrecoverable via UI/API; only aggregate digests remain for proof of deletion
Data Subject Access Request (DSAR) Export and Redaction
Given a verified DSAR is submitted for subject user_id=B for the last 24 months When an admin initiates "Generate DSAR Export" Then a machine-readable export (JSON or CSV) of all audit-trail personal data for user_id=B within the timeframe is produced no later than 30 days and typically within 60 minutes for <= 10,000 events And the export redacts third-party personal identifiers while preserving context (e.g., role labels for other actors) And the export includes a manifest describing data categories, sources, and processing purposes And the DSAR request, verification, export generation, and delivery are each recorded in the audit log with timestamps and actor identities And access to DSAR exports is restricted to authorized roles; unauthorized attempts are denied and logged

Litigation Hold

Place defensible holds on specific matters or artifacts to pause retention and deletion policies. Records who initiated the hold, why, and when; propagates via API to connected systems and prevents export tampering. Reduces spoliation risk and ensures evidence remains intact through disputes or regulatory reviews.

Requirements

Scoped Hold Creation
"As a solo consumer-law attorney, I want to quickly create a scoped legal hold on a matter and its related files so that I can preserve relevant evidence without over-collecting or missing artifacts."
Description

Provide a guided flow to create a defensible legal hold at either the matter or artifact level, capturing legal basis, reason, initiating user, start date/time, and optional expiry/review dates. Allow precise scoping by selecting custodians (client, staff, vendors), data sources (Briefly documents, uploaded files, integrated repositories), and date ranges, with validation and preview before activation. Auto-link holds to the originating matter, assign a unique Hold ID, and apply templates for common scenarios to streamline solo-attorney workflows. Ensure immediate activation upon confirmation and render held items clearly labeled within the UI across web and mobile. Store all configuration immutably for evidentiary defensibility while enabling non-destructive scope amendments via versioning.

Acceptance Criteria
Matter-Level Hold Creation with Required Metadata
Given a logged-in attorney with Hold-Manage permission and an open matter When they start Create Hold from the matter context and choose Matter-level Then the flow requires Legal Basis and Reason fields before proceeding And the Start Date/Time defaults to current UTC and is editable to a future time only And optional Expiry and Review dates can be set but cannot precede Start Date/Time And the Initiating User and Matter ID are auto-captured and read-only in the summary And upon confirmation a unique immutable Hold ID is generated in the format HOLD-YYYYMMDD-##### And the hold is auto-linked to the originating matter and visible in the matter's Holds list
Scoped Selection of Custodians, Data Sources, and Date Ranges
Given a user in the hold creation flow When they define scope Then they can add custodians from Clients, Staff, and Vendors directories with multi-select And they can select data sources including Briefly Documents, Uploaded Files, and Integrated Repositories And they can set an inclusive Date Range with From and To fields supporting absolute dates and relative presets And validation prevents activation if scope contains no custodians or no data sources And validation prevents inconsistent ranges (e.g., From after To) And the scope summary displays total custodians, sources selected, and the date window
Preview and Validation before Activation
Given a hold with defined scope and required metadata When the user navigates to the Preview step Then a preview displays the total count of matched items by source and custodian And a sample list of matched items with titles, source, custodian, and date is shown And conflicts with existing holds or retention policies are flagged with clear warnings And the Activate button is disabled until all required fields pass validation And the user can download a pre-activation summary PDF containing metadata, scope, counts, and warnings
Immediate Activation and API Propagation
Given a user confirms activation of a valid hold When the activation is submitted Then the hold status becomes Active within 5 seconds And an event is emitted to the integrations API containing Hold ID, scope, timestamps, and initiating user And connected systems receive the event or it is queued with retry/backoff until acknowledged And download or export actions for in-scope items are blocked for non-privileged users And any permitted export for privileged users automatically includes the Hold ID, scope hash, and checksum to detect tampering
UI Labeling of Held Items Across Web and Mobile
Given items fall within an active hold's scope When those items are displayed in search results, lists, or detail views on web or mobile Then each item shows a Held label including the Hold ID and Active status And a filter toggle allows users to include or limit results to held items And tapping or clicking the label opens the hold summary in a modal or drawer And labels are responsive and accessible with ARIA tags and high-contrast meeting WCAG AA
Template Application for Common Hold Scenarios
Given a user starts hold creation from any context When they select a predefined template (e.g., Regulatory Inquiry, Litigation Preservation) Then the template pre-populates legal basis, reason, default scope patterns, and review cadence And the user may edit any pre-populated field except the Hold ID which is generated on confirmation And selecting a template reduces the required manual steps to no more than two screens before preview And the selected template name and version are recorded in the hold metadata
Immutable Storage and Versioned Scope Amendments
Given an active hold exists When an authorized user amends the hold scope or dates Then a new non-destructive version is created with a monotonically increasing version number (e.g., v2) And the original configuration and all prior versions remain immutable and read-only And the audit log records who, when, what changed, and the reason for change with timestamps in UTC And the Hold ID remains constant across versions while the effective scope updates immediately upon save And a cryptographic hash of each version's configuration is stored for evidentiary defensibility
Retention Pause & Deletion Intercept
"As a practitioner, I want held items to be undeletable and read-only so that I can confidently prevent spoliation during active disputes."
Description

Implement an enforcement layer that intercepts retention timers, deletions, and destructive edits for items under hold, converting them to read-only (WORM) until release. Surface clear, actionable error messages for blocked actions and record every attempted change in the audit log. Ensure idempotent, low-latency checks for hold status to avoid performance regressions at scale. Support concurrent holds with union semantics, and automatically restore original retention policies and permissions upon release.

Acceptance Criteria
Deletion Attempt on Held Item Is Blocked and Explained
Given an item is under at least one active litigation hold When a user with delete permission attempts to delete the item via UI or API Then the system rejects the request with HTTP 423 Locked (API) or a blocking UI error And the error message includes the hold name/ID, who placed it, timestamp, and a link/instruction to request release And the item remains unchanged and read-only (WORM) And an immutable audit entry is recorded with actor, action=delete, channel, request ID, item ID, hold IDs, timestamp, and outcome=blocked_by_hold
Destructive Edit Intercept Enforces WORM
Given an item is under at least one active litigation hold When a user or integration attempts any destructive write (e.g., content change, attachment replace, metadata change that affects retention) Then the system rejects the request with HTTP 423 Locked (API) or a blocking UI error And the item remains read-only (WORM) with no partial updates committed And the error message is clear and actionable, referencing the active hold(s) And an immutable audit entry is recorded with actor, action=write_blocked_by_hold, fields attempted, request ID, item ID, hold IDs, and timestamp
Retention Timer Job Skips Held Items
Given a scheduled retention/deletion job is processing items whose retention has expired And an item in scope is under at least one active litigation hold When the job evaluates the item Then deletion, purge, and destruction steps are skipped for that item And the job emits a metric deletion_skipped_due_to_hold=1 for the item And an immutable audit entry is recorded with actor=system, action=retention_delete_skipped, job ID, item ID, hold IDs, and timestamp And the item remains read-only (WORM) with no state change
Concurrent Holds Apply Union Semantics
Given an item is subject to multiple active holds A and B When hold A is released while hold B remains active Then the item remains held and read-only (WORM) And any delete or destructive edit attempts continue to be blocked referencing the remaining active hold(s) And the UI/API returns the complete list of active holds for the item And an immutable audit entry records the release of A and continued enforcement due to B
Release Restores Original Policies and Permissions
Given an item had its original retention policy and permissions snapshotted at hold placement And all active holds on the item are released When the final hold release is processed Then the item exits WORM state and becomes writable per its pre-hold permissions And the original retention policy is restored with correct remaining durations (pausing elapsed during the hold) And if the original policy no longer exists, the system applies the configured successor policy and records the mapping And an immutable audit entry records before/after permissions and retention policy restoration with correlation ID
Hold Status Check Is Idempotent and Low-Latency at Scale
Given the enforcement layer checks hold status on every mutating request When sustained load is 5,000 RPS with 20% of requests targeting held items Then the added p95 latency from the hold check is ≤ 10 ms and p99 ≤ 25 ms, with error rate ≤ 0.01% And no false allows occur (0%), and false blocks ≤ 0.01% And retries with the same idempotency key do not create duplicate audit entries And per-item hold status may be cached up to 1s without permitting writes that should be blocked
Export Tampering Prevention for Held Items
Given an item is under at least one active litigation hold When a user or integration attempts to export the item in a way that would alter content/metadata or omit integrity controls Then the system either blocks the export with HTTP 423 Locked (API) or only permits an immutable export package containing original bytes, metadata, and a signed manifest of SHA-256 checksums And the error or success message clearly explains the constraint and references the active hold(s) And an immutable audit entry is recorded with actor, action=export_blocked_or_readonly, export options, item ID, hold IDs, and timestamp
API Propagation & Connectors
"As an attorney, I want holds to automatically apply across my connected tools so that preservation is consistent without manual, error-prone steps."
Description

Propagate active hold metadata and scope to connected systems via secure APIs and webhooks, mapping Briefly matter and artifact IDs to external object identifiers. Provide built-in connectors for common repositories (email, cloud storage, practice management) with retry, backoff, and reconciliation jobs to guarantee eventual consistency. Expose a propagation status dashboard showing per-system success, pending, and error states with remediation guidance. Support scoped updates and revocations, and maintain least-privilege credentials with rotation and audit for each connector.

Acceptance Criteria
Webhook Propagation of New Hold to Email Repository
Given a new active hold is created with matter_id and artifact_ids When the outbound webhook to the Email Connector is triggered Then the payload includes hold_id, matter_id, artifact_ids, scope, reason, initiator_user_id, and created_at (ISO-8601) And the webhook is HMAC-SHA256 signed with a rotating secret and includes X-Briefly-Signature and X-Briefly-Timestamp And payloads with timestamps older than 5 minutes or invalid signatures are rejected (HTTP 401) And a 2xx response marks propagation status=Success for Email within 30 seconds And non-2xx or timeouts (>10s) schedule retries with exponential backoff (1m,2m,4m,8m,16m) up to 5 attempts, then status=Error with last_error_code recorded And duplicate deliveries for the same hold_id and idempotency_key are processed idempotently (no duplicate mappings or state changes) And the connector returns external_message_ids for each artifact_id; Briefly persists artifact_id→external_id mappings with version and checksum
Connector Retry, Backoff, and Reconciliation Job
Given any connector item is in Pending or Error When the periodic reconciliation job runs every 15 minutes Then it verifies hold application in the external system for all Pending/Error items And enqueues discrepancies for retry with priority High up to 3 additional attempts And emits metrics attempts_count, age_seconds, and success_rate per connector And raises an alert when error_rate > 2% over a rolling 15-minute window And allows Org Admins to trigger manual reconciliation, returning job_id and a completion summary (processed, fixed, still_error) And achieves 99% eventual consistency (Success) within 60 minutes of initial event once the remote system is available
Propagation Status Dashboard
Given an Org Admin opens the status dashboard for a specific hold When the dashboard loads Then it displays each connected system with counts of Success, Pending, Error, and last_updated_at And rows in Error include last_error_code, last_error_message, next_retry_at, and remediation steps And filters by system, status, and date range are available and affect displayed totals And export of the current view to CSV is available and includes all visible columns And the view auto-refreshes every 30 seconds without full page reload and limits to ≤1 refresh request per 30 seconds per user And users without Org Admin or Litigation Manager roles receive HTTP 403
Scoped Update to Modify Hold Scope
Given Hold H exists with custodians [A,B] and artifacts [x,y] When custodian C is added and artifact y is removed Then Briefly emits delta events Add(Custodian=C) and Remove(Artifact=y) to all affected connectors And external systems apply additions/removals atomically and return updated mappings And successful operations are marked Success; failures are retried per retry policy And update ordering is enforced with a monotonically increasing sequence number per hold; out-of-order updates return HTTP 409 and are retried And an immutable audit log entry records actor, timestamp, actions (adds/removes), and affected IDs, queryable by hold_id
Revocation of Hold and Unhold Propagation
Given Hold H is active across connected systems When an authorized user revokes Hold H Then a REVOKE event is dispatched to all connectors within 5 seconds And connectors remove hold flags/retention pauses without deleting artifacts, allowing normal retention to resume per system policy And Briefly marks all per-system statuses as Revoked within 15 minutes or shows Error with remediation if unsuccessful And all mappings for H are archived (read-only) and no longer used for propagation And late-arriving updates for H are rejected with HTTP 410 Gone and logged And an audit log entry captures reason, approver, timestamp, and affected systems
Least-Privilege Credentials, Rotation, and Audit
Given a connector is configured When validating credentials Then only the documented minimal scopes for that connector are accepted; excessive scopes cause configuration to fail with a clear error And secrets are stored in a FIPS-validated KMS; access is role-restricted and every access is logged with actor, time, and purpose And automatic key rotation occurs at most every 90 days without propagation downtime, verified by a canary event; on failure, rotation rolls back automatically And disabling or revoking the credential yields 401/403 on propagation attempts and surfaces as Error on the dashboard with remediation guidance And an access review report can be generated listing connector, scopes, last_rotated_at, last_used_at, and approver of the last change
Tamper-proof Audit & Chain of Custody
"As a lawyer, I want a verifiable audit trail for the entire lifecycle of a hold so that I can demonstrate defensible preservation in court or regulatory reviews."
Description

Record an immutable, append-only audit trail for each hold capturing initiator, timestamps, reason, scope details, propagation events, blocked actions, acknowledgments, modifications, and release events. Protect the log with cryptographic hashing and sequence integrity to detect tampering, and store it in WORM-compliant storage. Provide court-ready exports (PDF/JSON) with verifiable checksums and a readable summary timeline. Normalize timestamps to a trusted time source and include relevant environment metadata for defensibility.

Acceptance Criteria
Immutable Append-Only Audit on Hold Lifecycle
Given a user with permission creates a litigation hold, When the hold is saved, Then an audit entry is appended containing hold_id, initiator_id, reason, scope, timestamp_utc, sequence_number=1, and entry_type='create'. Given hold metadata is updated, When changes are saved, Then a new audit entry with entry_type='modification' is appended capturing changed_fields with before and after values and an incremented sequence_number. Given any attempt is made to update or delete an existing audit entry, When the request is processed, Then the operation is rejected with HTTP 403 and a new 'blocked_action' audit entry is appended referencing the targeted entry.
Cryptographic Hash-Chain and Sequence Integrity
Given a new audit entry is appended, When it is persisted, Then it includes prev_hash (hash of prior entry) and hash=SHA-256(prev_hash || canonicalized_entry_payload) and a strictly incremented sequence_number with no gaps. Given the integrity verification API is called for a hold, When the log has not been tampered with, Then the API returns status='valid', head_hash, total_entries, and first_sequence=1. Given any audit entry is altered or removed outside the system, When the verification API is called, Then it returns status='invalid' and the first_mismatch_sequence and expected_vs_actual_hash values.
WORM-Compliant Storage Enforcement
Given WORM storage is configured, When an audit segment/object is committed, Then it is stored with write-once immutability enabled in compliance/legal-hold mode until the hold is released per policy. Given a user or process attempts to modify or delete a WORM-protected audit object before eligibility, When the request is processed, Then it is blocked (HTTP 403/Error) and a 'blocked_action' audit entry is appended with object_id and reason='WORM'. Given the WORM status API is called, When the object exists, Then it returns immutable=true, mode in {Compliance, LegalHold}, and retention_or_hold_expiration >= current_time.
Court-Ready Export (PDF/JSON) with Verifiable Checksums
Given an authorized user requests an audit export for a hold, When generation completes, Then the system provides a PDF human-readable timeline and a JSON machine-readable file containing all entries and metadata. And Then the JSON includes sha256 checksum over canonical JSON and head_hash; the PDF includes the same checksum and head_hash in its footer. Given any exported file is modified after download, When the verification tool/API is run against it, Then it reports checksum mismatch and status='invalid'.
Trusted Time Normalization and Drift Recording
Given any audit event is recorded, When the timestamp is captured, Then timestamp_utc is stored in ISO 8601 with 'Z' suffix and millisecond precision and sourced from a trusted time service. And Then the entry includes time_source_id and clock_offset_ms; the absolute value of clock_offset_ms must be <= 500 ms under normal operation. Given the time service is unreachable, When events are recorded, Then entries include time_sync_status='unsynced' and measured clock_offset_ms, and a health alert is raised.
Propagation Events and Blocked Actions Logging
Given a hold propagates to connected systems via API, When a propagation request is sent, Then an audit entry is appended per system with system_id, request_id, event='propagate', timestamp_utc, status in {queued, sent, acknowledged, failed}, retry_count, and error_detail if any. Given a user attempts an action prohibited by an active hold (e.g., delete, export redact, edit artifact), When the attempt occurs, Then the action is prevented and an audit entry is appended with actor_id, action, object_reference, timestamp_utc, and reason='prohibited_by_hold'.
Acknowledgments and Environment Metadata Capture
Given custodians or stakeholders are notified of a hold, When an acknowledgment is received, Then an audit entry is appended with recipient_id, method in {email, in_app, api}, timestamp_utc, ip_address, and user_agent. And Then every audit entry includes environment metadata: app_version, api_version, host_id, region, request_id, and actor_auth_context (user_id/service_id and mfa_present boolean).
Custodian Notice & Acknowledgment
"As a solo attorney, I want to notify custodians and capture their acknowledgment so that I can document compliance and reduce preservation risk."
Description

Generate mobile-friendly legal hold notices to custodians (clients, staff, vendors) via email and SMS, with configurable templates, languages, and instructions. Track delivery, opens, and acknowledgments with automated reminders, escalation rules, and a simple acknowledgment workflow (e-sign compatible) that feeds into the hold’s audit trail. Allow re-notification on scope changes and record all communications and attachments linked to the hold and matter.

Acceptance Criteria
Initial Notice Dispatch via Email and SMS
Given a litigation hold with at least one custodian with email and/or mobile number, When the hold is activated or the user clicks "Send Notices", Then the system sends the notice via all available channels (email, SMS) to each custodian within 60 seconds and records a send event per channel. Given a configured template, language, and instructions, When the notice is generated, Then the message includes the matter name, hold reason, required actions, response deadline, and a secure unique acknowledgment link. Given the recipient opens on a mobile device of width 320–414 px, When the notice link is rendered, Then the layout is responsive with readable font ≥14px, tappable CTA ≥40x40 px, and no horizontal scrolling. Given an invalid email or undeliverable phone number, When sending is attempted, Then the system marks the channel as "Failed – Invalid" and does not retry that channel automatically.
Delivery, Open, and Acknowledgment Tracking
Given a notice was sent, When the email/SMS provider returns a delivery receipt or bounce, Then the system stores delivery_status as Delivered/Bounced with timestamp and provider metadata. Given a custodian clicks the secure link, When the landing page loads, Then an Opened event is recorded with timestamp, channel (email/SMS), IP, and user-agent, and the status transitions to Opened. Given a custodian completes acknowledgment, When they submit, Then status transitions to Acknowledged, an acknowledgment timestamp is stored, and the associated hold shows acknowledgment complete for that custodian. Given no events occur, When 24 hours elapse after send, Then status remains Sent with zero opens and zero acknowledgments logged.
Automated Reminders and Escalation
Given a notice remains unacknowledged, When the configured reminder cadence (e.g., every 48 hours, max 5) runs, Then the system sends a reminder via all viable channels and logs each reminder event. Given a custodian acknowledges, When a reminder is scheduled, Then the system cancels pending reminders for that custodian. Given the acknowledgment deadline passes without acknowledgment, When the escalation rule is triggered (e.g., +24 hours past due), Then an escalation email is sent to the configured role with a list of noncompliant custodians and is logged. Given do-not-disturb hours are configured, When a reminder would fall within the DND window, Then it is deferred to the next allowed window.
E-signature Acknowledgment Workflow
Given e-sign is enabled for notices, When a custodian opens the acknowledgment page, Then they can sign via click-to-accept, typed, or drawn signature options after explicit consent to e-sign is captured. Given the acknowledgment is submitted, When processing completes, Then a signed PDF is generated with signer name, email/phone, timestamp (UTC), IP, and signature type and is attached to the hold and matter. Given an expired or invalid token link, When accessed, Then the system displays a secure error and offers Request new link without revealing hold details. Given multi-factor is required by policy, When the custodian begins acknowledgment, Then a one-time code is sent to the same channel and must be entered before signature is permitted.
Template, Language, and Instruction Configuration
Given an admin creates or edits a notice template, When variables like {CustodianName}, {MatterName}, {Deadline}, and {Instructions} are included, Then the preview renders with sample data and validates that all required placeholders are present. Given multiple languages are configured, When a custodian’s preferred language is set, Then the generated notice uses the matching language and falls back to a default when not available. Given attachments are configured (e.g., policy PDF), When the notice is sent, Then the attachment is delivered (as email attachment or secure download link) and logged with a content hash. Given a template is deactivated, When a user attempts to select it, Then it is not available for new notices but remains visible on prior communications for audit.
Re-notification on Hold Scope Changes
Given a hold’s scope changes (sources, date range, obligations), When the change is saved, Then the system prompts the user to re-notify impacted custodians and shows a change summary. Given the user confirms re-notification, When notices are sent, Then impacted custodians receive an Updated Hold Notice with version number and change summary, and unaffected custodians are not contacted. Given re-acknowledgment is required by policy, When re-notification is sent, Then prior acknowledgments remain preserved and a new acknowledgment is required and tracked under a new version. Given multiple changes occur within 2 hours, When re-notification would be redundant, Then the system batches them into a single consolidated update.
Comprehensive Audit Trail and Integrity
Given any communication event (send, deliver, open, reminder, escalation, acknowledgment), When it occurs, Then an immutable audit record is appended with actor/system id, timestamp (UTC), channel, payload hash (SHA-256), and event outcome. Given an authorized user exports the audit trail, When the export is generated, Then it includes a verification checksum and a reproducible event sequence suitable for evidentiary use. Given API integrations consume audit data, When the hold id is provided, Then the API returns paginated audit events with filtering by custodian, event type, and date range. Given least-privilege access controls, When a user without hold permissions attempts to view communications, Then access is denied and the attempt is logged.
Export Controls & Evidence Packaging
"As an attorney, I want controlled, tamper-evident exports of held materials so that any shared evidence remains intact and verifiable."
Description

Prevent unauthorized export, download, or alteration of held artifacts; when authorized, produce read-only evidence packages containing originals, normalized derivatives (e.g., PDF), a cryptographic manifest, hold metadata, and visible/invisible watermarks. Embed Hold ID and checksums into package manifests to enable verification on receipt or re-import. Log all export events and require elevated permissions with just-in-time approval for sensitive exports.

Acceptance Criteria
Block Unauthorized Export of Held Artifacts
Given an artifact is under an active Litigation Hold And the user lacks the "Export:Evidence" permission or the artifact is marked "Held" When the user attempts to export, download, print, or bulk-export the artifact via UI or API Then the system returns HTTP 403 with error code "EXPORT_HELD_FORBIDDEN" And no file bytes are streamed and no temporary package is created And any export UI controls for the artifact are disabled or hidden And the attempt is recorded in the audit log with user ID, artifact ID, Hold ID, channel (UI/API), timestamp, and outcome "Blocked"
Enforce Elevated Permission and JIT Approval for Sensitive Exports
Given an artifact is under an active Litigation Hold And the user has "Export:Evidence" permission but lacks an active "SensitiveExport" approval When the user initiates an evidence export Then a just-in-time approval request is created and routed to the configured approver group And the export cannot proceed until one approver grants approval with a stated rationale And approvals expire after 30 minutes if the export has not started And denial or expiration prevents export and is communicated to the requester with reason And all approval actions are logged with approver identity, timestamps, Hold ID, and decision
Generate Read-only Evidence Package with Required Components
Given an export request for held artifacts has been approved When the system generates the evidence package Then the package is read-only and contains: And the original files in their native formats And normalized derivatives per artifact type (PDF/A for documents, PNG for images, MP3 for audio, MP4 for video) And a cryptographic manifest listing each file path, byte size, and SHA-256 checksum And hold metadata including Hold ID, hold reason, initiator, start timestamp, and scope And visible and invisible watermarks applied to all derivatives And a manifest signature binding the contents to the manifest And the package can be opened without requiring proprietary software
Verify Package Integrity and Hold Metadata on Receipt/Re-import
Given a package produced by the system When a recipient runs Verify Package in the UI or submits the package for re-import Then the system validates the manifest signature and per-file SHA-256 checksums And any mismatch or missing file causes verification to fail with error code "EVIDENCE_INTEGRITY_FAILED" And the Hold ID in the package metadata must match the Hold ID(s) of the originating matter And successful verification is recorded with package hash, verifier identity, timestamp, and result "Pass"
Comprehensive Audit Logging for All Export Attempts and Outcomes
Given any export attempt (blocked, approved, failed, or completed) When the event occurs Then an immutable audit record is created containing export ID, requester, approver (if any), Hold ID(s), artifact IDs, timestamps (requested, approved, started, completed), channel (UI/API), source IP, package hash (if created), and outcome And audit records are queryable by Hold ID, user, date range, and outcome And audit records cannot be edited or deleted by any user
Watermarking and Tamper-Evidence in Exported Derivatives
Given derivatives are generated for an authorized export When a reviewer opens a derivative file Then a visible watermark is present on each page or frame including the Hold ID and the label "Evidence—Do Not Alter" And an invisible forensic watermark is embedded and detectable by the system’s verifier And derivative files are produced as read-only; attempts to edit result in a changed checksum that causes verification to fail
API Export Control Parity and Approval Token Enforcement
Given an external system calls the export API for held artifacts And the caller lacks a valid approval token linked to a current JIT approval and "Export:Evidence" scope When the API request is made Then the API responds with HTTP 403 and error code "EXPORT_APPROVAL_REQUIRED" And when a valid approval token is presented within 30 minutes of approval, the export proceeds under the same controls as the UI flow And all API requests and outcomes are logged with client ID, Hold ID(s), and token ID
Hold Review & Release Workflow
"As a case owner, I want a controlled process to review and release holds so that I can safely return systems to normal without losing defensibility."
Description

Provide a guided review to modify, extend, or release a hold with optional approvals, risk checks (e.g., related matters, pending requests), and staged releases across systems. On release, restore original retention policies, remove read-only locks, send custodian release notices, and capture a final summary in the audit trail. Support scheduled releases and the ability to reopen a hold with full version history retained.

Acceptance Criteria
Modify Hold During Guided Review
Given a user with Hold Manager role opens an active hold in Guided Review When they change the hold scope (custodians, artifacts, systems) and add a review note Then inline validation occurs and unsaved changes are indicated And on Save, a new version (v+1) is created with a diff view And the hold remains Active And changes propagate to all connected systems via API within 2 minutes, with per-system success logged And any failed propagation is surfaced with retry and "defer with reason" options And the audit trail records who, when, what changed, and system outcomes
Extend Hold with Optional Approval
Given the organization requires approval for extensions beyond the current expiration When the user proposes a new expiration date/time and provides a justification Then the system validates that the new expiration is later than the current expiration and that justification is non-empty And routes an approval request to configured approvers via in-app and email within 1 minute When an approver approves Then the expiration updates and propagates to connected systems within 2 minutes; audit is updated with approver, timestamp, and changes When an approver rejects Then the expiration remains unchanged; the requester is notified; audit captures the rejection and reason
Risk Checks Gate Release with Override
Given the user initiates a hold release and risk checks are enabled When related matters, active preservation requests, or pending exports/DSARs are detected Then a risk panel lists each issue with severity (Hard/Soft), counts, and deep links within 5 seconds And Hard risks disable the Release action for users without Override permission When a user with Override permission elects to proceed Then a mandatory reason is captured and, if configured, secondary approval is required before continuing And all risk check results and decisions (override/no override) are recorded in the audit trail
Staged Release Across Systems with Rollback
Given connected systems have a defined release order and dependencies When the user executes a staged release Then the system processes stages in order per system: restore original retention policy, remove read-only lock, verify via API health/check And real-time progress is shown with per-system status (Success/Failed/Skipped) When any stage fails Then prior successful stages are rolled back where supported and the release is marked Partially Released with remediation guidance And a downloadable error report is generated including system, step, timestamp, and error details
Release Restores Policies and Custodian Notices
Given a release completes successfully Then original retention policies are restored exactly as recorded pre-hold and read-only locks are removed in all connected systems And no document content or non-hold metadata is altered And custodian release notices are sent to 100% of custodians via configured channels including case/matter name, release date, and obligations end summary And delivery status is tracked (Delivered/Opened/Bounced) and reminders are sent after 48 hours to non-openers And the audit includes notice template version, recipients list, delivery outcomes, and timestamps
Scheduled Release Execution and Audit Summary
Given a user schedules a hold release for a future date/time in tenant timezone When saving the schedule Then validation ensures the time is in the future and the scheduler has permission; the schedule appears on the hold timeline And preflight risk checks run at schedule creation; any blocking issues are shown to the user When the scheduled time occurs Then risk checks re-run; if clear, the release executes; if not, execution is aborted and the scheduler is notified with reasons And a final execution summary (scheduler, execution time, systems affected, outcomes) is captured in the audit trail
Reopen Hold With Full Version History
Given a hold was previously released When a user with Hold Manager role selects Reopen and chooses a prior version snapshot Then a new version (v+1) is created with scope restored from the selected snapshot And locks and retention pauses are re-applied across systems with propagation status tracked And custodians receive reinstatement notices referencing the prior release And the full immutable version history remains available with diffs viewable across versions

Product Ideas

Innovative concepts that could enhance this product's value proposition.

Passkey Intake Portal

Let clients resume intake with passkeys—no passwords. Cuts lockouts and PII exposure; supports device biometrics and magic-link fallback.

Idea

Trust-Safe Tap-to-Pay

Collect retainers inside intake with Apple/Google Pay. Auto-split trust/operating deposits, issue receipts, and trigger retainer e-sign upon payment.

Idea

Template Jumpstart Studio

Import PDFs/Word and auto-map fields to Briefly templates. Suggest clauses by practice area and jurisdiction; produce a ready-to-use library in minutes.

Idea

Clinic Kiosk Mode

Run pop-up clinics with offline-friendly, multilingual kiosk intake. QR handoff to personal devices; batch print or e-sign in line to clear crowds fast.

Idea

Jurisdiction Smart Rules

Route clients through court-specific questions using ZIP/county detection. Auto-select forms, filing fees, and venue; reduce misfiled drafts and rework.

Idea

Curbside ID Sign

Display a QR to e-sign on phone and scan ID in one flow. Verify identity with liveness check; store encrypted ID snapshot in matter.

Idea

Audit Trail Vault

Generate immutable, time-stamped audit packets for each matter. Include consent logs, versioned drafts, and access history; one-click export for ethics inquiries.

Idea

Press Coverage

Imagined press coverage for this groundbreaking product concept.

P

Briefly Launches Passkey Intake and Device Trust to Cut Drop‑Off and Protect PII for Solo Consumer‑Law Firms

Imagined Press Article

Briefly, the legal intake and document automation platform built for solo consumer‑law attorneys handling high‑volume matters, today announced the general availability of its Passkey Intake Portal and Device Trust suite. The release brings passwordless, mobile‑first sign‑in with One‑Tap Resume, an Adaptive Magic‑Link fallback, Trusted Delegate access, PII Shield redaction, QR Handoff from shared devices, and a self‑serve Device Trust Manager—so solos can speed intake‑to‑engagement, reduce lockouts and re‑verification loops, and keep sensitive client data protected from the first touchpoint. Consumer‑law practices live and die by momentum. A client who can complete intake, e‑sign a retainer, and receive a court‑ready first draft in one sitting is far more likely to engage and stay engaged. Yet traditional portals force passwords, resets, and repeated identity prompts that stall progress and increase exposure when links get forwarded. Briefly’s new passkey‑based experience removes friction while raising the bar on security and auditability, aligning with the platform’s core promise to validate facts once, auto‑assemble documents, and secure instant e‑sign—all in under 30 minutes. How it works • One‑Tap Resume with Passkeys: Clients sign in with Face ID/Touch ID or device biometrics—no passwords or security questions. Autosaved progress drops them exactly where they left off, slashing drop‑off, support tickets, and re‑entry errors. • Adaptive Magic‑Link: If a device can’t use passkeys, Briefly automatically offers a time‑limited, device‑bound magic link with firm‑defined policies (email vs. SMS, expiration, one‑use). The flow encourages a passkey setup after sign‑in to keep future logins passwordless. • Trusted Delegate: Clients can securely invite a helper—spouse, translator, caregiver—via a restricted, expiring link. Firms can limit what fields are visible (hide SSN/DOB), restrict who can e‑sign, and see a full log of delegate actions. • Device Trust Manager: Clients can view and revoke authorized devices in one tap, and firms can force sign‑outs across all sessions for a matter. Real‑time alerts flag new device access to keep everyone informed. • QR Handoff: For clinics and courthouse hallways, clients can scan a short‑lived QR to move an intake session from a shared device to their own phone, then set up a passkey there—minimizing data entry on public machines. • PII Shield: Until a passkey login is completed, sensitive data stays redacted and notifications show minimal context. Pre‑auth download controls and screenshot limitations reduce accidental exposure if links are forwarded. Security that is provable—not just promised Beyond strong authentication and access controls, Briefly’s platform records a complete, tamper‑evident trail for every matter. ChainSeal Ledger creates an append‑only, hash‑chained record of intake edits, consents, e‑sign events, payments, and accesses. TimeScope Replay reconstructs exactly what each participant saw when they gave consent, while Consent Diff shows how disclosure language evolved and who accepted which version. Provenance Tags track the origin and confidence of each data point—client input, delegate action, OCR/ID scan, or import—so attorneys can quickly answer the question: Why do we trust this data? Together, these capabilities strengthen enforceability of signatures, reduce disputes, and accelerate responses to bar or ethics inquiries. With a single click, firms can export Regulator Pack, a pre‑indexed binder and machine‑readable archive tailored to common regulatory questions, complete with checksums and a lightweight verifier. Quotes Our goal is simple: make intake effortless for clients and provably secure for lawyers, without asking anyone to memorize another password, said Alex Kim, founder and CEO of Briefly. Passkeys and device trust give solos the best of both worlds—frictionless mobile re‑entry and a higher standard of assurance from the very first interaction. As a consumer‑law solo, I can’t babysit portals or chase codes, and I won’t compromise on client privacy, said Sam T., a beta user and veteran attorney. With One‑Tap Resume and PII Shield, intakes that used to take days of back‑and‑forth now finish in a single lunch break, and I have the audit trail to prove what happened if a question ever arises. Why it matters now Solos are increasingly mobile and often practice in environments—courthouses, clinics, community events—where speed and clarity are critical. Early adopters of Briefly’s passkey experience report cutting intake‑to‑engagement under 30 minutes, reducing retyping errors by up to 60%, and reclaiming as much as six billable hours weekly. By eliminating password hurdles and locking down sensitive details until the right person is verified, firms see higher completion rates and fewer support escalations. Availability Passkey Intake and Device Trust capabilities are available today to all Briefly customers at no additional charge. Adaptive Magic‑Link, Trusted Delegate, QR Handoff, and PII Shield are enabled by default with firm‑level policy controls. ChainSeal Ledger, TimeScope Replay, Consent Diff, Provenance Tags, and Regulator Pack are included in Briefly’s core audit and compliance toolkit. About Briefly Briefly is legal intake and document automation for solo consumer‑law attorneys handling high‑volume matters. Mobile‑friendly, guided questionnaires validate facts once, then assemble a complete retainer and court‑ready first draft for instant e‑sign—eliminating retyping and signature chase. Firms consistently cut intake‑to‑engagement under 30 minutes, reduce errors by up to 60%, and reclaim six billable hours weekly. Media contact Press Inquiries: press@briefly.legal Phone: +1‑415‑555‑0137 Website: https://getbriefly.com

P

Briefly Unveils Trust‑Safe Payments Suite with Tap‑to‑Pay and Auto‑Reconciled IOLTA Compliance

Imagined Press Article

Briefly today announced a comprehensive Trust‑Safe Payments Suite that brings tap‑to‑pay retainers, built‑in IOLTA safeguards, installment autopay, surcharge compliance, dispute defense, and low‑fee bank transfers directly into the intake experience. Designed for solo consumer‑law attorneys who close matters in hallways, clinics, and over the phone, the suite pairs speed with ethics‑first controls so firms can get paid faster without risking commingling or chargebacks. The announcement centers on six integrated capabilities: Trust Split Guard, Tap Terminal, Installment AutoPay, Surcharge Compliance, Dispute Shield, and Bank Pay Saver. Together they transform the moment of intent into a compliant, auditable payment event and immediately route funds to the right place—trust vs. operating—with the audit trail and evidence packet a court (or card network) expects. Why it matters Consumer‑law solos often face a bind: make it easy to pay and risk ethics pitfalls, or enforce strict controls and watch clients abandon the process. External point‑of‑sale hardware, one‑off payment links, and manual ledger entries create gaps that invite errors, disputes, and wasted time. By embedding payments inside a guided intake and tying every authorization back to a signed retainer and identity check, Briefly gives solos the speed of a modern checkout with the guardrails of a well‑run trust account. What’s in the suite • Trust Split Guard: Enforces compliant trust vs. operating routing at checkout. It automatically classifies amounts, blocks prohibited commingling or fee withdrawals from trust, writes IOLTA‑ready ledger entries per matter, and captures the necessary client consents. State‑aware rules and one‑click reconciliation exports shrink bookkeeping time and reduce ethics risk. • Tap Terminal: Turns any modern phone into a tap‑to‑pay point of sale inside intake—no extra hardware. Collect retainers via Apple Pay or Google Pay contactless in court hallways, clinics, or curbside, auto‑attach payments to the matter, issue branded receipts, and trigger the retainer e‑sign flow on the spot. • Installment AutoPay: Offer compliant payment plans or trust top‑ups without extra tools. Firms set installments and caps, capture a single authorization, and let Briefly auto‑collect via card or bank with smart reminders, automatic retries, and a live plan dashboard. • Surcharge Compliance: When permitted, Briefly applies or suppresses surcharges based on card type and jurisdiction, shows clear client disclosures, routes convenience fees to operating (never trust), and offers no‑fee ACH alternatives—maximizing savings while staying transparent. • Dispute Shield: If a dispute occurs, Briefly auto‑bundles the signed retainer, payment authorization, intake audit trail, device/IP data, and receipts into a ready‑to‑submit evidence packet—cutting response time and boosting win rates. • Bank Pay Saver: Prominently offers low‑fee bank transfers for larger retainers. Instant account verification, NSF/retry workflows, and clear settlement ETAs keep clients informed. Firms can optionally delay countersign or work start until funds clear, preventing unfunded engagements. Integrated with identity and consent The payments suite is deeply integrated with Briefly’s identity and audit features. Instant QR Sign lets attorneys launch a combined e‑sign and ID check on a client’s phone in seconds. Liveness Pulse and Smart Frame Capture improve first‑try success, while ID Auto‑Match reduces typos by parsing barcodes and auto‑filling intake fields. Signer Bind Proof cryptographically binds the verified ID to the e‑signature certificate and audit trail. ChainSeal Ledger and TimeScope Replay provide tamper‑evident and point‑in‑time records of what was shown and agreed to when payment and consent were captured. Quotes Getting paid should not put solos at odds with ethics rules, said Priya Desai, VP of Product at Briefly. With Trust Split Guard and Tap Terminal, you can collect a retainer on the spot and know every dollar is routed and recorded correctly—no hardware to lug, no spreadsheets to reconcile. I close more matters in the same hour I meet clients, and I sleep better knowing surcharges aren’t misapplied and trust funds are handled the right way, said Carlos M., a consumer‑law solo and early adopter. The dispute packet alone has changed the game; I don’t dread chargebacks anymore. Proven impact Early Briefly users report cutting intake‑to‑engagement under 30 minutes and reclaiming up to six billable hours a week by eliminating retyping and signature chase. Bringing payments into that same flow compounds the efficiency: clients authorize once, sign once, and get a clear, mobile‑friendly receipt with all required disclosures. Firms see fewer failed payments, fewer unfunded engagements, and faster cash flow. Availability The Trust‑Safe Payments Suite is available today to all Briefly customers. Tap Terminal requires a compatible device; Trust Split Guard, Installment AutoPay, Surcharge Compliance, Dispute Shield, and Bank Pay Saver are enabled with firm‑level policy controls and jurisdictional settings. About Briefly Briefly is legal intake and document automation for solo consumer‑law attorneys handling high‑volume matters. Guided, mobile‑first questionnaires validate facts once, then assemble a complete retainer and court‑ready first draft for instant e‑sign. By eliminating retyping and signature chase, Briefly helps solos reduce errors by up to 60% and reclaim six billable hours weekly. Media contact Press Inquiries: press@briefly.legal Phone: +1‑415‑555‑0137 Website: https://getbriefly.com

P

Briefly Debuts Court‑Ready Drafting Intelligence and Jurisdiction Automation to Eliminate Rework and Rejections

Imagined Press Article

Briefly announced a major expansion of its drafting and court‑readiness capabilities, combining AI‑assisted template mapping with jurisdiction‑aware automation. The release brings Smart Map AI, Clause Compass, Variant Builder, Field Harmonizer, Live Fill Preview, Precedent Miner, and Redline Sync together with court‑specific tools like Boundary Snap, Form Sync Live, Fee SmartCalc, Venue Verifier, Filing Playbook, and Deadline Mapper. The result is a single flow that validates facts once, produces a compliant first draft, selects the right forms and fees, and schedules deadlines—before a matter leaves intake. Why it matters Solo consumer‑law attorneys routinely lose time to out‑of‑date forms, misapplied venue rules, and drafts that must be rebuilt when a detail changes. A fragmented tool stack compounds the problem: PDFs need mapping; clauses must reflect local rules; forms must be watched for updates; and deadlines vary by service method and court holidays. Briefly’s new capabilities close these gaps so high‑volume practices can scale quality, not chaos. Smarter templates from day one • Smart Map AI reads PDFs and Word files to auto‑detect fields, signatures, and checkboxes, mapping them to Briefly’s merge fields with confidence scores. One‑click fixes resolve low‑confidence matches, cutting hours of manual setup and reducing template errors. • Field Harmonizer normalizes field names across imported forms—merging duplicates and enforcing a reusable schema that powers questionnaires and documents. Data flows cleanly across matters without retyping. • Precedent Miner ingests past retainers and pleadings, extracting reusable clauses and tagging them by outcome and jurisdiction. Attorneys build a trusted clause library in minutes instead of weeks. • Clause Compass recommends the right clauses by practice area and venue, with plain‑language rationale and rule citations. Risk flags highlight required language so solos can draft with confidence. • Variant Builder lets attorneys create jurisdiction‑specific variants from a single base template. Changes cascade safely with side‑by‑side diffs, maintaining consistency while respecting local nuances. • Live Fill Preview generates instant test outputs with sample or real intake data. Attorneys can toggle fact patterns to catch conditional text gaps before go‑live. • Redline Sync keeps Word pros in their comfort zone—export for tracked changes and re‑import without breaking merge fields or logic. Court‑aware from intake to filing • Boundary Snap resolves the correct county and venue from a client’s address or live GPS, even across split ZIP codes and rural routes, and logs a confidence score with a mini‑map. • Venue Verifier checks eligibility against claim‑specific rules (e.g., residency, transaction location, property county) and asks only the minimal extra questions to confirm. It generates a plain‑language rationale with citations that can be inserted into the audit trail or pleading. • Form Sync Live always pulls the latest court‑mandated forms for the detected venue and safely remaps fields when forms change, with deprecation alerts and one‑click migration. • Fee SmartCalc calculates exact filing fees, surcharges, and e‑file provider add‑ons per venue and case type—and auto‑fills fee waiver forms when criteria are met. Totals flow directly into Briefly’s Trust Split Guard. • Filing Playbook provides a step‑by‑step, venue‑specific checklist—submission channel, coversheets, copy counts, office hours, addresses, and formatting quirks—optimized for courthouse use. • Deadline Mapper turns local rules into concrete dates for service, responses, and hearings, accounting for weekends, court holidays, and service method buffers. Tasks can be pushed to calendars with reminders and rule references. Quotes Solos shouldn’t have to be detectives to file correctly, said Elena Park, Head of Legal Strategy at Briefly. By unifying template intelligence with venue rules, lawyers get a compliant draft and a reliable plan of action before they leave intake—no last‑minute scramble or clerk callbacks. I used to spend hours chasing the right form version and re‑drafting when a venue changed, said Ivy L., an operations‑minded solo who piloted the new features. Now Smart Map AI and Variant Builder do the heavy lifting, and Venue Verifier plus Form Sync Live keep me out of trouble with local rules. My first‑pass acceptance rate is up, and my blood pressure is down. Proven impact Early adopters report significant reductions in rework and rejected filings, alongside the broader Briefly benefits of completing intake‑to‑engagement in under 30 minutes and cutting errors by up to 60%. By pairing drafting with court intelligence, solos build repeatable workflows that scale across repetitive, high‑volume matters without sacrificing accuracy. Audit‑ready by design Every step—venue decisions, template versions, clause rationales, fee calculations, and deadlines—feeds Briefly’s ChainSeal Ledger and TimeScope Replay. Consent Diff links who accepted which disclosure language and when, while Regulator Pack exports a pre‑indexed binder and machine‑readable JSON with checksums so regulators (and opposing counsel) can verify integrity independently. Availability The drafting intelligence and jurisdiction automation capabilities are available today to all Briefly customers. Smart Map AI, Clause Compass, Variant Builder, Field Harmonizer, Live Fill Preview, Precedent Miner, and Redline Sync are included with template automation. Boundary Snap, Form Sync Live, Fee SmartCalc, Venue Verifier, Filing Playbook, and Deadline Mapper are enabled with venue detection and rule updates managed by Briefly. About Briefly Briefly is legal intake and document automation for solo consumer‑law attorneys handling high‑volume matters. Guided, mobile‑first questionnaires validate facts once, then assemble a complete retainer and court‑ready first draft for instant e‑sign, helping firms eliminate retyping, reduce errors, and reclaim hours each week. Media contact Press Inquiries: press@briefly.legal Phone: +1‑415‑555‑0137 Website: https://getbriefly.com

P

Briefly Introduces Clinic Kiosk Mode with Offline Sync and Multilingual E‑Sign to Move Lines, Not Paper

Imagined Press Article

Briefly announced Clinic Kiosk Mode, a set of offline‑friendly, multilingual tools that keep high‑volume legal clinics moving even when Wi‑Fi is unreliable and lines are out the door. The release includes Offline Sync Queue, Instant Language Swap, Queue Tickets, Privacy Reset, Batch Pack Print, and Sign Station—plus seamless QR Handoff to personal devices and Instant QR Sign for on‑phone e‑sign and ID checks. The goal: improve comprehension, speed engagement, and preserve confidentiality in the busiest, least forgiving environments. Clinics at libraries, churches, and community centers play a vital role in expanding access to consumer justice. But they also concentrate the worst operational challenges into a few hours: shared devices, mixed language needs, sporadic connectivity, and a rush to get retainers signed so attorneys can start real work. By capturing intakes, uploads, and signatures offline, enabling one‑tap language changes, and orchestrating the flow of people with scannable tickets, Briefly helps mission‑driven solos and volunteers deliver order, speed, and dignity at scale. How it works • Offline Sync Queue: Staff can capture full intakes, uploads, and signatures even when the network drops. Data is encrypted and queued locally, then auto‑syncs the moment connectivity returns. Conflict‑safe merge rules prevent duplicates and preserve who did what and when. • Instant Language Swap: With one tap, staff can switch the entire kiosk flow—questions, help text, receipts, and printed packets—into the client’s preferred language. The system can detect preference from device locale or a quick chooser. An English helper overlay keeps staff oriented. • Queue Tickets: Briefly issues scannable, QR‑based tickets that show place‑in‑line on the client’s phone and on a staff triage board. Attendees are routed to the right station (intake, review, e‑sign, print), and vulnerable clients can be prioritized with a drag‑and‑drop action. • Privacy Reset: Between users, a visible countdown and one‑tap reset clears forms, files, and clipboard data, locks downloads, and hides notifications, protecting PII on shared devices. • Batch Pack Print: Staff can generate collated, barcoded print packets in one click for everyone currently queued. Scanning barcodes later auto‑files signed pages back to the right case. • Sign Station: A dedicated e‑sign lane cycles through next‑ready clients. Large‑type, ADA‑friendly prompts help finish each packet in under a minute. Staff see real‑time completion and can escalate edge cases to attorney review without blocking the line. • QR Handoff and Instant QR Sign: Clients can move a kiosk session to their own phone via a short‑lived QR and finish intake or e‑sign privately. A combined e‑sign + ID check runs on the phone with Liveness Pulse, Smart Frame Capture, and ID Auto‑Match improving first‑try success. Security and accountability, even under pressure PII Shield keeps sensitive data redacted until a passkey login or verified QR session is in place, while Device Trust Manager lets clients revoke lost devices and firms force sign‑outs across a matter. ChainSeal Ledger and TimeScope Replay provide a tamper‑evident, point‑in‑time record of exactly what each participant saw and signed. Consent Diff prompts for re‑consent when disclosures change, and Regulator Pack assembles a one‑click export tuned for common ethics questions. Quotes At pop‑up clinics, chaos is the default: spotty Wi‑Fi, short attention spans, and a lot of good intentions competing for too few minutes, said Marcus Lee, COO of Briefly. Clinic Kiosk Mode turns that reality into a repeatable flow that moves lines without sacrificing comprehension or confidentiality. We used to apologize for delays and language mismatches, and we worried about data left behind on shared machines, said Dana C., a mission‑first solo who runs monthly community clinics. Now we print packets in batches, swap languages instantly, and finish signatures in a dedicated lane. It feels like an airport boarding process—in the best way. Measurable relief for frontline teams Early pilots report shorter lines, fewer skipped steps, and higher completion rates. With autosave and One‑Tap Resume on personal devices, attendees can step away and pick up where they left off without starting over. Staff spend less time explaining forms and more time resolving edge cases. As with Briefly’s core product, firms see intake‑to‑engagement times drop under 30 minutes and error rates fall by up to 60%. Availability Clinic Kiosk Mode and its related capabilities—Offline Sync Queue, Instant Language Swap, Queue Tickets, Privacy Reset, Batch Pack Print, Sign Station, QR Handoff, and Instant QR Sign—are available today. Firms can enable clinic features in settings and customize policies for language support, privacy, and offline retention. About Briefly Briefly is legal intake and document automation for solo consumer‑law attorneys handling high‑volume matters. Guided, mobile‑first questionnaires validate facts once, assemble a complete retainer and court‑ready first draft, and deliver instant e‑sign—eliminating retyping and signature chase so attorneys can reclaim six billable hours weekly. Media contact Press Inquiries: press@briefly.legal Phone: +1‑415‑555‑0137 Website: https://getbriefly.com

Want More Amazing Product Ideas?

Subscribe to receive a fresh, AI-generated product idea in your inbox every day. It's completely free, and you might just discover your next big thing!

Product team collaborating

Transform ideas into products

Full.CX effortlessly brings product visions to life.

This product was entirely generated using our AI and advanced algorithms. When you upgrade, you'll gain access to detailed product requirements, user personas, and feature specifications just like what you see below.