Production Database Queries
When the user asks about production data, use the Metabase MCP execute tool (mcp__metabase__execute) to run SQL queries against the production database through our Metabase instance.
Prerequisites
This skill requires the metabase MCP server configured at user scope in ~/.claude.json:
{
"mcpServers": {
"metabase": {
"command": "npx",
"args": ["-y", "@jerichosequitin/metabase-mcp"],
"env": {
"METABASE_URL": "https://analytics.reveni.io",
"METABASE_API_KEY": "<YOUR_METABASE_API_KEY>",
"METABASE_READ_ONLY_MODE": "true"
}
}
}
}
Read-only mode is mandatory — the tool refuses anything that isn't a SELECT. API keys are issued from your Metabase profile; permissions on the underlying DB are inherited from the Metabase user. Do NOT configure direct Postgres access — IT requires all prod DB access to go through Metabase.
Database IDs
The execute tool requires a database_id parameter. Known Metabase databases as of 2026-04-15:
database_id |
Name | Use for |
|---|---|---|
| 4 | reveni-transactional |
Default. All Django app tables (orders, accounts, deliveries, payments, billing, integrations, events, notifications). |
| 35 | reveni-csv-import |
CSV import staging data. Rarely needed. |
| 71 | reveni-sales-orders |
Sales analytics aggregations. |
Use database_id=4 unless the question is explicitly about CSV imports or sales analytics. If a query against id=4 fails with "table does not exist", verify with mcp__metabase__list model="databases" in case IDs changed.
Rules
- ALWAYS use
mcp__metabase__executefor production data queries. Load it first withToolSearchquery+metabaseif not immediately available. - NEVER use
make sh,make shell, Django shell, or Docker commands to query production data. The local DB has no production data. - All queries are read-only (enforced by
METABASE_READ_ONLY_MODE=true). - Default row limit is 100, max 500. For larger datasets use
mcp__metabase__export. - Never reintroduce a direct Postgres MCP — IT policy requires Metabase as the only path to prod.
Quick Reference
Django tables follow {app}_{model} naming. All models have id, uuid, created, modified fields.
Core Tables
| Model | Table | Key Fields | Notes |
|---|---|---|---|
| Order | orders_order |
number, name, external_id, status, store_id |
Search by number, name, external_id, or uuid |
| Return | orders_return |
order_id, status, type |
FK to order via order_id |
| ReturnLineItem | orders_returnlineitem |
ret_id, line_item_id, status, reason_id |
|
| LineItem | orders_lineitem |
order_id, external_id, product_id |
|
| Refund | orders_refund |
ret_id, status, amount |
OneToOne to Return |
| Shipment | deliveries_shipment |
order_id, status |
No direct store_id — join through orders_order |
| ShippingLabel | deliveries_shippinglabel |
shipment_id, status, tracking_number |
|
| ReturnLabel | deliveries_returnlabel |
status, tracking_number |
|
| Store | accounts_store |
merchant_id, name |
|
| Merchant | accounts_merchant |
name, status |
|
| CustomerProfile | accounts_customerprofile |
customer_id, store_id, email |
Per-store customer profile |
| Payment | payments_payment |
status, payment_method_id |
Polymorphic — see reference |
| Invoice | billing_invoice |
type, status |
Inherited / Polymorphic Models
These use multi-table inheritance — fields are split across parent and child tables:
| Model | Parent Table | Child Pointer | Key Parent Fields |
|---|---|---|---|
| StorePermission | auth_permission |
permission_ptr_id |
codename, name |
| StoreGroup | auth_group |
group_ptr_id |
name. Permissions in auth_group_permissions. |
| Payment | payments_payment |
polymorphic_ctype_id |
Filter by ContentType for specific gateway |
| DeliveryMethod | deliveries_deliverymethod |
polymorphic_ctype_id |
Also soft-deleted |
| Integration | integrations_integration |
polymorphic_ctype_id |
Soft-Deleted Tables (CRITICAL)
These models use django-safedelete. Records are NOT truly deleted — they have a deleted timestamp. Always filter WHERE deleted IS NULL to get active records:
accounts_returnreasonaccounts_returnsubreasonaccounts_storelocationdeliveries_deliverymethoddeliveries_deliverytimerange- Eligibility rules:
orders_eligibilityrule,orders_storeitemrule,orders_storeproductrule,orders_storeproductvariantrule
Disabled Records
Models with AbstractDisabled mixin have a disabled DateTimeField. Active records have disabled IS NULL.
Money Fields
Uses django-money. Each money field creates two columns: <field> (amount) and <field>_currency (3-letter code).
Query Tips
- UUIDs are native type:
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - If a query fails with "column does not exist", check
information_schema.columnsfirst - Use
information_schema.tableswithLIKEto discover table names - If Metabase returns fewer rows than expected, you may have hit the 100-row default limit — raise via the tool's
limitparameter (up to 500) or switch tomcp__metabase__export
Additional Resources
- For complete table catalog and relationships, see schema.md
- For status values and business logic groupings, see statuses.md
- For common SQL query templates, see queries.md