A React + TypeScript web application for visualizing and monitoring operational data from Direct Air Capture (DAC) units.
The dashboard is designed to translate complex, time-series sensor data into clear, actionable insights for operators and stakeholders.
This project focuses on usability, system observability, and end-to-end ownership of a data-driven product.
- Real-Time Sensor Visualization
- Time-series charts for CO₂ concentration, temperature, airflow, and capture efficiency
- Configurable time ranges and sensor selection
- System Health Overview
- High-level status indicators for DAC units
- Threshold-based alerts for anomalous or degraded performance
- Click-to-navigate from dashboard to detailed views
- Operational Workflows
- Ability to trigger test runs and view results (simulated with mock data generation)
- Background task execution for long-running tests
- Click-to-navigate from test results to sensor data views
- Responsive UI
- Designed for use across desktop and tablet devices
- Intuitive navigation with state persistence via URL parameters
- Production-Oriented Architecture
- Strong typing with TypeScript
- Clean separation between UI, data fetching, and domain logic
- Structured logging and error handling
- Input validation and security best practices
Main dashboard showing system status, unit health, and alerts
Time-series charts displaying CO₂ concentration, temperature, airflow, and capture efficiency
Test run execution interface with results and status tracking
Frontend
- React 18.2.0
- TypeScript 5.2.2
- Vite 5.0.8
- Recharts 2.10.3 (data visualization)
- React Router DOM 6.20.0
- Styled-jsx (scoped CSS)
Backend
- FastAPI 0.104.1 (Python REST API)
- PostgreSQL 15 (Alpine)
- SQLAlchemy 2.0.23 (ORM)
- Alembic 1.12.1 (database migrations)
- Pydantic 2.5.0 (data validation)
- Structured JSON logging
Tooling & Deployment
- Docker & Docker Compose
- Automated startup script (
start.sh) - Security vulnerability scanning (npm audit, pip-audit/safety)
- Database seeding scripts
Before setting up this repository, ensure you have the following installed:
- Node.js (v18 or higher) - Download
- Docker Desktop - Download
- Git - Usually pre-installed on macOS/Linux
-
Clone the repository:
git clone <repository-url> cd dac-ops-dash
-
Install frontend dependencies:
cd frontend npm install cd ..
-
Set up environment variables:
Create a
.envfile in the project root with the following required variables:# PostgreSQL Configuration (REQUIRED - no defaults allowed) POSTGRES_USER=your_username POSTGRES_PASSWORD=your_secure_password_min_8_chars POSTGRES_DB=dac_ops_db # Database Connection URL (REQUIRED - must match credentials above) DATABASE_URL=postgresql://your_username:your_secure_password_min_8_chars@postgres:5432/dac_ops_db # Backend Database Settings (REQUIRED - must match POSTGRES_* values) DATABASE_HOST=postgres DATABASE_PORT=5432 DATABASE_NAME=dac_ops_db DATABASE_USER=your_username DATABASE_PASSWORD=your_secure_password_min_8_chars # CORS Configuration CORS_ORIGINS=http://localhost:3000,http://localhost:5173 # Frontend API URL VITE_API_BASE_URL=http://localhost:8000/api # Backend Development Mode (set to empty string "" for production) UVICORN_RELOAD=--reload
Important Security Notes:
- Passwords must be at least 8 characters long
- Default credentials (
dac_user/dac_password) are not allowed - All database-related variables are required (no fallback defaults)
-
Start all services with Docker:
Option A: Use the automated startup script (recommended):
./start.sh
This script will:
- Verify
.envfile exists - Start all Docker containers
- Wait for services to be healthy
- Automatically seed the database if it's empty
Option B: Manual startup:
# Start containers docker-compose up -d # Check service status docker-compose ps # View logs docker-compose logs -f # Seed database (if needed) docker-compose exec backend python seed_data.py
- Verify
-
Access the application:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- API Documentation: http://localhost:8000/docs
If you prefer to run services locally without Docker, follow these steps:
- PostgreSQL 15 - Install via:
- macOS:
brew install postgresql@15 - Linux:
sudo apt-get install postgresql-15(Ubuntu/Debian) - Windows: Download PostgreSQL installer
- macOS:
- Python 3.11+ - Download Python
- Node.js 18+ - Already required above
# Start PostgreSQL service
# macOS:
brew services start postgresql@15
# Linux:
sudo systemctl start postgresql
# Windows: PostgreSQL service should start automatically after installation
# Create the database
createdb dac_ops_db
# Or using psql:
psql -U postgres -c "CREATE DATABASE dac_ops_db;"# Navigate to backend directory
cd backend
# Create Python virtual environment
python -m venv venv
# Activate virtual environment
# macOS/Linux:
source venv/bin/activate
# Windows:
# venv\Scripts\activate
# Install Python dependencies
pip install -r requirements.txt# In the backend directory, create .env file
cd backend
cp .env.example .env # If .env.example exists, or create manuallyEdit backend/.env with your local database credentials:
# All fields are REQUIRED (no defaults)
DATABASE_URL=postgresql://postgres:your_secure_password@localhost:5432/dac_ops_db
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=dac_ops_db
DATABASE_USER=postgres
DATABASE_PASSWORD=your_secure_password # Must be at least 8 characters
CORS_ORIGINS=http://localhost:5173,http://localhost:3000Note: The password must be at least 8 characters and cannot be the default dac_password.
# Make sure you're in the backend directory with venv activated
cd backend
source venv/bin/activate # If not already activated
# Run migrations
alembic upgrade head# Still in backend directory with venv activated
python seed_data.py# In backend directory with venv activated
uvicorn main:app --reload --port 8000The backend API will be available at:
- API: http://localhost:8000
- API Documentation: http://localhost:8000/docs
# Return to project root
cd ..
# Create .env file in project root (if not already created)
# Edit .env and set:
# VITE_API_BASE_URL=http://localhost:8000/api# In frontend directory
cd frontend
npm run devThe frontend will be available at http://localhost:5173 (or the port Vite assigns).
You'll need three terminal windows:
-
Terminal 1 - PostgreSQL (if not running as a service):
# macOS brew services start postgresql@15 -
Terminal 2 - Backend:
cd backend source venv/bin/activate uvicorn main:app --reload --port 8000
-
Terminal 3 - Frontend:
cd frontend npm run dev
- Database connection errors:
- Ensure PostgreSQL is running and credentials in
.envare correct - Verify password meets requirements (min 8 chars, not default)
- Check that
DATABASE_URLmatches your credentials
- Ensure PostgreSQL is running and credentials in
- Port already in use: Change ports in
uvicorncommand or frontendvite.config.ts - Module not found errors: Ensure virtual environment is activated and dependencies are installed
- Migration errors: Try
alembic downgrade -1thenalembic upgrade headto reset migrations - Validation errors on startup: Check that all required environment variables are set and passwords meet security requirements
This project implements several security best practices:
- All string fields have length limits to prevent DoS attacks
- XSS protection on user-input fields (summary, names, etc.)
- Pydantic schema validation on all API endpoints
- No hardcoded credentials - All database credentials must be provided via environment variables
- Password strength validation (minimum 8 characters, no default passwords)
- Environment variable validation on startup
- Frontend: Run
npm run security:auditto check for vulnerable dependencies - Backend: Run
python backend/check_security.pyto scan Python dependencies (requirespip-auditorsafety)
A comprehensive security audit report is available at .cursor/SECURITY_FIX.md documenting identified vulnerabilities and remediation strategies.
The application is structured around a clear separation of concerns:
- UI Components: Presentational components focused on usability and clarity
- Domain Components: DAC-specific concepts such as units, sensors, and test runs
- Data Layer: Typed API clients and data-fetching hooks
- State Management: Local component state and React context for shared filters
This approach keeps the UI intuitive while ensuring the system remains extensible as data volume and complexity grow.
type SensorReading = {
id: string;
unitId: string;
sensorType: 'co2' | 'temperature' | 'airflow' | 'efficiency';
value: number;
unit: string;
timestamp: string;
createdAt: string;
};
type DacUnit = {
id: string;
name: string;
status: 'healthy' | 'warning' | 'critical';
location: string | null;
lastUpdated: string | null;
createdAt: string;
updatedAt: string;
};
type TestRun = {
id: string;
unitId: string;
status: 'pending' | 'running' | 'completed' | 'failed';
startedAt: string;
completedAt: string | null;
error: string | null;
result: TestResult | null;
};
type TestResult = {
id: string;
testRunId: string;
passed: boolean;
summary: string;
metrics: TestMetric[];
createdAt: string;
};npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm run lint- Run ESLintnpm run security:audit- Check for vulnerable npm dependenciesnpm run security:fix- Auto-fix npm vulnerabilitiesnpm run docker:up- Start Docker containersnpm run docker:down- Stop Docker containersnpm run docker:logs- View container logsnpm run docker:build- Rebuild Docker images
python backend/check_security.py- Scan Python dependencies for vulnerabilitiesdocker-compose exec backend python seed_data.py- Seed database with sample datadocker-compose exec backend alembic upgrade head- Run database migrations
dac-ops-dash/
├── frontend/ # React frontend application
│ ├── src/
│ │ ├── app/ # React app configuration
│ │ │ ├── App.tsx # Main React component with router setup
│ │ │ ├── routes.tsx # Route definitions
│ │ │ └── Layout.tsx # Layout wrapper component
│ │ ├── components/ # Reusable UI components
│ │ │ ├── common/ # Shared UI primitives
│ │ │ │ ├── Card.tsx
│ │ │ │ ├── LoadingState.tsx
│ │ │ │ ├── ErrorState.tsx
│ │ │ │ └── Tooltip.tsx
│ │ │ ├── overview/ # Dashboard components
│ │ │ │ ├── SystemStatusCard.tsx
│ │ │ │ ├── UnitStatusGrid.tsx
│ │ │ │ └── AlertBanner.tsx
│ │ │ ├── sensors/ # Sensor visualization components
│ │ │ │ ├── SensorChart.tsx
│ │ │ │ ├── SensorSelector.tsx
│ │ │ │ ├── SensorLegend.tsx
│ │ │ │ └── TimeRangePicker.tsx
│ │ │ └── workflows/ # Test workflow components
│ │ │ ├── TestRunButton.tsx
│ │ │ ├── TestRunStatus.tsx
│ │ │ └── TestResultsPanel.tsx
│ │ ├── pages/ # Page components
│ │ │ ├── DashboardPage.tsx
│ │ │ ├── SensorsPage.tsx
│ │ │ └── TestsPage.tsx
│ │ ├── hooks/ # Custom React hooks
│ │ │ ├── useSensorData.ts
│ │ │ ├── useDacUnits.ts
│ │ │ └── useTestRuns.ts
│ │ ├── api/ # API client functions
│ │ │ ├── client.ts # Base API client
│ │ │ ├── sensors.ts
│ │ │ ├── units.ts
│ │ │ └── tests.ts
│ │ ├── context/ # React Context providers
│ │ │ └── FilterContext.tsx
│ │ ├── types/ # TypeScript type definitions
│ │ │ └── domain.ts
│ │ ├── utils/ # Utility functions
│ │ │ ├── thresholds.ts
│ │ │ ├── formatters.ts
│ │ │ └── mockData.ts
│ │ ├── main.tsx # React entry point
│ │ └── index.css # Global styles
│ ├── public/ # Static assets
│ │ └── (empty - static assets if needed)
│ ├── package.json # Frontend dependencies & scripts
│ ├── vite.config.ts # Vite configuration
│ ├── tsconfig.json # TypeScript configuration
│ ├── index.html # HTML entry point
│ └── Dockerfile # Frontend container definition
│
├── backend/ # FastAPI backend
│ ├── app/
│ │ ├── database.py # Database connection & settings
│ │ ├── models.py # SQLAlchemy ORM models
│ │ ├── schemas.py # Pydantic request/response schemas
│ │ ├── logging_config.py # Structured logging configuration
│ │ ├── routers/ # API route handlers
│ │ │ ├── units.py # DAC unit endpoints
│ │ │ ├── sensors.py # Sensor reading endpoints
│ │ │ └── tests.py # Test run endpoints
│ │ ├── services/ # Business logic
│ │ │ └── test_executor.py # Test execution service
│ │ └── utils/ # Utility functions
│ │ ├── database.py # Transaction management
│ │ └── transformers.py # Model-to-schema transformers
│ ├── alembic/ # Database migrations
│ ├── main.py # FastAPI application entry point
│ ├── seed_data.py # Database seeding script
│ ├── check_security.py # Security vulnerability scanner
│ ├── requirements.txt # Python dependencies
│ └── Dockerfile # Backend container definition
│
├── docker-compose.yml # Multi-container orchestration
├── start.sh # Automated startup script
├── README.md # Project documentation
└── .env # Environment variables (not in repo)