# Seismo Fleet Manager v0.1.1 Backend API and web interface for managing seismograph fleet status. Track multiple seismographs calling in data from remote deployments, monitor their status, and manage your fleet through a unified database. ## Features - **Web Dashboard**: Modern, responsive UI with dark/light mode support - **Fleet Monitoring**: Track all seismograph units in one place - **Roster Management**: Full CRUD operations via API or CSV import *(New in v0.1.1)* - **Status Management**: Automatically mark units as OK, Pending (>12h), or Missing (>24h) - **Data Ingestion**: Accept reports from emitter scripts via REST API - **Photo Management**: Upload and view photos for each unit - **Interactive Maps**: Leaflet-based maps showing unit locations - **SQLite Storage**: Lightweight, file-based database for easy deployment ## Tech Stack - **FastAPI**: Modern, fast web framework - **SQLAlchemy**: SQL toolkit and ORM - **SQLite**: Lightweight database - **HTMX**: Dynamic updates without heavy JavaScript frameworks - **TailwindCSS**: Utility-first CSS framework - **Leaflet**: Interactive maps - **Jinja2**: Server-side templating - **uvicorn**: ASGI server - **Docker**: Containerization for easy deployment ## Quick Start with Docker Compose (Recommended) ### Prerequisites - Docker and Docker Compose installed ### Running the Application 1. **Start the service:** ```bash docker compose up -d ``` 2. **Check logs:** ```bash docker compose logs -f ``` 3. **Stop the service:** ```bash docker compose down ``` The application will be available at: - **Web Interface**: http://localhost:8001 - **API Documentation**: http://localhost:8001/docs - **Health Check**: http://localhost:8001/health ### Data Persistence The SQLite database and photos are stored in the `./data` directory, which is mounted as a volume. Your data will persist even if you restart or rebuild the container. ## Local Development (Without Docker) ### Prerequisites - Python 3.11+ - pip ### Setup 1. **Install dependencies:** ```bash pip install -r requirements.txt ``` 2. **Run the server:** ```bash uvicorn backend.main:app --host 0.0.0.0 --port 8001 --reload ``` The application will be available at http://localhost:8001 ## API Endpoints ### Web Pages - **GET** `/` - Dashboard home page - **GET** `/roster` - Fleet roster page - **GET** `/unit/{unit_id}` - Unit detail page ### Fleet Status & Monitoring - **GET** `/api/status-snapshot` - Complete fleet status snapshot - **GET** `/api/roster` - List of all units with metadata - **GET** `/api/unit/{unit_id}` - Detailed unit information - **GET** `/health` - Health check endpoint ### Roster Management *(New in v0.1.1)* - **POST** `/api/roster/add` - Add new unit to roster ```bash curl -X POST http://localhost:8001/api/roster/add \ -F "id=BE1234" \ -F "unit_type=series3" \ -F "deployed=true" \ -F "note=Main site sensor" ``` - **POST** `/api/roster/set-deployed/{unit_id}` - Toggle deployment status - **POST** `/api/roster/set-retired/{unit_id}` - Toggle retired status - **POST** `/api/roster/set-note/{unit_id}` - Update unit notes - **POST** `/api/roster/import-csv` - Bulk import from CSV ```bash curl -X POST http://localhost:8001/api/roster/import-csv \ -F "file=@roster.csv" \ -F "update_existing=true" ``` ### CSV Import Format Create a CSV file with the following columns (only `unit_id` is required): ```csv unit_id,unit_type,deployed,retired,note,project_id,location BE1234,series3,true,false,Primary sensor,PROJ-001,San Francisco CA BE5678,series3,true,false,Backup sensor,PROJ-001,Los Angeles CA ``` See [sample_roster.csv](sample_roster.csv) for a working example. ### Emitter Reporting - **POST** `/emitters/report` - Submit status report from a seismograph unit - **POST** `/api/series3/heartbeat` - Series3 multi-unit telemetry payload - **GET** `/fleet/status` - Retrieve status of all seismograph units (legacy) ### Photo Management - **GET** `/api/unit/{unit_id}/photos` - List photos for a unit - **GET** `/api/unit/{unit_id}/photo/{filename}` - Serve specific photo file ## API Documentation Once running, interactive API documentation is available at: - **Swagger UI**: http://localhost:8001/docs - **ReDoc**: http://localhost:8001/redoc ## Testing the API ### Using curl **Submit a report:** ```bash curl -X POST http://localhost:8001/emitters/report \ -H "Content-Type: application/json" \ -d '{ "unit": "SEISMO-001", "unit_type": "series3", "timestamp": "2025-11-20T10:30:00", "file": "event_20251120_103000.dat", "status": "OK" }' ``` **Get fleet status:** ```bash curl http://localhost:8001/api/roster ``` **Import roster from CSV:** ```bash curl -X POST http://localhost:8001/api/roster/import-csv \ -F "file=@sample_roster.csv" \ -F "update_existing=true" ``` ### Using Python ```python import requests from datetime import datetime # Submit report response = requests.post( "http://localhost:8001/emitters/report", json={ "unit": "SEISMO-001", "unit_type": "series3", "timestamp": datetime.utcnow().isoformat(), "file": "event_20251120_103000.dat", "status": "OK" } ) print(response.json()) # Get fleet status response = requests.get("http://localhost:8001/api/roster") print(response.json()) # Import CSV with open('roster.csv', 'rb') as f: files = {'file': f} data = {'update_existing': 'true'} response = requests.post( "http://localhost:8001/api/roster/import-csv", files=files, data=data ) print(response.json()) ``` ## Data Model ### RosterUnit Table (Your Fleet Roster) | Field | Type | Description | |-------|------|-------------| | id | string | Unit identifier (primary key) | | unit_type | string | Type of seismograph (default: "series3") | | deployed | boolean | Whether unit is deployed in field | | retired | boolean | Whether unit is retired from service | | note | string | Notes about the unit | | project_id | string | Associated project identifier | | location | string | Deployment location description | | last_updated | datetime | Last modification timestamp | ### Emitter Table (Device Check-ins) | Field | Type | Description | |-------|------|-------------| | id | string | Unit identifier (primary key) | | unit_type | string | Type of seismograph (e.g., "series3") | | last_seen | datetime | Last report timestamp | | last_file | string | Last file processed | | status | string | Current status: OK, Pending, Missing | | notes | string | Optional notes (nullable) | ## Project Structure ``` seismo-fleet-manager/ ├── backend/ │ ├── main.py # FastAPI app entry point │ ├── database.py # SQLAlchemy database configuration │ ├── models.py # Database models (RosterUnit, Emitter) │ ├── routes.py # Legacy API endpoints │ ├── routers/ # Modular API routers │ │ ├── roster.py # Fleet status endpoints │ │ ├── roster_edit.py # Roster management & CSV import │ │ ├── units.py # Unit detail endpoints │ │ ├── photos.py # Photo management │ │ ├── dashboard.py # Dashboard partials │ │ └── dashboard_tabs.py # Dashboard tab endpoints │ ├── services/ │ │ └── snapshot.py # Fleet status snapshot logic │ └── static/ # Static assets (CSS, etc.) ├── templates/ # Jinja2 HTML templates │ ├── base.html # Base layout with sidebar │ ├── dashboard.html # Main dashboard │ ├── roster.html # Fleet roster table │ ├── unit_detail.html # Unit detail page │ └── partials/ # HTMX partial templates ├── data/ # SQLite database & photos (persisted) ├── requirements.txt # Python dependencies ├── Dockerfile # Docker container definition ├── docker-compose.yml # Docker Compose configuration ├── CHANGELOG.md # Version history ├── FRONTEND_README.md # Frontend documentation └── README.md # This file ``` ## Docker Commands **Build the image:** ```bash docker compose build ``` **Start in foreground:** ```bash docker compose up ``` **Start in background:** ```bash docker compose up -d ``` **View logs:** ```bash docker compose logs -f seismo-backend ``` **Restart service:** ```bash docker compose restart ``` **Rebuild and restart:** ```bash docker compose up -d --build ``` **Stop and remove containers:** ```bash docker compose down ``` **Remove containers and volumes:** ```bash docker compose down -v ``` ## What's New in v0.1.1 - **Roster Editing API**: Full CRUD operations for managing your fleet roster - **CSV Import**: Bulk upload roster data from CSV files - **Enhanced Data Model**: Added project_id and location fields to roster - **Bug Fixes**: Improved database session management and error handling - **Dashboard Improvements**: Separate views for Active, Benched, and Retired units See [CHANGELOG.md](CHANGELOG.md) for complete version history. ## Future Enhancements - Email/SMS alerts for missing units - Historical data tracking and reporting - Multi-user authentication - PostgreSQL support for larger deployments - Advanced filtering and search - Export roster to various formats - Automated backup and restore ## License MIT ## Version **Current: 0.1.1** - Roster Management & CSV Import (2025-12-02) Previous: 0.1.0 - Initial Release (2024-11-20)