Go to file
fchinembiri 8b56609d64 fix(nextgen): disable infisical-standalone internal ingress controller to resolve port conflicts 2026-06-04 13:20:40 +02:00
.gitea/workflows ci: fix deploy job git push authentication 2026-05-08 20:16:26 +02:00
apps fix: resolve minio URL double-prefix, fix docstrings, implement spatial mode filtering 2026-05-09 00:05:58 +02:00
k8s fix(nextgen): disable infisical-standalone internal ingress controller to resolve port conflicts 2026-06-04 13:20:40 +02:00
ops Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
plan feat: implement Phase 5 Technical Portfolio and deep-dive documentation 2026-04-28 13:16:26 +02:00
terraform feat: update terraform with full cluster inventory and Portainer 2026-05-04 19:59:33 +02:00
training Add professional training template with MLflow, MinIO, and Inference generation 2026-04-23 22:57:46 +02:00
.geminiignore Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
.gitignore Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
AGENTS.md docs: enforce strict engineering policy [skip ci] 2026-05-08 20:44:38 +02:00
CLAUDE.md docs: enforce strict engineering policy [skip ci] 2026-05-08 20:44:38 +02:00
GEMINI.md docs: enforce strict engineering policy [skip ci] 2026-05-08 20:44:38 +02:00
I10A3339~2.jpg Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
MCP_TEST.txt chore: add MCP_TEST.txt verification file 2026-05-04 16:36:46 +02:00
PXL_20231209_104246132.PORTRAIT.jpg Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
README.md Enhance README with Mermaid diagrams for architecture, DFD, and GitOps pipeline 2026-04-23 22:31:22 +02:00
mc_mirror_dw.log Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
studiofranknkaycee-72.jpg Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
studiofranknkaycee-75.jpg Initial commit: Restructuring GeoCrop to Sovereign MLOps Platform 2026-04-23 22:02:12 +02:00
test_async_inference.py test: update test script port to 8088 for live cluster test 2026-05-09 00:07:54 +02:00
trigger_ci.txt trigger ci from agent 2026-04-28 13:10:38 +00:00
trigger_ci_2.txt chore: trigger ci retry 2 2026-05-09 00:16:13 +02:00

README.md

Sovereign MLOps Platform: GeoCrop LULC Portfolio

Welcome to the Sovereign MLOps Platform, a comprehensive self-hosted environment on K3s designed for end-to-end Land Use / Land Cover (LULC) crop-mapping in Zimbabwe.

This project showcases professional skills in MLOps, Cloud-Native Architecture, Geospatial Analysis, and GitOps.

🏗️ System Architecture

The platform is built on a robust, self-hosted Kubernetes (K3s) cluster with a focus on data sovereignty and scalability.

graph TD
    subgraph "Frontend & Entry"
        WEB[React 19 Frontend]
        ING[Nginx Ingress]
    end

    subgraph "Core Services (geocrop namespace)"
        API[FastAPI Backend]
        RQ[Redis Queue]
        WORKER[ML Inference Worker]
        TILER[TiTiler Dynamic Server]
    end

    subgraph "MLOps & Infra"
        GITEA[Gitea Source Control]
        ARGO[ArgoCD GitOps]
        MLF[MLflow Tracking]
        JUPYTER[JupyterLab Workspace]
    end

    subgraph "Storage & Data"
        MINIO[(MinIO S3 Storage)]
        POSTGIS[(Postgres + PostGIS)]
    end

    %% Flow
    WEB --> ING
    ING --> API
    API --> RQ
    RQ --> WORKER
    WORKER --> MINIO
    WORKER --> POSTGIS
    TILER --> MINIO
    WEB --> TILER
    ARGO --> GITEA
    ARGO --> ING
    JUPYTER --> MINIO
    MLF --> POSTGIS

📊 System Data Flow (DFD)

How data moves from raw satellite imagery to final crop-type predictions:

graph LR
    subgraph "External Sources"
        DEA[Digital Earth Africa STAC]
    end

    subgraph "Storage (MinIO)"
        DS[(/geocrop-datasets)]
        BS[(/geocrop-baselines)]
        MD[(/geocrop-models)]
        RS[(/geocrop-results)]
    end

    subgraph "Processing"
        TRAIN[Jupyter Training]
        INFER[Inference Worker]
    end

    %% Data movement
    DEA -- "Sentinel-2 Imagery" --> INFER
    DS -- "CSV Batches" --> TRAIN
    TRAIN -- "Trained Models" --> MD
    MD -- "Model Load" --> INFER
    BS -- "DW TIFFs" --> INFER
    INFER -- "Classification COG" --> RS
    RS -- "Map Tiles" --> WEB[Frontend Visualization]

🗺️ UX Data Flow: Parallel Loading Strategy

To ensure a seamless user experience, the system implements a dual-loading strategy:

sequenceDiagram
    participant U as User (Frontend)
    participant T as TiTiler (S3 Proxy)
    participant A as FastAPI
    participant W as ML Worker
    participant M as MinIO

    U->>A: Submit Job (AOI + Year)
    A->>U: Job ID (Accepted)
    
    par Instant Visual Context
        U->>T: Fetch Baseline Tiles (DW)
        T->>M: Stream Baseline COG
        M->>T: 
        T->>U: Render Baseline Map
    and Asynchronous Prediction
        A->>W: Enqueue Task
        W->>M: Fetch Model & Data
        W->>W: Run Inference & Post-processing
        W->>M: Upload Prediction COG
        loop Polling
            U->>A: Get Status?
            A-->>U: Processing...
        end
        W->>A: Job Complete
        U->>A: Get Status?
        A->>U: Prediction URL
        U->>T: Fetch Prediction Tiles
        T->>M: Stream Prediction COG
        T->>U: Overlay High-Res Result
    end

🚀 Deployment & GitOps Pipeline

graph LR
    DEV[Developer] -->|Push| GITEA[Gitea]
    
    subgraph "CI/CD Pipeline"
        GITEA -->|Trigger| GA[Gitea Actions]
        GA -->|Build & Push| DH[Docker Hub: frankchine]
    end

    subgraph "GitOps Sync"
        ARGO[ArgoCD] -->|Monitor| GITEA
        DH -->|Image Pull| K3S[K3s Cluster]
        ARGO -->|Apply Manifests| K3S
    end

🛠️ Training Workflow

Training is performed in JupyterLab using a custom MinIOStorageClient that bridges the gap between object storage and in-memory data processing.

Using the MinIO Storage Client

from training.storage_client import MinIOStorageClient

# Initialize client (uses environment variables automatically)
storage = MinIOStorageClient()

# List available training batches
batches = storage.list_files('geocrop-datasets')

# Load a batch directly into memory (No disk I/O)
df = storage.load_dataset('geocrop-datasets', 'batch_1.csv')

# Train your model and upload the artifact
# ... training code ...
storage.upload_file('model.pkl', 'geocrop-models', 'Zimbabwe_Ensemble_Model.pkl')

🖥️ Service Registry


Created and maintained by fchinembiri.