Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Git / version control
.git
.gitignore

# Python
.venv
venv
__pycache__
*.pyc
*.pyo
*.egg-info
.pytest_cache
.mypy_cache
.coverage
htmlcov

# Node
frontend/node_modules
frontend/dist
frontend/.env
npm-debug.log*

# Local data and outputs (mounted at runtime)
data
outputs
logs
models_pretrained

# Secrets
secrets
.env
.env.*

# IDE / OS
.claude
.cursor
.vscode
.DS_Store

# Docs / tests that are not needed at runtime
team_docs
*.pdf
tests
notebooks
scripts/*.sh
scripts/setup_gee.py

# Large pretrained weights if they exist locally
# (The production ONNX is copied explicitly in the Dockerfile if present)
models/**/*.pth
models/**/*.pt
models/**/best_model.pth
54 changes: 44 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,19 +1,53 @@
# ClimateVision Environment Variables
# Copy this file to .env and fill in your actual credentials
# NEVER commit .env to git!
# Copy this file to .env and fill in your actual credentials.
# NEVER commit .env or secrets/ to git!

# Google Earth Engine
# ---------------------------------------------------------------------------
# Google Earth Engine (required for real satellite imagery)
# ---------------------------------------------------------------------------
# Service account email registered with Earth Engine.
GEE_SERVICE_ACCOUNT=your-service-account@your-project.iam.gserviceaccount.com
GEE_PRIVATE_KEY_FILE=path/to/your-private-key.json
# OR if using OAuth:

# Path to the service-account JSON key, relative to the project root.
# Keep the file in secrets/ (gitignored).
GEE_SERVICE_ACCOUNT_KEY=secrets/gee-key.json

# Google Cloud / Earth Engine project ID.
GEE_PROJECT_ID=your-gee-project-id

# Sentinel Hub (optional - for later)
# ---------------------------------------------------------------------------
# Sentinel Hub (optional future source)
# ---------------------------------------------------------------------------
SENTINEL_HUB_CLIENT_ID=your_client_id_here
SENTINEL_HUB_CLIENT_SECRET=your_client_secret_here

# API Keys (optional - for later)
API_SECRET_KEY=your_secret_key_here
# ---------------------------------------------------------------------------
# API Security
# ---------------------------------------------------------------------------
# Secret used for API-key hashing and any signed tokens.
# Generate with: openssl rand -hex 32
API_SECRET_KEY=change_me_in_production

# Set to 1 ONLY in local development to enable the cv_dev bypass key.
# NEVER enable this in production.
CLIMATEVISION_ALLOW_DEV_KEY=0

# ---------------------------------------------------------------------------
# CORS / Frontend
# ---------------------------------------------------------------------------
# Comma-separated list of origins allowed to call the API.
# Include your production domain and any local dev URLs.
CLIMATEVISION_CORS_ORIGINS=https://climatevision.green,https://www.climatevision.green,http://localhost:5173,http://127.0.0.1:5173

# ---------------------------------------------------------------------------
# LLM Reporting (optional)
# ---------------------------------------------------------------------------
ANTHROPIC_API_KEY=your_anthropic_api_key
CLIMATEVISION_LLM_MODEL=claude-haiku-4-5-20251001

# Database (optional - for later)
DATABASE_URL=postgresql://user:password@localhost:5432/climatevision
# ---------------------------------------------------------------------------
# Database
# ---------------------------------------------------------------------------
# SQLite is used by default. Use an absolute path or a project-relative path.
# For production with high traffic, switch to PostgreSQL and update db.py.
DATABASE_URL=sqlite:///outputs/climatevision.sqlite3
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,28 @@ jobs:

- name: Type check and build
run: npm run build

docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
push: false
target: api
cache-from: type=gha
cache-to: type=gha,mode=max

# Aggregator job used as a required status check named "ci"
ci:
needs: [python, frontend, docker]
runs-on: ubuntu-latest
steps:
- name: All checks passed
run: echo "CI passed"
23 changes: 23 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Deploy

on:
push:
branches: [main]

jobs:
test:
uses: ./.github/workflows/ci.yml

deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Flyctl
uses: superfly/flyctl-actions/setup-flyctl@master

- name: Deploy to Fly.io
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
run: fly deploy --remote-only
64 changes: 64 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Multi-stage Dockerfile for ClimateVision
# Builds the React frontend, then packages the FastAPI backend + static files.

# -----------------------------------------------------------------------------
# Stage 1: Build the frontend
# -----------------------------------------------------------------------------
FROM node:20-slim AS frontend-builder

WORKDIR /app/frontend

COPY frontend/package*.json ./
RUN npm ci

COPY frontend/ ./
ENV VITE_API_BASE_URL=
RUN npm run build

# -----------------------------------------------------------------------------
# Stage 2: Python API runtime
# -----------------------------------------------------------------------------
FROM python:3.11-slim AS api

WORKDIR /app

# Prevent Python from writing pyc files and buffering stdout
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV OMP_NUM_THREADS=1

# Install system dependencies required by rasterio, opencv, and other geospatial libs.
# build-essential and python3-dev are needed to compile packages like stringzilla
# that do not provide pre-built wheels for this platform.
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1 \
libgdal-dev \
build-essential \
python3-dev \
&& rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# Install the ClimateVision package
COPY setup.py README.md ./
COPY src/ ./src/
RUN pip install --no-cache-dir -e .

# Copy built frontend from the first stage
COPY --from=frontend-builder /app/frontend/dist ./frontend/dist

# Copy config and model directory structure
COPY config.yaml ./
COPY config/ ./config/
COPY models/ ./models/

# Create writable directories for SQLite and outputs
RUN mkdir -p /app/outputs /app/data /app/logs

EXPOSE 8000

# Note: GEE credentials and other secrets are supplied at runtime via env vars.
# Do not bake credentials into the image.
CMD ["uvicorn", "climatevision.api.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
25 changes: 25 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
services:
api:
build:
context: .
dockerfile: Dockerfile
target: api
image: climatevision:latest
container_name: climatevision-api
ports:
- "8000:8000"
env_file:
- .env
volumes:
# Persistent SQLite / outputs
- ./outputs:/app/outputs
# GEE service-account key (read-only)
- ./secrets:/app/secrets:ro
environment:
- DATABASE_URL=sqlite:///app/outputs/climatevision.sqlite3
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
Loading
Loading