From 05c63367c8f4e60f250b3357b246c2292b581905 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Nov 2025 18:46:46 +0000 Subject: [PATCH] Containerize backend with Docker Compose Added Docker support for easy deployment: - Dockerfile: Python 3.11 slim image with FastAPI app - docker-compose.yml: Service definition with volume mounting for data persistence - .dockerignore: Exclude unnecessary files from Docker build - database.py: Updated to store SQLite DB in ./data directory for volume persistence - .gitignore: Added entries for database files and data directory - README.md: Comprehensive documentation with Docker and local setup instructions The application can now be run with: docker compose up -d Database persists in ./data directory mounted as a volume --- .dockerignore | 19 ++++ .gitignore | 6 ++ Dockerfile | 19 ++++ README.md | 251 ++++++++++++++++++++++++++++++++++++++++++++- database.py | 6 +- docker-compose.yml | 23 +++++ 6 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e809327 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +*.so +*.egg +*.egg-info +dist +build +.git +.gitignore +*.db +*.db-journal +.env +.venv +venv/ +ENV/ +data/ diff --git a/.gitignore b/.gitignore index b7faf40..b697ede 100644 --- a/.gitignore +++ b/.gitignore @@ -205,3 +205,9 @@ cython_debug/ marimo/_static/ marimo/_lsp/ __marimo__/ + +# Seismo Fleet Manager +# SQLite database files +*.db +*.db-journal +data/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3533224 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM python:3.11-slim + +# Set working directory +WORKDIR /app + +# Copy requirements first for better caching +COPY requirements.txt . + +# Install dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application code +COPY . . + +# Expose port +EXPOSE 8000 + +# Run the application +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/README.md b/README.md index 661646a..ee96d16 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,249 @@ -# seismo-fleet-manager -Web app and backend for tracking deployed units. +# Seismo Fleet Manager - Backend v0.1 + +Backend API 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 + +- **Fleet Monitoring**: Track all seismograph units in one place +- **Status Management**: Automatically mark units as OK, Pending (>12h), or Missing (>24h) +- **Data Ingestion**: Accept reports from emitter scripts via REST API +- **SQLite Storage**: Lightweight, file-based database for easy deployment + +## Tech Stack + +- **FastAPI**: Modern, fast web framework +- **SQLAlchemy**: SQL toolkit and ORM +- **SQLite**: Lightweight database +- **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 API will be available at `http://localhost:8000` + +### Data Persistence + +The SQLite database is 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 + python main.py + ``` + + Or with auto-reload: + ```bash + uvicorn main:app --reload + ``` + +The API will be available at `http://localhost:8000` + +## API Endpoints + +### Root +- **GET** `/` - Health check + +### Emitter Report +- **POST** `/emitters/report` +- Submit status report from a seismograph unit +- **Request Body:** + ```json + { + "unit": "SEISMO-001", + "unit_type": "series3", + "timestamp": "2025-11-20T10:30:00", + "file": "event_20251120_103000.dat", + "status": "OK" + } + ``` +- **Response:** + ```json + { + "message": "Emitter report received", + "unit": "SEISMO-001", + "status": "OK" + } + ``` + +### Fleet Status +- **GET** `/fleet/status` +- Retrieve status of all seismograph units +- **Response:** + ```json + [ + { + "id": "SEISMO-001", + "unit_type": "series3", + "last_seen": "2025-11-20T10:30:00", + "last_file": "event_20251120_103000.dat", + "status": "OK", + "notes": null + } + ] + ``` + +## API Documentation + +Once running, interactive API documentation is available at: +- **Swagger UI**: http://localhost:8000/docs +- **ReDoc**: http://localhost:8000/redoc + +## Testing the API + +### Using curl + +**Submit a report:** +```bash +curl -X POST http://localhost:8000/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:8000/fleet/status +``` + +### Using Python + +```python +import requests +from datetime import datetime + +# Submit report +response = requests.post( + "http://localhost:8000/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:8000/fleet/status") +print(response.json()) +``` + +## Data Model + +### Emitters Table + +| 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/ +├── main.py # FastAPI app entry point +├── database.py # SQLAlchemy database configuration +├── models.py # Database models +├── routes.py # API endpoints +├── requirements.txt # Python dependencies +├── Dockerfile # Docker container definition +├── docker-compose.yml # Docker Compose configuration +├── .dockerignore # Docker ignore rules +└── data/ # SQLite database directory (created at runtime) +``` + +## 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 +``` + +**Stop and remove containers:** +```bash +docker compose down +``` + +**Remove containers and volumes:** +```bash +docker compose down -v +``` + +## Future Enhancements + +- Automated status updates based on last_seen timestamps +- Web-based dashboard for fleet monitoring +- Email/SMS alerts for missing units +- Historical data tracking and reporting +- Multi-user authentication +- PostgreSQL support for larger deployments + +## License + +MIT + +## Version + +0.1.0 - Initial Release diff --git a/database.py b/database.py index bb191d9..49ad5d9 100644 --- a/database.py +++ b/database.py @@ -1,8 +1,12 @@ from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker +import os -SQLALCHEMY_DATABASE_URL = "sqlite:///./seismo_fleet.db" +# Ensure data directory exists +os.makedirs("data", exist_ok=True) + +SQLALCHEMY_DATABASE_URL = "sqlite:///./data/seismo_fleet.db" engine = create_engine( SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0b84fce --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3.8' + +services: + seismo-backend: + build: . + container_name: seismo-fleet-manager + ports: + - "8000:8000" + volumes: + # Persist SQLite database + - ./data:/app/data + environment: + - PYTHONUNBUFFERED=1 + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +volumes: + data: