510 lines
19 KiB
Markdown
510 lines
19 KiB
Markdown
# 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.
|