Federal Forensic Case Management Suite
Technical system specifications, database schemas, ACID transaction logic, and REST API references for the Custody Suite Ecosystem.
1. Project Overview
Custody Suite is a secure web-based system designed for managing case dossiers and tracking physical evidence collected at offense scenes. It provides a tamper-evident, legally auditable Chain of Custody record.
By integrating advanced MySQL database View filters, transactional Stored Procedures, and automated auditing Triggers directly on the database engine, the platform enforces referential integrity independent of application-level routing.
2. Technology Stack
The architecture is selected to support high-performance relational operations, secure data isolation, and concurrent process server executions.
| Technology | Role |
|---|---|
| Next.js 15.1.4 | Frontend View |
| FastAPI 0.115.6 | Backend Controller |
| MySQL Server 8.0 | Relational Database |
| Concurrently 9.1.2 | Server Launcher |
* Full justifications visible on larger screens.
3. System Architecture
The diagram below illustrates the request lifecycle for a custody handover transaction, showing how it is processed by the database.
[Evidence Handover Action]
│
▼
👤 User Client ---> ⚛ React UI (NextJS tab synchronization)
│
▼ (HTTP POST payload)
⚡ FastAPI Controller (Pydantic validator)
│
├─(Invoke Stored Procedure)──> 🔒 MySQL Database (sp_transfer_custody)
│ │
│<─(Transaction SUCCESS)────────────┤
│ ▼
│ [Update status & insert log]
│
├─(Fire Update Trigger)──────> ⚡ MySQL Database (trg_evidence_update)
│ │
│ ▼
│ [Write to audit_logs table]
│
▼
👤 Client UI Refresh (Real-time timeline update)
4. Workspace Folder Structure
backend/app/: Houses REST API controllers (`main.py`) and the database connection manager (`db.py`), which executes stored procedures and compiles views.
database/: Contains the DDL schemas (`schema.sql`) and classifications seed files (`seed.sql`).
src/components/: Modular workspace tabs handling case dossier configurations, physical evidence timelines, and user account credentials.
5. Relational Database Design
The entity relationship diagram details key mapping dependencies, foreign keys, and audit log links.
users table ├── user_id (Primary Key, INT) ├── employee_id (Unique, VARCHAR) ├── role_id (Foreign Key referencing roles) └── department_id (Foreign Key referencing departments) │ ├── (1:N Relationship) ▼ cases table ├── case_id (Primary Key, INT) ├── case_number (Unique, VARCHAR) ├── lead_investigator (Foreign Key referencing users.user_id ON DELETE SET NULL) └── crime_scene_id (Foreign Key referencing crime_scenes) │ ├─ (1:N Relationship) ▼ evidence table ├── evidence_id (Primary Key, INT) ├── barcode (Unique, VARCHAR) ├── case_id (Foreign Key referencing cases.case_id ON DELETE CASCADE) └── collected_by (Foreign Key referencing users.user_id ON DELETE SET NULL) │ ├─ (1:N Relationship) ▼ evidence_custody table ├── custody_id (Primary Key, INT) ├── evidence_id (Foreign Key referencing evidence.evidence_id ON DELETE CASCADE) ├── from_user (Foreign Key referencing users.user_id ON DELETE SET NULL) └── to_user (Foreign Key referencing users.user_id ON DELETE SET NULL)
Relational Table Schema Specifications
Defines system permission profiles: role_id (PK), role_name (Unique), and description.
Defines laboratory or administrative divisions: department_id (PK), department_name (Unique), and location.
Credentials and metadata: user_id (PK), employee_id (Unique, EMP-XXXX), first_name, last_name, email (Unique), phone, password_hash, role_id (FK), department_id (FK), and status.
Geolocated offense zones: scene_id (PK), address, city, district, state, country, latitude, longitude, and description.
Primary dossiers: case_id (PK), case_number (Unique, CASE-YYYY-XXXX), title, description, crime_type, priority, status, opened_date, closed_date, lead_investigator (FK), and crime_scene_id (FK).
Unified participants profile: person_id (PK), first_name, last_name, gender, dob, phone, email, and address.
Case relations linking to persons: case_id (FK), person_id (FK), and customized roles (e.g. alibi, injuries, statements).
Physical assets log: evidence_id (PK), barcode (Unique, EVID-XXXX-XX), case_id (FK), type_id, description, collected_by (FK), collected_date, storage_location, current_status, and is_sealed.
Chain tracking history: custody_id (PK), evidence_id (FK), from_user (FK), to_user (FK), transfer_date, purpose, location, and remarks.
Engine security log: log_id (PK), user_id (FK), action, table_name, record_id, timestamp, and ip_address.
6. API Endpoint Reference
| Method | Endpoint |
|---|---|
| GET | /api/cases |
| POST | /api/cases |
| PUT | /api/cases/{id} |
| DELETE | /api/cases/{id} |
| GET | /api/evidence |
| POST | /api/evidence-custody |
| POST | /api/users |
| DELETE | /api/users/{id} |
* Usage details visible on larger screens.
POST /api/users
Registers a new user credentials. Auto-hashes the password using `bcrypt` and generates the employee ID.
// Request Payload: application/json { "first_name": "Marcus", "last_name": "Burnett", "email": "marcus@forensics.gov", "phone": "+1 (555) 012-3456", "password": "SecurePassword123", "role_id": 2, // 2 = Investigator "department_id": 1, // 1 = Forensic Unit "status": "Active" } // Response: 201 Created { "user_id": 4, "employee_id": "EMP-004", "first_name": "Marcus", "last_name": "Burnett", "email": "marcus@forensics.gov", "status": "Active" }
POST /api/evidence-custody
Invokes the stored procedure to transfer custody and logs the handoff details.
// Request Payload: application/json { "evidence_id": 4, "from_user": 2, "to_user": 3, "purpose": "Autopsy Testing", "location": "Medical Lab, Vault A", "remarks": "Container seal verified" } // Response: 201 Created { "custody_id": 14, "evidence_id": 4, "from_user": 2, "to_user": 3, "transfer_date": "2026-07-10T09:20:00" }
7. Database Procedural SQL Code
Stored Procedure Transaction (`sp_transfer_custody`)
Performs evidence custody handoffs within an atomic transaction. If any update fails, the entire transaction is rolled back:
CREATE PROCEDURE sp_transfer_custody( IN p_evidence_id INT, IN p_from_user INT, IN p_to_user INT, IN p_purpose VARCHAR(255), IN p_location VARCHAR(255), IN p_remarks TEXT, IN p_status VARCHAR(50), OUT p_success BOOLEAN ) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SET p_success = FALSE; END; START TRANSACTION; INSERT INTO evidence_custody (evidence_id, from_user, to_user, transfer_date, purpose, location, remarks) VALUES (p_evidence_id, p_from_user, p_to_user, NOW(), p_purpose, p_location, p_remarks); UPDATE evidence SET current_status = p_status, storage_location = p_location WHERE evidence_id = p_evidence_id; COMMIT; SET p_success = TRUE; END;
Automated Database trigger (`trg_evidence_update`)
Fires automatically on the database server whenever an evidence status updates, logging the action in `audit_logs`:
CREATE TRIGGER trg_evidence_update AFTER UPDATE ON evidence FOR EACH ROW BEGIN IF OLD.current_status <> NEW.current_status OR OLD.storage_location <> NEW.storage_location THEN INSERT INTO audit_logs (user_id, action, table_name, record_id, timestamp, ip_address) VALUES (NEW.collected_by, CONCAT('EVIDENCE_UPDATE: status=', NEW.current_status, ', location=', NEW.storage_location), 'evidence', NEW.evidence_id, NOW(), '127.0.0.1'); END IF; END;
Aggregated Database view (`v_case_summaries`)
Combines multiple tables and calculates live totals, enabling the backend to fetch case summaries with a single query:
CREATE OR REPLACE VIEW v_case_summaries AS SELECT c.case_id, c.case_number, c.title, c.description, c.crime_type, c.priority, c.status, CONCAT(u.first_name, ' ', u.last_name) AS lead_investigator_name, (SELECT COUNT(*) FROM evidence e WHERE e.case_id = c.case_id) AS evidence_count, (SELECT COUNT(*) FROM suspects s WHERE s.case_id = c.case_id) AS suspect_count FROM cases c LEFT JOIN users u ON c.lead_investigator = u.user_id;
8. Security & Data Safeguards
- ✓Password Hashing via bcrypt
User accounts created in the system have their passwords securely hashed using bcrypt prior to database storage.
- ✓Self-Deletion Protection
The frontend hides the deletion controls on the logged-in user's profile card, protecting active sessions from accidental self-deletion.
- ✓Orphan Prevention Cascades
MySQL schemas utilize ON DELETE SET NULL on creator references, preserving forensic logs even when user accounts are deactivated.
9. Technical Challenges
MySQL Semicolon Splits inside Stored Procedures
- Problem: Standard SQL runners split strings by semicolons, breaking stored procedures.
- Cause: Internal semicolons within BEGIN/END blocks are incorrectly parsed as statement separators.
- Resolution: Executed procedural definitions as unified raw SQL blocks directly during the initialization routine.
Workspace Session Reactivity
- Problem: Browser refreshes reset the workspace back to the initial dashboard.
- Cause: React states are reset when the page reloads.
- Resolution: Synchronized active workspace coordinates with browser URL parameters (`?tab=...&caseId=...`), preserving views across refreshes.
10. Configuration & Roadmap
.env.example
# MySQL Database Coordinates DB_HOST=127.0.0.1 DB_PORT=3306 DB_NAME=forensic_management_system DB_USER=root DB_PASSWORD=your_mysql_password
Roadmap
Core Case Flow
FastAPI CRUD, NextJS migration, timeline logging.
Advanced MySQL
Stored procedures, views, triggers, and audit logs.
Signature & Scan
Sign-off signature pads and mobile barcode scanning.