diff --git a/backend/migrate_add_project_data_collection_mode.py b/backend/migrate_add_project_data_collection_mode.py new file mode 100644 index 0000000..dbac4d6 --- /dev/null +++ b/backend/migrate_add_project_data_collection_mode.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +""" +Migration: Add data_collection_mode column to projects table. + +Values: + "remote" — units have modems; data pulled via FTP/scheduler automatically + "manual" — no modem; SD cards retrieved daily and uploaded by hand + +All existing projects are backfilled to "manual" (safe conservative default). + +Run once inside the Docker container: + docker exec terra-view python3 backend/migrate_add_project_data_collection_mode.py +""" +from pathlib import Path + +DB_PATH = Path("data/seismo_fleet.db") + + +def migrate(): + import sqlite3 + + if not DB_PATH.exists(): + print(f"Database not found at {DB_PATH}. Are you running from /home/serversdown/terra-view?") + return + + conn = sqlite3.connect(DB_PATH) + conn.row_factory = sqlite3.Row + cur = conn.cursor() + + # ── 1. Add column (idempotent) ─────────────────────────────────────────── + cur.execute("PRAGMA table_info(projects)") + existing_cols = {row["name"] for row in cur.fetchall()} + + if "data_collection_mode" not in existing_cols: + cur.execute("ALTER TABLE projects ADD COLUMN data_collection_mode TEXT DEFAULT 'manual'") + conn.commit() + print("✓ Added column data_collection_mode to projects") + else: + print("○ Column data_collection_mode already exists — skipping ALTER TABLE") + + # ── 2. Backfill NULLs to 'manual' ──────────────────────────────────────── + cur.execute("UPDATE projects SET data_collection_mode = 'manual' WHERE data_collection_mode IS NULL") + updated = cur.rowcount + conn.commit() + conn.close() + + if updated: + print(f"✓ Backfilled {updated} project(s) to data_collection_mode='manual'.") + print("Migration complete.") + + +if __name__ == "__main__": + migrate() diff --git a/backend/models.py b/backend/models.py index 2150d25..24738c4 100644 --- a/backend/models.py +++ b/backend/models.py @@ -157,6 +157,11 @@ class Project(Base): project_type_id = Column(String, nullable=False) # FK to ProjectType.id status = Column(String, default="active") # active, on_hold, completed, archived, deleted + # Data collection mode: how field data reaches Terra-View. + # "remote" — units have modems; data pulled via FTP/scheduler automatically + # "manual" — no modem; SD cards retrieved daily and uploaded by hand + data_collection_mode = Column(String, default="manual") # remote | manual + # Project metadata client_name = Column(String, nullable=True, index=True) # Client name (e.g., "PJ Dick") site_address = Column(String, nullable=True) diff --git a/backend/routers/projects.py b/backend/routers/projects.py index 3f63f98..9de68d8 100644 --- a/backend/routers/projects.py +++ b/backend/routers/projects.py @@ -613,6 +613,7 @@ async def get_project(project_id: str, db: Session = Depends(get_db)): "site_coordinates": project.site_coordinates, "start_date": project.start_date.isoformat() if project.start_date else None, "end_date": project.end_date.isoformat() if project.end_date else None, + "data_collection_mode": project.data_collection_mode or "manual", "created_at": project.created_at.isoformat(), "updated_at": project.updated_at.isoformat(), } @@ -659,6 +660,8 @@ async def update_project( project.start_date = datetime.fromisoformat(data["start_date"]) if data["start_date"] else None if "end_date" in data: project.end_date = datetime.fromisoformat(data["end_date"]) if data["end_date"] else None + if "data_collection_mode" in data and data["data_collection_mode"] in ("remote", "manual"): + project.data_collection_mode = data["data_collection_mode"] project.updated_at = datetime.utcnow() diff --git a/templates/partials/project_create_modal.html b/templates/partials/project_create_modal.html index 3758542..bd34fad 100644 --- a/templates/partials/project_create_modal.html +++ b/templates/partials/project_create_modal.html @@ -75,6 +75,32 @@ Include this modal in pages that use the project picker. +