A self-hostable dashboard for inspecting and understanding PostgreSQL Row-Level Security (RLS) policies. Connect to any PostgreSQL database, see which tables have RLS enabled, view policy definitions, and optionally get AI-powered explanations of what each policy does.
- RLS policy viewer -- Browse all tables in a database, see which have RLS enabled/forced, and expand to view individual policy definitions (USING and WITH CHECK expressions).
- Policy & function comments -- Displays PostgreSQL
COMMENT ON POLICYandCOMMENT ON FUNCTIONannotations prominently alongside each definition. - Function resolution -- Automatically discovers functions referenced by RLS policies via
pg_depend, shows their full definitions, and flags security concerns (e.g.,SECURITY DEFINERwithout a pinnedsearch_path). - AI explanations -- Optionally configure an Anthropic or OpenAI API key to get plain-language explanations of policies and their referenced functions. Rendered as formatted markdown.
- Connection management -- Store multiple PostgreSQL connections with encrypted credentials (Fernet). Test connections before saving.
- Schema browser -- Switch between schemas to view tables and policies across your database.
- TLS by default -- Self-signed certificates are generated automatically. Bring your own certs or disable TLS for plain HTTP.
- Single-container deployment -- Ships as one Docker image running Caddy, the API, and the frontend.
curl -sSL https://raw.githubusercontent.com/jasondcamp/rlsee/main/bin/install.sh | bashThis installs RLSee to /opt/rlsee, generates secrets, pulls the Docker image, and starts the stack with self-signed TLS.
# Clone the repo
git clone https://github.com/jasondcamp/rlsee.git
cd rlsee
# Generate secrets
make keys
# Copy the output into a .env file
# Start with Docker Compose
cp .env.example .env
# Edit .env with your generated keys
docker compose up --buildThe app will be available at https://localhost:8765. On first visit you'll create an admin account, then add a PostgreSQL connection.
# Start both backend and frontend with hot-reload
make devThis runs docker-compose.dev.yml which starts:
- Backend (Flask) on port 8766 with auto-reload
- Frontend (Next.js) on port 8765 with hot module replacement
Backend:
cd backend
pip install -r requirements.txt
export SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
export FERNET_KEY=$(python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")
python run.pyFrontend:
cd frontend
npm install
NEXT_PUBLIC_API_URL=http://localhost:8766 npm run devAll configuration is via environment variables. See .env.example for the full list.
| Variable | Required | Description |
|---|---|---|
SECRET_KEY |
Yes | Flask session secret. Generate with python3 -c "import secrets; print(secrets.token_hex(32))" |
FERNET_KEY |
Yes | Encryption key for stored database credentials. Generate with python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
DATABASE_URL |
No | SQLite connection string for app data. Default: sqlite:///rlsee.db |
TLS_CERT |
No | TLS mode. internal (default) = self-signed, off = plain HTTP, or path to cert file |
TLS_KEY |
No | Path to TLS key file (when using custom certs) |
TOKENTALLY_API_KEY |
No | TokenTally API key for tracking LLM usage |
LLM provider settings (Anthropic/OpenAI API keys and model selection) are configured through the Settings page in the UI.
├── backend/ Flask API server
│ ├── app/
│ │ ├── models/ SQLAlchemy models (User, Connection, Setting)
│ │ ├── routes/ API endpoints (auth, connections, database, settings)
│ │ └── services/ Business logic (auth, crypto, database, LLM)
│ └── run.py Entry point
├── frontend/ Next.js 15 app
│ └── src/
│ ├── app/ Pages (login, dashboard, connections, database, settings)
│ ├── components/ UI components
│ ├── stores/ Zustand state management
│ └── lib/ API client
├── bin/install.sh One-line installer
├── Dockerfile Multi-stage production build
├── start.sh Container entrypoint (Caddy + Gunicorn + Node)
├── docker-compose.yml Production deployment
└── docker-compose.dev.yml Development with hot-reload
A single container runs three processes:
- Caddy (foreground) -- Reverse proxy with TLS termination on ports 8765 (frontend) and 8766 (API).
- Gunicorn -- Flask API server on
127.0.0.1:8000. - Node.js -- Next.js standalone server on
127.0.0.1:3000.
The browser auto-detects the API URL from the current hostname, so no build-time configuration is needed.
RLSee queries PostgreSQL system catalogs directly:
pg_policy+pg_get_expr()-- Extracts policy definitions (USING/WITH CHECK expressions) as human-readable SQL.obj_description()-- RetrievesCOMMENT ON POLICYandCOMMENT ON FUNCTIONannotations.pg_depend-- Resolves which functions are referenced by each policy, without relying on fragile text parsing of policy expressions.pg_proc+pg_get_functiondef()-- Retrieves full function source code for display and inclusion in LLM prompts.pg_class/pg_namespace-- Enumerates tables and schemas with RLS status.
- All traffic is encrypted with TLS by default (self-signed certificates generated on first start).
- Database credentials are encrypted at rest using Fernet symmetric encryption.
- Passwords are hashed with PBKDF2-SHA256 (via Werkzeug).
- The app connects to your PostgreSQL databases as a read-only observer -- it never modifies your data or schema.
- Functions flagged as
SECURITY DEFINERwithout a pinnedsearch_pathare highlighted as a potential security risk.
AGPL-3.0 -- see LICENSE.