Metadata-Version: 2.4
Name: gtm-admin
Version: 0.1.24
Summary: Workflow monitoring and management for FastAPI apps
License: MIT License
        
        Copyright (c) 2026 GTM Admin Contributors
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Classifier: Framework :: FastAPI
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.11
Requires-Dist: alembic>=1.14.0
Requires-Dist: asyncpg>=0.30.0
Requires-Dist: bcrypt>=4.0.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic-settings>=2.0.0
Requires-Dist: python-jose[cryptography]>=3.3.0
Requires-Dist: python-multipart>=0.0.12
Requires-Dist: sqlmodel>=0.0.22
Requires-Dist: uvicorn[standard]>=0.32.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: hatchling>=1.25.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# gtm-admin

Workflow monitoring and management for FastAPI apps.

`gtm-admin` adds a self-hosted dashboard and run-tracking API to **any FastAPI application** with zero infrastructure setup. Decorate Python workflow functions with `@gtm.workflow` and choose how they are triggered: manually, on a cron schedule, or via a webhook.

## Install

```bash
pip install gtm-admin

# Required for cron-scheduled workflows:
pip install apscheduler
```

## Usage

```python
import os
from fastapi import FastAPI
from gtm_admin import GTMAdmin

app = FastAPI()

gtm = GTMAdmin(
    app,
    db_url=os.environ["GTM_DB_URL"],
    secret=os.environ["GTM_SECRET"],
)

# ── Manual workflow (called from your own code) ──────────────────────────────
@gtm.workflow
async def enrich_leads(inputs: dict):
    results = call_some_api(inputs["leads"])
    return {"enriched": results}

# ── Cron workflow (runs on a schedule automatically) ──────────────────────────
@gtm.workflow(cron="0 9 * * 1-5")   # every weekday at 09:00
async def daily_sync(inputs: dict):
    return {"synced": sync_database()}

# ── Webhook workflow (triggered by an external HTTP POST) ─────────────────────
@gtm.workflow(webhook=True)
# → auto-mounts POST /api/webhooks/process_event
async def process_event(inputs: dict):
    return handle(inputs)
```

## Workflow Decorator Options

| Parameter  | Type   | Default | Description                                                         |
| ---------- | ------ | ------- | ------------------------------------------------------------------- |
| `cron`     | `str`  | `None`  | 5-field cron expression. Requires `apscheduler`.                    |
| `interval` | `int`  | `None`  | Run every N seconds. Requires `apscheduler`.                        |
| `webhook`  | `bool` | `False` | Auto-mount `POST /api/webhooks/{name}`. Body is passed as `inputs`. |

When used without arguments (`@gtm.workflow`) the workflow is **manual** — called directly from your code or via the dashboard re-run button.

### Cron syntax

```
┌───── minute (0-59)
│ ┌───── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌───── month (1-12)
│ │ │ │ ┌───── day of week (0-6 or 1-5 for Mon–Fri)
* * * * *
```

```python
@gtm.workflow(cron="0 9 * * 1-5")   # every weekday at 09:00
async def daily_sync(inputs: dict): ...

@gtm.workflow(interval=10)           # every 10 seconds
async def frequent_job(inputs: dict): ...
```

### Webhook usage

```bash
curl -X POST https://your-app.com/api/webhooks/process_event \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}'
```

The JSON body is passed as `inputs` to your workflow function. Every invocation is tracked as a `WorkflowRun` with `trigger_type = "webhook"`.

## GTMAdmin options

| Parameter   | Type    | Required | Default | Description                                                   |
| ----------- | ------- | -------- | ------- | ------------------------------------------------------------- |
| `app`       | FastAPI | ✓        | —       | Your FastAPI application instance                             |
| `db_url`    | str     | ✓        | —       | PostgreSQL connection string (`postgresql+asyncpg://...`)     |
| `secret`    | str     | ✓        | —       | Secret key for signing JWT tokens                             |
| `dev`       | bool    |          | `False` | Proxy `/admin/*` to Vite HMR server instead of serving static |
| `auto_seed` | bool    |          | `False` | Seed the database with demo data on startup                   |

## API Routes

All routes are mounted under `/api` on your FastAPI app.

| Method | Path                            | Auth | Description                                |
| ------ | ------------------------------- | ---- | ------------------------------------------ |
| POST   | `/api/auth/token`               | —    | Log in; returns a JWT access token         |
| POST   | `/api/auth/register`            | —    | Register a new user account                |
| GET    | `/api/health`                   | —    | Health check                               |
| POST   | `/api/webhooks/{name}`          | —    | Invoke a webhook-enabled workflow          |
| GET    | `/api/workflow-runs`            | ✓    | Paginated list of runs (filterable)        |
| GET    | `/api/workflow-runs/stats`      | ✓    | Status counts + active/recent run lists    |
| GET    | `/api/workflow-runs/{id}`       | ✓    | Full run detail with nodes                 |
| POST   | `/api/workflow-runs/{id}/rerun` | ✓    | Re-execute a workflow with the same inputs |
| GET    | `/api/config`                   | ✓    | List all config records                    |
| POST   | `/api/config`                   | ✓    | Create a config record                     |
| PATCH  | `/api/config/{id}`              | ✓    | Update a config record                     |
| DELETE | `/api/config/{id}`              | ✓    | Delete a config record                     |
| GET    | `/api/db-tables`                | ✓    | List all database tables                   |
| POST   | `/api/db-tables`                | ✓    | Create a table                             |
| PATCH  | `/api/db-tables/{id}`           | ✓    | Update a table's schema or rows            |
| DELETE | `/api/db-tables/{id}`           | ✓    | Delete a table                             |
| GET    | `/admin/`                       | —    | Dashboard SPA                              |

## Dashboard Features

| Page            | Route            | Description                                         |
| --------------- | ---------------- | --------------------------------------------------- |
| Overview        | `/`              | Status count cards, active runs, and recent runs    |
| Workflows       | `/workflows`     | Searchable/filterable table; click a row for detail |
| Workflow Detail | `/workflows/:id` | Node-level I/O, timing, logs; re-run button         |
| Config          | `/config`        | Key/value configuration store with typed fields     |
| Database        | `/database`      | Lightweight table viewer and editor                 |

## Deployment

```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install gtm-admin
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
```

Set the following environment variables in your hosting console:

| Variable     | Description                                          |
| ------------ | ---------------------------------------------------- |
| `GTM_DB_URL` | PostgreSQL connection string (Supabase, Neon, …)     |
| `GTM_SECRET` | Random secret — generate with `openssl rand -hex 32` |

## Development mode

In dev mode, `/admin/*` is proxied to a Vite HMR server instead of serving static files. Use this when developing the dashboard locally:

```python
gtm = GTMAdmin(app, db_url=..., secret=..., dev=os.getenv("GTM_DEV") == "true")
```

## Package Structure

```
api/
├── src/gtm_admin/          # The published library
│   ├── __init__.py         # Exports GTMAdmin
│   ├── core.py             # GTMAdmin class — mounts router + dashboard
│   ├── auth.py             # JWT creation/verification + bcrypt helpers
│   ├── database.py         # Async SQLAlchemy engine + session factory + migrations
│   ├── decorator.py        # @gtm.workflow — wraps functions with run capture logic
│   ├── deps.py             # get_current_user FastAPI dependency
│   ├── models.py           # WorkflowRun, User, ConfigRecord, DbTable SQLModel models
│   ├── router.py           # All API route handlers + Pydantic response schemas
│   ├── seed.py             # Demo data seeder (used by auto_seed=True)
│   └── static/             # Built React SPA (populated by `pnpm run build`)
├── app/                    # Standalone FastAPI app for local development
│   ├── main.py             # App entry point — includes all routers + Vite proxy
│   ├── auth.py             # Auth helpers (mirrors the library)
│   ├── config.py           # pydantic-settings config (DATABASE_URL, SECRET_KEY)
│   ├── database.py         # Engine + session setup for the standalone app
│   ├── deps.py             # FastAPI dependencies
│   ├── models/             # SQLModel models (WorkflowRun, User, ConfigRecord, DbTable)
│   └── routers/            # auth, workflow_runs, configs, db_tables, execution_buckets
├── alembic/                # Database migrations for the standalone dev app
├── seed.py                 # Seed script (run directly: uv run python seed.py)
├── hatch_build.py          # Build hook — runs `pnpm run build` before packaging
└── pyproject.toml          # Package metadata + hatchling build config
```

## Local development setup

```bash
cd api
cp .env.example .env        # Set DATABASE_URL and SECRET_KEY
uv sync                      # Creates .venv and installs all dependencies
uv run alembic upgrade head  # Apply migrations
uv run python seed.py        # (Optional) seed demo data
```

Run the standalone dev server (from the monorepo root):

```bash
make dev-api                 # FastAPI on :8080 with GTM_DEV=true
make dev-frontend            # Vite on :5173 (run concurrently for HMR)
make dev                     # Both at once
```

## Requirements

- Python 3.11+
- PostgreSQL database (Supabase, Neon, or self-hosted)
- FastAPI app

## License

MIT
