saterys 0.4.2
Saterys — Scalable Analysis Toolkit for Earth Remote sYStemS
License: MIT
Requires Python: >=3.9

<div align="center">

# <img width="25" height="25" alt="SATERYS_Icon" src="https://github.com/user-attachments/assets/3aca7c9b-4dc9-4cb2-be2b-b59aaf718900" /> SATERYS

### Scalable Analysis Toolkit for Earth Remote sYStemS

[![PyPI version](https://img.shields.io/pypi/v/saterys.svg?style=for-the-badge&color=brightgreen)](https://pypi.org/project/saterys/)
[![Python versions](https://img.shields.io/pypi/pyversions/saterys.svg?style=for-the-badge&color=blue)](https://pypi.org/project/saterys/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](LICENSE)
[![Build](https://img.shields.io/github/actions/workflow/status/bastian6666/saterys/ci.yml?style=for-the-badge&label=build&color=purple)](https://github.com/bastian6666/saterys/actions)

**A modern geospatial pipeline builder with interactive node-based workflows**

[📖 Documentation](#-documentation) • [🚀 Quick Start](#-quick-start) • [🎯 Examples](#-examples) • [🔌 Plugins](#-plugins)

</div>

---

## 🌟 Overview

**SATERYS** is a powerful geospatial analysis platform that combines the best of modern web technologies with robust geospatial processing capabilities. Build complex Earth observation workflows using an intuitive drag-and-drop interface, execute Python-based analysis nodes, and visualize results on interactive maps.

![SATERYS Interface](https://github.com/user-attachments/assets/e070d04e-eb8c-4b4e-a798-5a3ad76621ff)

## ✨ Key Features

<table>
<tr>
<td>

### 🎨 **Visual Pipeline Builder**
- Interactive, node-based workflow canvas powered by [Svelvet](https://svelvet.io/)
- Drag-and-drop creation and editing of geospatial analysis pipelines
- Real-time connection validation and error highlighting
- Dark/Light theme support for comfortable use in any environment
- Visual grouping and annotation of workflow components

</td>
<td>

### ⚡ **High-Performance Backend**
- FastAPI-powered REST API for rapid, scalable processing
- Asynchronous execution for efficient resource use
- Hot-reloadable plugin system for instant extension and customization
- Automatic error handling and detailed logging
- Built-in job queue for batch and long-running tasks

</td>
</tr>
<tr>
<td>

### 🛰️ **Geospatial Native**
- Native support for GeoTIFF, COG, and other raster formats
- Interactive map preview with Leaflet and tile-based raster visualization via [rio-tiler](https://github.com/cogeotiff/rio-tiler)
- Coordinate system handling and automatic reprojection
- Raster statistics, band math, and index calculation (NDVI, NDWI, PCA, etc.)
- Vector data support (GeoJSON, SHP, GPKG) for overlays and analysis

</td>
<td>

### 🔌 **Extensible & Modular Architecture**
- Plugin-based node system: add your own analysis nodes in Python
- Custom analysis functions and reusable workflow components
- Easy integration with existing Python geospatial tools (NumPy, Rasterio, Shapely, etc.)
- Modular design for rapid prototyping and extension
- Built-in and user-defined nodes auto-discovered at startup

</td>
</tr>
<tr>
<td>

### 🧩 **Plugin Ecosystem**
- Simple plugin API for adding new node types
- Hot-reload support for rapid development
- Community-contributed plugins for specialized tasks

</td>
<td>

### 🖥️ **Modern Web UI**
- Responsive, single-page application built with Svelte
- Real-time workflow editing and execution feedback
- Integrated documentation and example workflows
- User authentication and role-based access (optional)

</td>
</tr>
</table>

---

## 🚀 Quick Start

### Installation

```bash
# Install SATERYS
pip install saterys
# Verify installation
saterys --help
```

### Launch the Application

```bash
# Start SATERYS server
saterys

# Access the web interface at http://localhost:8000
```

The application will automatically:
- 🔍 Discover all available plugins
- 🌐 Start the FastAPI backend 
- 🎨 Serve the Svelte frontend
- 📊 Open your default browser

### Development Mode

For development with hot-reload:

```bash
# Start with auto-reload
saterys --dev
```

---

## 🎯 Examples

### Basic Workflow: Hello World

1. **Add a Node**: Click "Add Node" and select "hello"
2. **Configure**: Set the name parameter to "SATERYS"  
3. **Execute**: Click the "Run" button
4. **View Results**: Check the output in the logs panel

```python
# This runs automatically when you execute the hello node
def run(args, inputs, context):
    name = args.get("name", "world")
    return {"text": f"hello {name}"}
```

### Geospatial Workflow: NDVI Calculation

Create a vegetation index from satellite imagery:

```bash
# 1. Add a raster input node
# 2. Set path to your multispectral image (e.g., Landsat, Sentinel)
# 3. Add NDVI calculation node
# 4. Configure band indices (e.g., red=4, nir=5 for Landsat 8)
# 5. Connect nodes and execute
```

**Example NDVI Node Configuration:**
```json
{
  "red_band": 4,
  "nir_band": 5,
  "output_path": "./results/ndvi_output.tif",
  "dtype": "float32"
}
```

### Custom Processing with Script Node

Write inline Python for custom analysis:

```python
# Script node example - band math
import numpy as np
import rasterio

def process_raster(input_raster):
    with rasterio.open(input_raster["path"]) as src:
        # Read bands
        red = src.read(4).astype(float)
        nir = src.read(5).astype(float)
        
        # Custom vegetation index
        evi = 2.5 * ((nir - red) / (nir + 6 * red - 7.5 * blue + 1))
        
        return {"custom_index": evi}
```

---

## 📚 Documentation

### Built-in Nodes

| Node Type | Description | Use Case |
|-----------|-------------|----------|
| 🔢 **raster.input** | Load GeoTIFF/COG files | Data ingestion |
| 🌿 **raster.ndvi** | Calculate NDVI | Vegetation analysis |
| 🌊 **raster.ndwi** | Calculate NDWI | Water body detection |
| 📊 **raster.pca** | Principal Component Analysis | Dimensionality reduction |
| ➕ **sum** | Sum numeric values | Basic arithmetic |
| 👋 **hello** | Hello world example | Testing/demos |
| 📝 **script** | Custom Python code | Flexible processing |

### API Endpoints

The FastAPI backend provides REST endpoints for integration:

```bash
# Get available node types
GET /node_types

# Execute a node
POST /run_node
{
  "nodeId": "unique-id",
  "type": "raster.ndvi", 
  "args": {"red_band": 4, "nir_band": 5},
  "inputs": {...}
}

# Register raster for preview
POST /preview/register
{
  "id": "my-raster",
  "path": "/path/to/file.tif"
}

# Get map tiles
GET /preview/tile/{id}/{z}/{x}/{y}.png
```

---

## 🔌 Plugins

SATERYS features a powerful plugin-first architecture that allows you to extend functionality without modifying the core.

### Plugin System

The plugin system provides two extension points:

- **Backend Plugins (Python)**: Add new REST API endpoints using FastAPI
- **Frontend Plugins (TypeScript)**: Add toolbar buttons, menus, canvas overlays, and custom nodes

### Quick Start: Running the Demo

1. **Build the frontend** (includes plugin build):
   ```bash
   cd saterys/web
   npm install
   npm run build
   ```

2. **Run the server**:
   ```bash
   cd ../..
   saterys
   ```

3. **Access the UI** at `http://localhost:8000`

4. **Click "Hello Plugin"** button in the toolbar
   - Shows toast notification
   - Calls `/plugins/starter/echo` backend endpoint
   - Displays "Echo OK" on success

### Creating Your Own Plugins

**Backend Plugin Structure:**
```
plugins/
  my_plugin/
    __init__.py          # Plugin code
    pyproject.toml       # Entry point registration
```

**Frontend Plugin Structure:**
```
saterys/web/plugins/
  @saterys/my-plugin/
    src/index.ts         # Plugin code
    tsconfig.json        # TypeScript config
    package.json         # Build scripts
```

See [`docs/plugin-api.md`](docs/plugin-api.md) for complete documentation including:
- Backend plugin API with FastAPI router integration
- Frontend registry functions (toolbar, menus, overlays, nodes)
- AppContext API for accessing core services
- Authentication integration
- Best practices and examples

### Starter Plugins

The repository includes fully-functional starter plugins:
- **Python**: `plugins/saterys_plugin_starter/` - Echo endpoint example
- **UI**: `saterys/web/plugins/@saterys/plugin-starter/` - Toolbar button + API call

Use these as templates for creating your own plugins!

---

## 🧩 Creating Plugins

SATERYS uses a simple plugin architecture. Create custom nodes by adding Python files to a `nodes/` directory:

### Basic Plugin Structure

```python
# nodes/my_custom_node.py

NAME = "my.custom.node"  # Unique identifier
DEFAULT_ARGS = {         # Default configuration
    "param1": "default_value",
    "param2": 42
}

def run(args, inputs, context):
    """
    Execute the node logic
    
    Args:
        args: Node configuration parameters
        inputs: Data from connected upstream nodes  
        context: Runtime context (nodeId, etc.)
        
    Returns:
        Dictionary with output data
    """
    # Your processing logic here
    result = process_data(args, inputs)
    
    return {
        "type": "custom",
        "data": result,
        "metadata": {...}
    }
```

### Raster Processing Plugin Example

```python
# nodes/custom_filter.py

NAME = "raster.custom_filter"
DEFAULT_ARGS = {
    "filter_size": 3,
    "operation": "gaussian"
}

def run(args, inputs, context):
    import rasterio
    import numpy as np
    from scipy import ndimage
    
    # Get input raster
    raster_input = next(
        (inp for inp in inputs.values() 
         if inp.get("type") == "raster"), 
        None
    )
    
    if not raster_input:
        raise ValueError("No raster input found")
    
    # Process the raster
    with rasterio.open(raster_input["path"]) as src:
        data = src.read(1)
        
        # Apply filter
        if args["operation"] == "gaussian":
            filtered = ndimage.gaussian_filter(
                data, 
                sigma=args["filter_size"]
            )
        
        # Save result...
        output_path = "/tmp/filtered_result.tif"
        # ... saving logic here ...
        
    return {
        "type": "raster",
        "path": output_path,
        "operation": "custom_filter"
    }
```

### Plugin Discovery

SATERYS automatically discovers plugins from:
1. **Built-in nodes**: `saterys/nodes/` (package installation)
2. **User nodes**: `./nodes/` (current working directory)

Simply restart the application after adding new plugins!

---

## 🛠️ Advanced Usage

### Environment Configuration

```bash
# Custom host and port
export SATERYS_HOST=0.0.0.0  
export SATERYS_PORT=8080

# Raster cache directory
export RASTER_CACHE=./my_cache

# Development frontend origin (for CORS)
export SATERYS_DEV_ORIGIN=http://localhost:5173
```

### Docker Usage

```dockerfile
FROM python:3.10-slim

RUN pip install saterys

# Add your custom nodes
COPY nodes/ /app/nodes/

WORKDIR /app

EXPOSE 8000

CMD ["saterys", "--host", "0.0.0.0"]
```

### Programmatic Usage

```python
import uvicorn
from saterys.app import app

# Customize the FastAPI app
@app.get("/custom")  
def custom_endpoint():
    return {"message": "Custom endpoint"}

# Run programmatically
if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

---

## 🤝 Contributing

We welcome contributions! Here's how to get started:

### Development Setup

```bash
# Clone the repository
git clone https://github.com/bastian6666/SATERYS.git
cd SATERYS

# Install in development mode
pip install -e .

# Install frontend dependencies (if modifying UI)
cd saterys/web
npm install

# Start development server
npm run dev
```

### Code Style

- Follow PEP 8 for Python code
- Use type hints where possible  
- Add docstrings for public functions
- Test your changes before submitting

### Submitting Changes

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

---

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

## 🙏 Acknowledgments

- **[FastAPI](https://fastapi.tiangolo.com/)**: For building modern, high-performance APIs with ease.
- **[Uvicorn](https://www.uvicorn.org/)**: An ASGI server for lightning-fast application deployment.
- **[Pydantic](https://docs.pydantic.dev/)**: Ensuring data validation and management is smooth and reliable.
- **[NumPy](https://numpy.org/)**: The foundation for numerical computing in Python.
- **[rio-tiler](https://github.com/cogeotiff/rio-tiler)**: Efficient raster tiling and preview generation.
- **[Rasterio](https://rasterio.readthedocs.io/)**: Simplifying geospatial raster data I/O.
- **[Fiona](https://fiona.readthedocs.io/)**: A powerful library for vector data handling (GPKG/SHP).
- **[PyProj](https://pyproj4.github.io/pyproj/)**: For seamless coordinate reference system transformations.
- **[Shapely](https://shapely.readthedocs.io/)**: Geometry manipulation made easy.
- **[APScheduler](https://apscheduler.readthedocs.io/)**: A flexible scheduling library for background jobs.
- **[SQLAlchemy](https://www.sqlalchemy.org/)**: The go-to library for database interaction and ORM functionality.
- **[pytz](https://pytz.sourceforge.net/)**: Comprehensive timezone support.
- **[tzlocal](https://github.com/regebro/tzlocal)**: Simplifies local timezone detection.

---

## 📞 Support

- 📖 [Documentation](docs/)
- 🐛 [Issue Tracker](https://github.com/bastian6666/SATERYS/issues)
- 💬 [Discussions](https://github.com/bastian6666/SATERYS/discussions)
- 📧 [Email](mailto:bastian@example.com)

---

<div align="center">

**Made with ❤️ for the geospatial community**

[![GitHub stars](https://img.shields.io/github/stars/bastian6666/SATERYS?style=social)](https://github.com/bastian6666/SATERYS/stargazers)
[![Twitter Follow](https://img.shields.io/twitter/follow/YourTwitter?style=social)](https://twitter.com/YourTwitter)

</div>