# quick start: postgres backend

this guide shows how to switch from in-memory to postgres storage in 5 minutes.

## step 1: install postgres dependencies

```bash
cd /Users/dorsa/Desktop/PROJECTS/synq_2/synqed-python
pip install sqlalchemy asyncpg
```

## step 2: start local postgres (using docker)

```bash
# pull and run postgres
docker run --name agent-registry-postgres \
  -e POSTGRES_PASSWORD=password \
  -e POSTGRES_DB=agentdb \
  -p 5432:5432 \
  -d postgres:15

# verify it's running
docker ps
```

or use existing postgres installation:

```bash
# create database
createdb agentdb

# or using psql
psql -c "CREATE DATABASE agentdb;"
```

## step 3: set environment variable

```bash
# for local postgres
export DATABASE_URL="postgresql+asyncpg://postgres:password@localhost:5432/agentdb"

# for cloud postgres (example)
# export DATABASE_URL="postgresql+asyncpg://user:pass@your-host.com:5432/agentdb"
```

## step 4: update main.py to init database on startup

the registry api already checks for `DATABASE_URL` and uses postgres if set.
we just need to initialize the database tables on startup.

update `synqed/agent_email/main.py`:

```python
import os
from synqed.agent_email.registry.api import get_registry

# add startup event
@app.on_event("startup")
async def startup_event():
    """initialize database tables if using postgres."""
    database_url = os.getenv("DATABASE_URL")
    
    if database_url:
        print("initializing postgres database...")
        registry = get_registry()
        
        # postgres registry has init_db method
        if hasattr(registry, 'init_db'):
            await registry.init_db()
            print("✓ database tables created")
    else:
        print("using in-memory registry (no DATABASE_URL set)")
```

## step 5: update registry api to support both backends

the registry api needs small updates to handle async operations.

update `synqed/agent_email/registry/api.py`:

```python
import os

# at the top, add postgres import
_global_registry = None
_using_postgres = False


def get_registry():
    """get registry instance (postgres if DATABASE_URL set, else in-memory)."""
    global _global_registry, _using_postgres
    
    if _global_registry is None:
        database_url = os.getenv("DATABASE_URL")
        
        if database_url:
            # use postgres backend
            from synqed.agent_email.registry.db import PostgresAgentRegistry
            _global_registry = PostgresAgentRegistry(database_url)
            _using_postgres = True
        else:
            # fallback to in-memory for local dev
            from synqed.agent_email.registry.models import AgentRegistry
            _global_registry = AgentRegistry()
            _using_postgres = False
    
    return _global_registry


def is_using_postgres() -> bool:
    """check if using postgres backend."""
    return _using_postgres
```

then update endpoints to handle async if using postgres:

```python
@router.post("")
async def register_agent(request: AgentRegistrationRequest):
    registry = get_registry()
    
    # ... validation code ...
    
    # register (handles both sync and async)
    if is_using_postgres():
        await registry.register(entry)
    else:
        registry.register(entry)
    
    return entry
```

## step 6: run the server

```bash
# make sure DATABASE_URL is set
export DATABASE_URL="postgresql+asyncpg://postgres:password@localhost:5432/agentdb"

# run server
python demos/demo_server.py
```

you should see:

```
initializing postgres database...
✓ database tables created
registering demo agent runtimes...
✓ registered cosmos and gemini runtimes
...
```

## step 7: test it works

in another terminal:

```bash
# run demo
python demos/cosmos_gemini_demo.py
```

## verify postgres is being used

```bash
# connect to postgres
docker exec -it agent-registry-postgres psql -U postgres -d agentdb

# check tables
\dt

# should show:
#            List of relations
#  Schema |      Name       | Type  |  Owner   
# --------+-----------------+-------+----------
#  public | agent_registry  | table | postgres

# query agents
SELECT agent_id, email_like FROM agent_registry;

# should show cosmos and gemini!
```

## production deployment

for production, use managed postgres:

### google cloud sql

```bash
# connection string format
DATABASE_URL="postgresql+asyncpg://user:pass@/dbname?host=/cloudsql/PROJECT:REGION:INSTANCE"
```

### aws rds

```bash
DATABASE_URL="postgresql+asyncpg://admin:pass@your-rds.amazonaws.com:5432/agentdb"
```

### supabase (postgres as a service)

1. create project at supabase.com
2. get connection string from settings
3. use "connection pooler" url for production

```bash
DATABASE_URL="postgresql+asyncpg://postgres.xxx:pass@aws-0-us-west-1.pooler.supabase.com:6543/postgres"
```

## troubleshooting

### "no module named asyncpg"

```bash
pip install asyncpg
```

### "connection refused"

check postgres is running:

```bash
docker ps  # should show postgres container
# or
pg_isready
```

### "database does not exist"

create the database:

```bash
docker exec -it agent-registry-postgres psql -U postgres -c "CREATE DATABASE agentdb;"
```

### see sql queries (debugging)

in `synqed/agent_email/registry/db.py`, change:

```python
self.engine = create_async_engine(
    database_url,
    echo=True,  # <- set to True
    ...
)
```

## migration from in-memory to postgres

if you have existing agents registered in-memory and want to migrate:

1. export existing data:

```python
# before switching to postgres
from synqed.agent_email.registry.api import get_registry
import json

registry = get_registry()
agents = registry.list_all()

with open('agents_backup.json', 'w') as f:
    json.dump([a.model_dump() for a in agents], f)
```

2. switch to postgres (set DATABASE_URL)

3. import data:

```python
# after switching to postgres
import json
import asyncio
from synqed.agent_email.registry.api import get_registry
from synqed.agent_email.registry.models import AgentRegistryEntry

async def import_agents():
    with open('agents_backup.json') as f:
        data = json.load(f)
    
    registry = get_registry()
    await registry.init_db()
    
    for agent_data in data:
        entry = AgentRegistryEntry(**agent_data)
        await registry.register(entry)
    
    print(f"imported {len(data)} agents")

asyncio.run(import_agents())
```

---

**that's it!** you now have persistent agent registry storage with postgres. 🎉

