A single-tenant database observability platform that ingests, parses, and analyzes SQL queries.
Design direction: this project is evolving into an OpenLineage-native observability backend for data pipelines AND warehouses ("Jaeger for OpenLineage" + first-class query workload analytics). See
docs/data-observability/for the full design, phased task breakdown, and codebase audit.
- User Authentication: Clerk-based authentication for human users
- Database Registration: Register and manage database connections from the UI
- Agent Integration: Generate per-database agent tokens for secure query ingestion
- Query Ingestion: REST API endpoint for agents to send batches of query logs
- SQL Parsing: Parse SQL queries using SQLGlot to extract tables, columns, and operations
- Query Analysis: View queries with detailed parsing results and metadata
- FastAPI: REST API framework
- SQLAlchemy: ORM for PostgreSQL
- Alembic: Database migrations
- SQLGlot: SQL parsing engine
- Clerk: JWT authentication
- React 18: UI framework
- Vite: Build tool
- TailwindCSS: Styling
- Clerk React: Authentication
- React Router: Client-side routing
- Python 3.12+
- Node.js 18+
- PostgreSQL 14+
- Clerk account (for authentication)
git clone <repository-url>
cd baawm-appCreate a PostgreSQL database:
createdb baawm_dbOr using SQL:
CREATE DATABASE baawm_db;cd backend
pip install -r requirements.txtCreate a .env file in the backend directory:
cp .env.example .envEdit .env with your settings:
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/baawm_db
# Clerk Authentication
CLERK_JWKS_URL=https://your-clerk-domain.clerk.accounts.dev/.well-known/jwks.json
CLERK_ISSUER=https://your-clerk-domain.clerk.accounts.dev
# API
API_PREFIX=/api
DEBUG=TrueTo get your Clerk configuration:
- Sign up at clerk.com
- Create a new application
- Copy the JWKS URL and Issuer from the JWT Template settings
cd backend
alembic upgrade headcd backend
uvicorn app.main:app --reload --port 8000The API will be available at http://localhost:8000
cd frontend
npm installCreate a .env file in the frontend directory:
cp .env.example .envEdit .env with your Clerk publishable key:
VITE_CLERK_PUBLISHABLE_KEY=pk_test_your_clerk_publishable_key_here
VITE_API_URL=http://localhost:8000Get your Clerk publishable key from your Clerk dashboard.
cd frontend
npm run devThe frontend will be available at http://localhost:5173
Navigate to http://localhost:5173 and sign up using Clerk authentication.
- Click "Add Database" on the Databases page
- Enter a name, description, and select the engine type
- Save the agent token shown (it will only be displayed once)
Use the agent token to configure your data collection agent. Example:
export OBS_PLATFORM_URL="http://localhost:8000"
export OBS_DATABASE_ID="<your-database-id>"
export OBS_AGENT_TOKEN="<your-agent-token>"
curl -X POST "$OBS_PLATFORM_URL/api/ingest/batch" \
-H "Content-Type: application/json" \
-H "X-Agent-Token: $OBS_AGENT_TOKEN" \
-d '{
"queries": [
{
"external_id": "test:1",
"text": "SELECT id, email FROM users WHERE active = true",
"db_user": "app_user",
"app_name": "my-app",
"started_at": "2025-01-15T10:15:30.123Z",
"duration_ms": 42,
"rows": 100,
"cpu_time_ms": 30,
"io_read_bytes": 8192,
"io_write_bytes": 0
}
]
}'After ingesting queries, trigger parsing:
curl -X POST "http://localhost:8000/api/maintenance/parse-new-queries" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-clerk-jwt-token>" \
-d '{
"limit": 500
}'Or use the UI to trigger parsing manually (future feature).
Navigate to the Queries page to view ingested queries with their parsing results.
Once the backend is running, visit http://localhost:8000/docs for interactive API documentation (Swagger UI).
GET /health- Health check (public)GET /api/me- Get current userGET /api/databases- List databasesPOST /api/databases- Create databaseGET /api/databases/{id}- Get database detailsPOST /api/databases/{id}/rotate-agent-token- Rotate agent tokenPOST /api/ingest/batch- Ingest query batch (agent token auth)GET /api/queries- List queriesGET /api/queries/{id}- Get query detailPOST /api/maintenance/parse-new-queries- Parse unparsed queries
baawm-app/
├── backend/
│ ├── alembic/ # Database migrations
│ ├── app/
│ │ ├── api/
│ │ │ ├── routes/ # API route handlers
│ │ │ └── schemas/ # Pydantic schemas
│ │ ├── core/ # Core configuration
│ │ ├── models/ # SQLAlchemy models
│ │ └── services/ # Business logic (parsing, etc.)
│ ├── requirements.txt # Python dependencies
│ └── alembic.ini # Alembic configuration
├── frontend/
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ ├── services/ # API client
│ │ ├── types/ # TypeScript types
│ │ ├── App.tsx # Main app component
│ │ └── main.tsx # Entry point
│ ├── package.json # Node dependencies
│ └── vite.config.ts # Vite configuration
└── README.md
- users: User accounts (synced with Clerk)
- databases: Registered database connections
- raw_queries: Ingested query logs
- parsed_queries: Query parsing results
- query_tables: Tables referenced in queries
- query_columns: Columns referenced in queries
Backend tests (when implemented):
cd backend
pytestFrontend tests (when implemented):
cd frontend
npm testBackend:
cd backend
# Deploy using your preferred method (Docker, systemd, etc.)Frontend:
cd frontend
npm run build
# Serve the dist/ directory- Background job processing for parsing
- Advanced query analytics and insights
- Query performance tracking over time
- Data lineage visualization
- Multi-database comparison
- Alerts and notifications
- Query optimization recommendations
MIT
For issues and questions, please open an issue on GitHub.