# Eliza Kragh v. MAD Court Docket Website - Design Specification ## Project Overview A public-facing website to display court documents and filings for the ongoing lawsuit: **Eliza Kragh v. Montana Association of the Deaf**. The system provides public transparency for court proceedings while allowing administrative management of documents and user notifications. ## Technical Architecture ### System Components ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Next.js 15.4 │ │ Express.js 6 │ │ PostgreSQL 17.5 │ │ Frontend │◄──►│ Backend API │◄──►│ Database │ │ (Port 3000) │ │ (Port 3001) │ │ (Port 5432) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ ┌─────────────────┐ │ │ │ Redis │ │ └──────────────►│ Cache/Session │◄─────────────┘ │ (Port 6379) │ └─────────────────┘ │ ┌─────────────────┐ │ File System │ │ /uploads/ │ └─────────────────┘ ``` **Technology Stack (June 2025 Latest Versions):** - **Frontend**: Next.js 15.4.0 with React 19, TypeScript 6.0, Tailwind CSS - **Backend**: Node.js 22 LTS, Express.js 6.0, TypeScript 6.0, Prisma 5.0 - **Database**: PostgreSQL 17.5 with Redis caching - **Infrastructure**: Docker Engine 28.1.1, Nginx reverse proxy ## Database Schema ### Tables Structure ```sql -- Docket Entries (main court filings) CREATE TABLE docket_entries ( id SERIAL PRIMARY KEY, date DATE NOT NULL, document_type VARCHAR(100) NOT NULL, summary TEXT NOT NULL, court_notes TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Documents (PDFs associated with entries) CREATE TABLE documents ( id SERIAL PRIMARY KEY, docket_entry_id INTEGER REFERENCES docket_entries(id) ON DELETE CASCADE, original_filename VARCHAR(255) NOT NULL, stored_filename VARCHAR(255) NOT NULL UNIQUE, file_path VARCHAR(500) NOT NULL, title VARCHAR(255) NOT NULL, summary TEXT, notes TEXT, is_primary BOOLEAN DEFAULT FALSE, file_size INTEGER NOT NULL, display_order INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Email Subscriptions CREATE TABLE subscriptions ( id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, unsubscribe_token VARCHAR(255) UNIQUE ); -- Admin Users CREATE TABLE admin_users ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP ); -- Indexes for performance CREATE INDEX idx_docket_entries_date ON docket_entries(date DESC); CREATE INDEX idx_documents_docket_entry ON documents(docket_entry_id); CREATE INDEX idx_documents_display_order ON documents(docket_entry_id, display_order); CREATE INDEX idx_subscriptions_active ON subscriptions(is_active); ``` ## API Endpoints ### Public Endpoints ``` GET /api/docket-entries Response: Array of docket entries with associated documents { "entries": [ { "id": 1, "date": "2024-12-15", "document_type": "Motion to Dismiss", "summary": "Defendant's motion...", "court_notes": "Motion filed within deadline...", "documents": [ { "id": 1, "title": "Main Document", "summary": "Primary motion document", "notes": "Filed by defendant's counsel", "is_primary": true, "display_order": 0 } ] } ] } GET /api/documents/:id/download Response: PDF file stream Headers: Content-Type: application/pdf POST /api/subscribe Body: { "email": "user@example.com" } Response: { "success": true, "message": "Subscribed successfully" } GET /api/unsubscribe/:token Response: Unsubscribe confirmation page ``` ### Admin Endpoints (Protected) ``` POST /api/auth/login Body: { "username": "admin", "password": "password" } Response: { "token": "jwt-token", "expires": "timestamp" } POST /api/docket-entries Body: { "date": "2024-12-15", "document_type": "Motion", "summary": "Entry summary", "court_notes": "Court notes", "documents": [ { "title": "Main Document", "summary": "Document summary", "notes": "Document notes", "is_primary": true, "file": "base64-encoded-pdf" } ] } PUT /api/docket-entries/:id Body: Updated entry data Response: Updated entry object DELETE /api/docket-entries/:id Response: { "success": true } POST /api/documents Body: FormData with file and metadata Response: Created document object PUT /api/documents/:id Body: Updated document metadata Response: Updated document object PUT /api/documents/:id/replace Body: FormData with new file Response: Updated document object DELETE /api/documents/:id Response: { "success": true } ``` ## File Management System ### UUID-Based Naming Scheme ``` Format: {entry-id}_{document-type}_{uuid}.pdf Examples: 001_main_a7b3c9d2-4e5f-6789-abcd-ef0123456789.pdf 001_exhibit_b8c4d0e3-5f60-789a-bcde-f01234567890.pdf 002_main_c9d5e1f4-6071-890b-cdef-012345678901.pdf ``` ### Directory Structure ``` uploads/ ├── 2024/ │ ├── 12/ │ │ ├── 001_main_a7b3c9d2-4e5f-6789-abcd-ef0123456789.pdf │ │ ├── 001_exhibit_b8c4d0e3-5f60-789a-bcde-f01234567890.pdf │ │ └── 002_main_c9d5e1f4-6071-890b-cdef-012345678901.pdf │ └── 11/ │ └── [previous month files] └── 2025/ └── [future files] ``` ### File Upload Process 1. Validate file type (PDF only) and size (max 10MB) 2. Generate UUID for filename 3. Create year/month directory structure 4. Save file with UUID-based name 5. Store metadata in database 6. Return success response with document ID ## Frontend Components ### Public Interface Components ``` components/ ├── Layout/ │ ├── Header.tsx # Site header with title and subscribe button │ ├── Footer.tsx # Site footer │ └── Layout.tsx # Main layout wrapper ├── Docket/ │ ├── DocketList.tsx # List of all docket entries │ ├── DocketEntry.tsx # Individual entry display │ ├── DocumentList.tsx # Documents within an entry │ └── DocumentViewer.tsx # PDF viewing modal ├── Subscription/ │ ├── SubscribeForm.tsx # Email subscription form │ └── SubscribeModal.tsx # Subscription confirmation modal └── Common/ ├── LoadingSpinner.tsx # Loading states ├── ErrorMessage.tsx # Error display └── Button.tsx # Reusable button component ``` ### Admin Interface Components ``` components/admin/ ├── Auth/ │ └── LoginForm.tsx # Admin login form ├── Dashboard/ │ ├── Dashboard.tsx # Main admin dashboard │ ├── EntryList.tsx # Manage existing entries │ └── Stats.tsx # Basic statistics ├── Entry/ │ ├── CreateEntry.tsx # New docket entry form │ ├── EditEntry.tsx # Edit existing entry │ └── DeleteEntry.tsx # Delete confirmation ├── Document/ │ ├── DocumentUpload.tsx # Multi-file upload component │ ├── DocumentEdit.tsx # Edit document metadata │ └── DocumentReplace.tsx # Replace PDF file └── Layout/ ├── AdminLayout.tsx # Admin layout wrapper └── AdminNav.tsx # Admin navigation ``` ## User Interface Layouts ### Public Docket Page ``` ┌─────────────────────────────────────────────────────────────┐ │ ELIZA KRAGH v. MAD DOCKET │ │ [Subscribe] │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Case Information │ │ ───────────────── │ │ Case: Eliza Kragh v. Montana Association of the Deaf │ │ Status: Ongoing │ │ Last Updated: December 15, 2024 │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Docket Entries │ │ ───────────────── │ │ [Date] | [Document Type] | [Summary] | [View] │ │ ──────────────────────────────────────────────────────── │ │ 12/15/24 | Motion to Dismiss | Defendant's motion... |[+] │ │ └─ 📄 Main Document │ │ └─ 📄 Exhibit A - Financial Records │ │ └─ 📄 Exhibit B - Email Correspondence │ │ ──────────────────────────────────────────────────────── │ │ 12/10/24 | Complaint | Plaintiff's initial filing... |[+] │ │ └─ 📄 Main Document │ │ └─ 📄 Exhibit 1 - Contract Agreement │ │ ──────────────────────────────────────────────────────── │ │ [More entries...] │ └─────────────────────────────────────────────────────────────┘ ``` ### Admin Dashboard ``` ┌─────────────────────────────────────────────────────────────┐ │ ADMIN DASHBOARD [Logout] │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ [+ New Docket Entry] │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Manage Existing Entries │ │ ────────────────────── │ │ 12/15/24 | Motion to Dismiss | [Edit] [Delete] │ │ └─ 📄 Main Document [Edit] [Replace] [Del] │ │ └─ 📄 Exhibit A [Edit] [Replace] [Del] │ │ └─ 📄 Exhibit B [Edit] [Replace] [Del] │ │ └─ [+ Add Document to Entry] │ │ ──────────────────────────────────────────────────────── │ │ 12/10/24 | Complaint | [Edit] [Delete] │ │ └─ 📄 Main Document [Edit] [Replace] [Del] │ │ └─ 📄 Exhibit 1 [Edit] [Replace] [Del] │ │ └─ [+ Add Document to Entry] │ └─────────────────────────────────────────────────────────────┘ ``` ## Docker Configuration ### docker-compose.yml ```yaml version: '3.8' services: frontend: build: context: ./frontend dockerfile: Dockerfile ports: - "3000:3000" environment: - NEXT_PUBLIC_API_URL=http://backend:3001/api depends_on: - backend backend: build: context: ./backend dockerfile: Dockerfile ports: - "3001:3001" environment: - DATABASE_URL=postgresql://docket_user:docket_pass@postgres:5432/docket_db - REDIS_URL=redis://redis:6379 - JWT_SECRET=your-secret-key - UPLOAD_DIR=/app/uploads volumes: - uploads:/app/uploads depends_on: - postgres - redis postgres: image: postgres:15 environment: - POSTGRES_DB=docket_db - POSTGRES_USER=docket_user - POSTGRES_PASSWORD=docket_pass volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" redis: image: redis:7-alpine ports: - "6379:6379" nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/ssl:/etc/nginx/ssl depends_on: - frontend - backend volumes: postgres_data: uploads: ``` ## Security Implementation ### Authentication & Authorization - JWT tokens for admin authentication - Token expiration and refresh mechanism - Protected routes middleware - Role-based access control ### File Security - Files served through API endpoints only - No direct file system access - File type validation (PDF only) - File size limits (10MB max) - UUID-based naming prevents enumeration ### Input Validation - All API inputs validated with Joi/Zod - SQL injection prevention with Prisma ORM - XSS protection with input sanitization - CSRF protection for admin forms ### Rate Limiting - API endpoint rate limiting - File upload rate limiting - Login attempt limiting - Email subscription rate limiting ## Email Notification System ### Subscription Process 1. User enters email on public site 2. Email validated and stored in database 3. Confirmation email sent with unsubscribe token 4. User added to active subscribers list ### Notification Trigger 1. Admin uploads new docket entry 2. System checks for active subscribers 3. Email notification queued for each subscriber 4. Background job processes email queue 5. Emails sent with entry summary and link ### Email Template ``` Subject: New Filing in Eliza Kragh v. Montana Association of the Deaf Dear Subscriber, A new document has been filed in the case of Eliza Kragh v. Montana Association of the Deaf: Date: December 15, 2024 Document Type: Motion to Dismiss Summary: Defendant's motion to dismiss based on lack of jurisdiction... View the complete filing and all documents at: https://docket-site.com To unsubscribe from these notifications, click here: https://docket-site.com/unsubscribe/[token] Best regards, Court Docket Notification System ``` ## Performance Optimization ### Frontend Optimization - Next.js static generation for public pages - Image optimization for any graphics - Code splitting and lazy loading - PDF.js worker for document rendering - Caching strategies for API responses ### Backend Optimization - Database query optimization with indexes - Redis caching for frequently accessed data - File streaming for PDF downloads - Connection pooling for database - Compression middleware for API responses ### Infrastructure Optimization - Nginx reverse proxy with caching - Gzip compression for static assets - CDN integration for file serving - Database connection pooling - Redis session storage ## Deployment Strategy ### Development Environment - Docker Compose for local development - Hot reloading for both frontend and backend - Development database with sample data - Email testing with local SMTP server ### Production Environment - Docker Swarm or Kubernetes deployment - SSL/TLS certificates with Let's Encrypt - Production database with backups - Real SMTP service for email notifications - Monitoring and logging with ELK stack ### CI/CD Pipeline - GitHub Actions for automated testing - Docker image building and pushing - Automated deployment to staging - Manual approval for production deployment - Database migration automation ## Testing Strategy ### Unit Testing - Backend API endpoints with Jest - Frontend components with React Testing Library - Database operations with test database - File upload functionality testing ### Integration Testing - End-to-end user workflows with Cypress - API integration testing - Email notification testing - File serving and download testing ### Security Testing - Authentication and authorization testing - Input validation testing - File upload security testing - SQL injection prevention testing This comprehensive design specification serves as the complete technical reference for implementing the Eliza Kragh v. MAD court docket website.