# Supabase Plugin Design - Phase G

> **MCP Plugin برای مدیریت Supabase Self-Hosted روی Coolify**

**Version**: v1.1.0 (طراحی - Self-Hosted)
**Priority**: High
**Estimated Tools**: 70-75

---

## Overview

پلاگین Supabase برای مدیریت **Supabase Self-Hosted** روی Coolify طراحی شده است.

### تفاوت Self-Hosted با Cloud

```
┌─────────────────────────────────────────────────────────────────┐
│              Supabase Self-Hosted vs Cloud                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ✅ موجود در Self-Hosted:                                       │
│  ├── Database API (PostgREST) - /rest/v1/                       │
│  ├── Auth API (GoTrue) - /auth/v1/                              │
│  ├── Storage API - /storage/v1/                                 │
│  ├── Edge Functions - /functions/v1/                            │
│  ├── postgres-meta (DB Admin) - /pg/                            │
│  └── Realtime - /realtime/v1/ (WebSocket)                       │
│                                                                  │
│  ❌ فقط در Cloud:                                                │
│  ├── Management API (api.supabase.com)                          │
│  ├── Projects & Organizations                                    │
│  ├── Database Branches                                           │
│  ├── Platform Analytics                                          │
│  └── Secrets Management (platform-level)                         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

**نکته مهم**: در Self-Hosted، هر instance یک پروژه است. Management API وجود ندارد.

---

## Authentication

### سطح واحد احراز هویت

```
┌─────────────────────────────────────────────────────────────────┐
│                 Supabase Self-Hosted Auth                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  API Keys (JWT-based):                                           │
│  ├── anon_key                                                    │
│  │   ├── Public/client-safe                                      │
│  │   ├── Protected by RLS policies                               │
│  │   └── role: "anon" in JWT                                     │
│  │                                                               │
│  └── service_role_key                                            │
│      ├── ⚠️ SERVER-ONLY - Never expose!                          │
│      ├── Bypasses ALL RLS policies                               │
│      └── role: "service_role" in JWT                             │
│                                                                  │
│  All keys signed with JWT_SECRET from .env                       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

### Environment Variables

```bash
# Supabase Self-Hosted Instance (Required)
SUPABASE_SITE1_URL=https://supabase.example.com
SUPABASE_SITE1_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SITE1_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SITE1_ALIAS=mysupabase

# Optional: Direct postgres-meta URL (when /pg/ is not exposed via Kong)
# SUPABASE_SITE1_META_URL=http://supabase-meta:8080
#
# Optional: Basic Auth for postgres-meta (when exposed via public URL)
# SUPABASE_SITE1_META_AUTH=admin:secretpassword

# Multiple Instances
SUPABASE_SITE2_URL=https://supabase-staging.example.com
SUPABASE_SITE2_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SITE2_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SITE2_ALIAS=staging
```

---

## API Endpoints (Kong Gateway)

تمام API ها از طریق Kong API Gateway (پورت 8000) در دسترس هستند:

```
Base URL: https://supabase.example.com (یا http://localhost:8000)

Database (PostgREST):
  GET/POST/PATCH/DELETE /rest/v1/{table}
  POST /rest/v1/rpc/{function}

Auth (GoTrue):
  POST /auth/v1/signup
  POST /auth/v1/token
  GET  /auth/v1/user
  POST /auth/v1/admin/users
  ...

Storage:
  GET/POST/DELETE /storage/v1/bucket
  GET/POST/DELETE /storage/v1/object/{bucket}/{path}
  ...

Edge Functions:
  POST /functions/v1/{function_name}

postgres-meta (Admin):
  GET  /pg/tables
  GET  /pg/columns
  GET  /pg/policies
  ...
```

---

## Architecture

### Project Structure

```
plugins/supabase/
├── __init__.py              # Export: SupabasePlugin, SupabaseClient
├── plugin.py                # کلاس اصلی SupabasePlugin
├── client.py                # SupabaseClient (unified client)
└── handlers/
    ├── __init__.py
    ├── database.py          # Database operations (18 tools)
    ├── auth.py              # User management (14 tools)
    ├── storage.py           # File management (12 tools)
    ├── functions.py         # Edge Functions (8 tools)
    ├── admin.py             # postgres-meta admin (12 tools)
    └── system.py            # Health & info (6 tools)
```

### Client Architecture

```python
class SupabaseClient:
    """
    Unified client for Supabase Self-Hosted APIs

    All requests go through Kong gateway on single base URL.
    """
    def __init__(
        self,
        base_url: str,               # e.g., https://supabase.example.com
        anon_key: str,               # For public/RLS-protected operations
        service_role_key: str,       # For admin operations (bypasses RLS)
    ):
        self.base_url = base_url.rstrip('/')
        self.anon_key = anon_key
        self.service_role_key = service_role_key

    async def request(
        self,
        method: str,
        endpoint: str,
        use_service_role: bool = False,
        **kwargs
    ) -> Any:
        """Make authenticated request to Supabase API"""
        key = self.service_role_key if use_service_role else self.anon_key
        headers = {
            "apikey": key,
            "Authorization": f"Bearer {key}",
            "Content-Type": "application/json"
        }
        url = f"{self.base_url}{endpoint}"
        # ... request logic
```

---

## Tool Categories

### 1. Database Handler (18 tools)

عملیات CRUD روی دیتابیس PostgreSQL از طریق PostgREST

| Tool | Method | Scope | Description |
|------|--------|-------|-------------|
| `list_tables` | GET | read | لیست جداول (via postgres-meta) |
| `get_table_schema` | GET | read | ساختار جدول |
| `query_table` | GET | read | کوئری SELECT با فیلتر |
| `insert_rows` | POST | write | درج رکوردها |
| `update_rows` | PATCH | write | به‌روزرسانی رکوردها |
| `upsert_rows` | POST | write | درج/به‌روزرسانی |
| `delete_rows` | DELETE | write | حذف رکوردها |
| `execute_rpc` | POST | write | اجرای stored procedure |
| `count_rows` | GET | read | شمارش رکوردها |
| `get_row_by_id` | GET | read | دریافت یک رکورد با ID |
| `bulk_insert` | POST | write | درج دسته‌ای |
| `bulk_update` | PATCH | write | به‌روزرسانی دسته‌ای |
| `bulk_delete` | DELETE | write | حذف دسته‌ای |
| `search_text` | GET | read | جستجوی Full-text |
| `get_foreign_tables` | GET | read | جداول مرتبط |
| `execute_sql` | POST | admin | اجرای SQL مستقیم (via postgres-meta) |
| `create_table` | POST | admin | ایجاد جدول جدید |
| `drop_table` | DELETE | admin | حذف جدول |

```python
# Query Table Example
{
    "name": "supabase_query_table",
    "description": "Query data from a Supabase table with filters and pagination",
    "schema": {
        "type": "object",
        "properties": {
            "site": {
                "type": "string",
                "description": "Supabase instance alias or site ID"
            },
            "table": {
                "type": "string",
                "description": "Table name"
            },
            "select": {
                "type": "string",
                "description": "Columns to select (e.g., 'id,name,email' or '*')",
                "default": "*"
            },
            "filters": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "column": {"type": "string"},
                        "operator": {
                            "type": "string",
                            "enum": ["eq", "neq", "gt", "gte", "lt", "lte",
                                     "like", "ilike", "in", "is", "cs", "cd"]
                        },
                        "value": {}
                    }
                },
                "description": "PostgREST filter conditions"
            },
            "order": {
                "type": "string",
                "description": "Order by (e.g., 'created_at.desc')"
            },
            "limit": {
                "type": "integer",
                "default": 100,
                "maximum": 1000
            },
            "offset": {
                "type": "integer",
                "default": 0
            }
        },
        "required": ["table"]
    },
    "scope": "read"
}
```

### 2. Auth Handler (14 tools)

مدیریت کاربران از طریق GoTrue Admin API

| Tool | Method | Scope | Description |
|------|--------|-------|-------------|
| `list_users` | GET | admin | لیست کاربران |
| `get_user` | GET | read | جزئیات کاربر |
| `create_user` | POST | admin | ایجاد کاربر |
| `update_user` | PUT | admin | به‌روزرسانی کاربر |
| `delete_user` | DELETE | admin | حذف کاربر |
| `invite_user` | POST | admin | ارسال دعوت‌نامه |
| `generate_link` | POST | admin | تولید magic/recovery link |
| `ban_user` | PUT | admin | مسدود کردن کاربر |
| `unban_user` | PUT | admin | رفع مسدودیت |
| `list_factors` | GET | read | لیست MFA factors |
| `delete_factor` | DELETE | admin | حذف MFA factor |
| `get_audit_logs` | GET | read | لاگ‌های auth |
| `verify_otp` | POST | write | تایید OTP |
| `resend_otp` | POST | write | ارسال مجدد OTP |

```python
# Create User Example
{
    "name": "supabase_create_user",
    "description": "Create a new user in Supabase Auth",
    "schema": {
        "type": "object",
        "properties": {
            "site": {"type": "string"},
            "email": {
                "type": "string",
                "format": "email"
            },
            "password": {
                "type": "string",
                "minLength": 6
            },
            "phone": {
                "type": "string",
                "description": "Phone number (E.164 format)"
            },
            "email_confirm": {
                "type": "boolean",
                "default": false,
                "description": "Auto-confirm email"
            },
            "user_metadata": {
                "type": "object",
                "description": "Custom user metadata"
            },
            "app_metadata": {
                "type": "object",
                "description": "App-specific metadata"
            }
        },
        "required": ["email", "password"]
    },
    "scope": "admin"
}
```

### 3. Storage Handler (12 tools)

مدیریت فایل‌ها و bucket ها

| Tool | Method | Scope | Description |
|------|--------|-------|-------------|
| `list_buckets` | GET | read | لیست bucket ها |
| `get_bucket` | GET | read | جزئیات bucket |
| `create_bucket` | POST | admin | ایجاد bucket |
| `update_bucket` | PUT | admin | به‌روزرسانی bucket |
| `delete_bucket` | DELETE | admin | حذف bucket |
| `empty_bucket` | POST | admin | خالی کردن bucket |
| `list_files` | GET | read | لیست فایل‌ها در مسیر |
| `upload_file` | POST | write | آپلود فایل |
| `download_file` | GET | read | دانلود فایل (base64) |
| `delete_files` | DELETE | write | حذف فایل‌ها |
| `move_file` | POST | write | انتقال/تغییر نام فایل |
| `get_public_url` | GET | read | دریافت URL عمومی |

### 4. Functions Handler (8 tools)

مدیریت و اجرای Edge Functions

| Tool | Method | Scope | Description |
|------|--------|-------|-------------|
| `list_functions` | GET | read | لیست functions موجود |
| `invoke_function` | POST | write | اجرای function |
| `invoke_function_get` | GET | read | اجرای function با GET |
| `get_function_body` | GET | read | دریافت کد function |
| `deploy_function` | POST | admin | deploy function جدید |
| `delete_function` | DELETE | admin | حذف function |
| `get_function_logs` | GET | read | لاگ‌های اخیر |
| `update_function_secrets` | PATCH | admin | تنظیم secrets |

**نکته**: در Self-Hosted، functions در `volumes/functions/` ذخیره می‌شوند.

### 5. Admin Handler (12 tools)

عملیات مدیریتی دیتابیس از طریق postgres-meta

| Tool | Method | Scope | Description |
|------|--------|-------|-------------|
| `list_schemas` | GET | read | لیست schemas |
| `list_extensions` | GET | read | لیست extensions |
| `enable_extension` | POST | admin | فعال‌سازی extension |
| `disable_extension` | DELETE | admin | غیرفعال‌سازی extension |
| `list_policies` | GET | read | لیست RLS policies |
| `create_policy` | POST | admin | ایجاد RLS policy |
| `update_policy` | PATCH | admin | به‌روزرسانی policy |
| `delete_policy` | DELETE | admin | حذف policy |
| `list_roles` | GET | read | لیست database roles |
| `list_triggers` | GET | read | لیست triggers |
| `list_functions_db` | GET | read | لیست DB functions |
| `get_database_size` | GET | read | سایز دیتابیس |

### 6. System Handler (6 tools)

سلامت و اطلاعات سیستم

| Tool | Method | Scope | Description |
|------|--------|-------|-------------|
| `health_check` | GET | read | بررسی سلامت |
| `get_config` | GET | read | تنظیمات فعلی |
| `get_version` | GET | read | نسخه سرویس‌ها |
| `test_connection` | GET | read | تست اتصال |
| `get_stats` | GET | read | آمار سرویس‌ها |
| `ping` | GET | read | Ping ساده |

---

## Tool Summary

| Handler | Tools | Description |
|---------|-------|-------------|
| Database | 18 | PostgREST CRUD + SQL |
| Auth | 14 | GoTrue user management |
| Storage | 12 | File & bucket management |
| Functions | 8 | Edge Functions |
| Admin | 12 | postgres-meta DB admin |
| System | 6 | Health & info |
| **Total** | **70** | |

---

## Implementation Phases

### Phase G.1: Core (Required)

**هدف**: دسترسی اولیه به Supabase Self-Hosted

1. **SupabasePlugin** class
2. **SupabaseClient** (unified)
3. **Database Handler** (18 tools)
4. **System Handler** (6 tools)

**ابزارها**: 24

### Phase G.2: Auth & Storage (Recommended)

**هدف**: مدیریت کاربران و فایل‌ها

1. **Auth Handler** (14 tools)
2. **Storage Handler** (12 tools)

**ابزارها**: 26 (جمع: 50)

### Phase G.3: Advanced (Complete)

**هدف**: قابلیت‌های پیشرفته

1. **Functions Handler** (8 tools)
2. **Admin Handler** (12 tools)

**ابزارها**: 20 (جمع: 70)

---

## PostgREST Operators Reference

| Operator | Description | Example |
|----------|-------------|---------|
| `eq` | Equal | `?column=eq.value` |
| `neq` | Not equal | `?column=neq.value` |
| `gt` | Greater than | `?column=gt.5` |
| `gte` | Greater or equal | `?column=gte.5` |
| `lt` | Less than | `?column=lt.10` |
| `lte` | Less or equal | `?column=lte.10` |
| `like` | LIKE (case-sensitive) | `?column=like.*pattern*` |
| `ilike` | LIKE (case-insensitive) | `?column=ilike.*pattern*` |
| `in` | IN array | `?column=in.(a,b,c)` |
| `is` | IS (null, true, false) | `?column=is.null` |
| `cs` | Contains (arrays) | `?column=cs.{a,b}` |
| `cd` | Contained by | `?column=cd.{a,b,c}` |
| `fts` | Full-text search | `?column=fts.query` |

---

## Error Handling

### PostgREST Errors

```python
async def handle_postgrest_error(response):
    data = await response.json()

    if response.status == 400:
        # Validation error
        raise ValidationError(data.get("message", "Invalid request"))
    elif response.status == 401:
        raise AuthError("Invalid API key")
    elif response.status == 403:
        # RLS policy violation
        raise RLSError(f"Row Level Security: {data.get('message')}")
    elif response.status == 404:
        raise NotFoundError("Resource not found")
    elif response.status == 409:
        raise ConflictError("Unique constraint violation")
    elif response.status == 406:
        raise NotAcceptableError("Invalid Accept header")
```

### GoTrue Errors

```python
async def handle_gotrue_error(response):
    data = await response.json()

    error_code = data.get("error_code") or data.get("code")
    message = data.get("msg") or data.get("message") or data.get("error_description")

    if error_code == "user_not_found":
        raise UserNotFoundError(message)
    elif error_code == "email_exists":
        raise DuplicateError("Email already registered")
    # ... more error codes
```

---

## Security Considerations

### Key Security

```
┌─────────────────────────────────────────────────────────────────┐
│                    API Key Security                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  anon_key:                                                       │
│  ├── ✅ Safe for client-side                                     │
│  ├── ✅ Protected by RLS policies                                │
│  ├── ⚠️ Always enable RLS on tables                              │
│  └── Used for: read operations, authenticated user actions      │
│                                                                  │
│  service_role_key:                                               │
│  ├── ❌ NEVER expose to client                                   │
│  ├── ❌ Bypasses ALL RLS policies                                │
│  ├── ✅ Server-side only                                         │
│  └── Used for: admin operations, background jobs                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

### Best Practices

1. **Always use RLS** - حتی با service_role_key، RLS را فعال نگه دارید
2. **Minimal service_role usage** - فقط وقتی واقعاً نیاز است
3. **Never log keys** - حتی در error messages
4. **Validate input** - قبل از اجرای SQL
5. **Audit admin operations** - تمام عملیات admin لاگ شود

---

## Example Usage

### Query Database

```json
{
    "tool": "supabase_query_table",
    "args": {
        "site": "mysupabase",
        "table": "users",
        "select": "id,email,created_at",
        "filters": [
            {"column": "role", "operator": "eq", "value": "admin"}
        ],
        "order": "created_at.desc",
        "limit": 50
    }
}
```

### Create User

```json
{
    "tool": "supabase_create_user",
    "args": {
        "site": "mysupabase",
        "email": "user@example.com",
        "password": "secure-password",
        "email_confirm": true,
        "user_metadata": {
            "name": "John Doe",
            "role": "editor"
        }
    }
}
```

### Upload File

```json
{
    "tool": "supabase_upload_file",
    "args": {
        "site": "mysupabase",
        "bucket": "avatars",
        "path": "users/123/profile.png",
        "content_base64": "iVBORw0KGgoAAAANSUhEUgAA...",
        "content_type": "image/png",
        "upsert": true
    }
}
```

### Invoke Edge Function

```json
{
    "tool": "supabase_invoke_function",
    "args": {
        "site": "mysupabase",
        "function_name": "send-notification",
        "body": {
            "user_id": "123",
            "message": "Hello from AI!"
        }
    }
}
```

---

## Coolify Deployment Notes

### Finding Supabase Credentials

در Coolify، بعد از deploy کردن Supabase:

1. **URL**: از Coolify dashboard → Project → Supabase → Domain
2. **Keys**: در Environment Variables:
   - `ANON_KEY` - کلید عمومی
   - `SERVICE_ROLE_KEY` - کلید ادمین
   - `JWT_SECRET` - برای verify کردن tokens

### Kong Gateway Port

```
Default: 8000
HTTPS: 8443 (اگر SSL فعال باشد)

Coolify معمولاً reverse proxy می‌کند:
https://supabase.example.com → Kong:8000
```

### Docker Compose Services

```yaml
# Supabase services on Coolify
services:
  kong:        # API Gateway - port 8000
  auth:        # GoTrue - /auth/v1/
  rest:        # PostgREST - /rest/v1/
  storage:     # Storage API - /storage/v1/
  meta:        # postgres-meta - /pg/
  functions:   # Edge Functions - /functions/v1/
  db:          # PostgreSQL
  realtime:    # Realtime WebSocket
```

---

## Endpoint Registration

### Endpoint Config

```python
# core/endpoints/config.py

EndpointType.SUPABASE: EndpointConfig(
    path="/supabase",
    name="Supabase Manager",
    description="Supabase Self-Hosted management (database, auth, storage, functions)",
    endpoint_type=EndpointType.SUPABASE,
    plugin_types=["supabase"],
    require_master_key=False,
    allowed_scopes={"read", "write", "admin"},
    tool_blacklist={
        "manage_api_keys_create",
        "manage_api_keys_delete",
        "manage_api_keys_rotate",
        "oauth_register_client",
        "oauth_revoke_client",
    },
    max_tools=80,
),
```

---

## Testing Checklist

### Unit Tests

- [ ] SupabaseClient authentication
- [ ] PostgREST CRUD operations
- [ ] PostgREST filtering and pagination
- [ ] GoTrue user operations
- [ ] Storage file operations
- [ ] Error handling for all endpoints

### Integration Tests

- [ ] Query and modify database
- [ ] Create and authenticate user
- [ ] Upload and download file
- [ ] Invoke Edge Function
- [ ] RLS policy enforcement
- [ ] Service role bypass

---

## Security: postgres-meta

**postgres-meta has NO built-in authentication.** It is designed as an internal service
behind Kong API Gateway. When accessed through Kong's `/pg/` route, Kong validates JWT tokens.

### Risk: Public Exposure

If postgres-meta is exposed via a public URL (e.g., on Coolify with a public domain),
**anyone with the URL can execute SQL as `supabase_admin`**.

### Deployment Scenarios

| Deployment | meta_url needed? | meta_auth needed? | Notes |
|-----------|:---:|:---:|-------|
| supabase.com cloud | N/A | N/A | postgres-meta tools disabled |
| Docker Compose (standard) | No | No | Kong handles JWT via `/pg/` |
| Docker Compose (no /pg/) | Yes (internal URL) | No | Internal network is secure |
| Coolify (internal URL) | Yes | No | Internal Docker network |
| Coolify (public domain) | Yes | **Yes** | Exposed without auth |
| MCP Hub hosted users | Yes (public URL) | **Yes** | Must use public URL |

### Recommendations

1. **Prefer internal Docker network URLs** (`http://supabase-meta:8080`) when possible
2. **If public URL required**: Configure Basic Auth via reverse proxy and set `META_AUTH`
3. **Never expose postgres-meta publicly without authentication**

### MCP Hub Support

MCP Hub supports `META_AUTH` (format: `username:password`) for Basic Auth with postgres-meta.
When configured, requests to postgres-meta use `Authorization: Basic ...` instead of JWT.

---

## References

- [Supabase Self-Hosting Docker](https://supabase.com/docs/guides/self-hosting/docker)
- [PostgREST Documentation](https://postgrest.org/en/stable/)
- [GoTrue API Reference](https://github.com/supabase/auth)
- [Supabase Storage API](https://supabase.com/docs/guides/storage)
- [Kong API Gateway](https://docs.konghq.com/)
- [postgres-meta](https://github.com/supabase/postgres-meta)

---

**Created**: 2025-11-29
**Updated**: 2025-11-29 (Self-Hosted version)
**Author**: Claude AI Assistant
**Status**: Design Phase
