Skip to main content

Quickstart

This guide walks you through setting up Permission Mongo and making your first API calls in under 5 minutes.

Prerequisites

Before you begin, ensure you have:
  • MongoDB 6.0+ running (localhost:27017)
  • Redis 7.0+ running (localhost:6379)
  • Go 1.21+ installed (for building from source)
Or use Docker Compose to start all dependencies (recommended).

Installation

Configuration

Permission Mongo uses YAML files for configuration. The example configuration in config/ includes:
1

Create server configuration

Create config/config.example.yaml with your MongoDB and Redis connection details:
config/config.example.yaml
server:
  host: "0.0.0.0"
  port: 8080

mongodb:
  uri: "mongodb://localhost:27017"
  database: "permission_mongo"

redis:
  addr: "localhost:6379"
  password: ""
  db: 0

auth:
  jwt_secret: "your-secret-key-change-in-production"
  token_expiry: "24h"

audit:
  enabled: true
  collection: "audit_logs"
Change the jwt_secret in production. This key is used to validate JWT tokens.
2

Define your schema

Create config/schema.yml to define collections and fields:
config/schema.yml
version: "1.0"

settings:
  default_tenant_field: company_id
  auto_timestamps: true
  id_type: objectId

collections:
  orders:
    fields:
      _id:
        type: objectId
        auto: true
      
      company_id:
        type: string
        required: true
        immutable: true
      
      customer_name:
        type: string
        required: true
        min_length: 1
        max_length: 200
      
      status:
        type: string
        enum: [draft, pending, shipped, delivered]
        default: draft
      
      total:
        type: number
        required: true
        min: 0
      
      created_at:
        type: date
        auto: true
        immutable: true
      
      updated_at:
        type: date
        auto_update: true
    
    indexes:
      - fields: [company_id, status]
      - fields: [company_id, created_at]
        order: [1, -1]
    
    access:
      tenant_field: company_id
This example is based on examples/config/schema.yml:220-361.
3

Define access policies

Create config/policy.yml to control who can access what:
config/policy.yml
version: "1.0"

roles:
  admin:
    description: "Full access to all resources"
  
  user:
    description: "Standard user with limited access"

policies:
  orders:
    admin:
      actions: [create, read, update, delete]
      when: doc.company_id == user.tenant_id
    
    user:
      actions: [create, read, update]
      when: doc.company_id == user.tenant_id
      fields:
        deny_write: [status]  # Users can't change status

defaults:
  deny_all: true
  audit_log: true
Based on examples/config/policy.yml:132-151.

Verify installation

Check that the server is running:
# Health check
curl http://localhost:8080/health

# Response:
{"status":"healthy"}

# Readiness check
curl http://localhost:8080/ready

# Response:
{"status":"ready","mongodb":"connected","redis":"connected"}
These endpoints are defined in pkg/api/api.go.

Make your first API call

For testing, you can enable dev mode by setting PM_DEV_MODE=true to bypass JWT authentication (see cmd/server/main.go:166-173). In production, always use proper JWT authentication.
1

Create a document

curl -X POST http://localhost:8080/orders \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "company_id": "acme-corp",
    "customer_name": "John Doe",
    "total": 150.00,
    "status": "draft"
  }'
Response:
{
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "company_id": "acme-corp",
    "customer_name": "John Doe",
    "total": 150.00,
    "status": "draft",
    "created_at": "2026-03-04T12:00:00Z",
    "updated_at": "2026-03-04T12:00:00Z"
  }
}
The create handler validates the document against the schema before inserting (see pkg/api/handlers_crud.go:64-100).
2

Read a document

curl http://localhost:8080/orders/507f1f77bcf86cd799439011 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response:
{
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "company_id": "acme-corp",
    "customer_name": "John Doe",
    "total": 150.00,
    "status": "draft",
    "created_at": "2026-03-04T12:00:00Z",
    "updated_at": "2026-03-04T12:00:00Z"
  }
}
3

List documents with filters

curl "http://localhost:8080/orders?status=draft&_limit=10&_sort=-created_at" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response:
{
  "data": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "company_id": "acme-corp",
      "customer_name": "John Doe",
      "total": 150.00,
      "status": "draft",
      "created_at": "2026-03-04T12:00:00Z"
    }
  ],
  "pagination": {
    "cursor": "eyJfaWQiOiI1MDdmMWY3N2JjZjg2Y2Q3OTk0MzkwMTEifQ==",
    "has_more": false,
    "total": 1
  }
}
Query parameters:
  • status=draft - Filter by field value
  • _limit=10 - Limit results (default: 100)
  • _sort=-created_at - Sort descending by created_at
4

Update a document

curl -X PUT http://localhost:8080/orders/507f1f77bcf86cd799439011 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "status": "pending",
    "total": 175.00
  }'
Response:
{
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "company_id": "acme-corp",
    "customer_name": "John Doe",
    "total": 175.00,
    "status": "pending",
    "created_at": "2026-03-04T12:00:00Z",
    "updated_at": "2026-03-04T12:05:00Z"
  }
}
Note that updated_at is automatically updated due to auto_update: true in the schema.
5

Delete a document

curl -X DELETE http://localhost:8080/orders/507f1f77bcf86cd799439011 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response:
{
  "success": true
}

Batch operations

Permission Mongo supports batch operations for efficiency:
# Batch create
curl -X POST http://localhost:8080/orders/batch \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "documents": [
      {
        "company_id": "acme-corp",
        "customer_name": "Alice",
        "total": 100
      },
      {
        "company_id": "acme-corp",
        "customer_name": "Bob",
        "total": 200
      }
    ]
  }'
Response:
{
  "data": [
    {"_id": "...", "customer_name": "Alice", ...},
    {"_id": "...", "customer_name": "Bob", ...}
  ],
  "count": 2
}
Batch handlers are implemented in pkg/api/handlers_batch.go.

Aggregation queries

Run MongoDB aggregation pipelines with automatic RBAC filtering:
curl -X POST http://localhost:8080/orders/aggregate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "pipeline": [
      {
        "$group": {
          "_id": "$status",
          "count": {"$sum": 1},
          "total_amount": {"$sum": "$total"}
        }
      },
      {
        "$sort": {"count": -1}
      }
    ]
  }'
Response:
{
  "data": [
    {"_id": "pending", "count": 15, "total_amount": 2500},
    {"_id": "draft", "count": 8, "total_amount": 1200},
    {"_id": "shipped", "count": 5, "total_amount": 900}
  ]
}
Permission Mongo automatically injects RBAC filters into the pipeline before the first $group stage.

Monitoring

Check Prometheus metrics:
curl http://localhost:8080/metrics
Metrics include:
  • permission_mongo_http_requests_total - Request counts by method/path/status
  • permission_mongo_http_request_duration_seconds - Request latency histograms
  • permission_mongo_mongo_operations_total - MongoDB operation counts
  • permission_mongo_rbac_evaluations_total - RBAC allowed/denied counts
See the full metrics documentation in monitoring/README.md.

Next steps

Installation

Explore all installation options including production deployment

Schema Configuration

Learn about all field types, constraints, and computed fields

Policy Configuration

Master RBAC with role inheritance and field-level permissions

API Reference

Complete REST API documentation with all endpoints

Troubleshooting

Ensure MongoDB is running on the configured URI:
# Check MongoDB status
mongosh mongodb://localhost:27017

# Or with Docker
docker ps | grep mongo
Update the mongodb.uri in config/config.example.yaml if using a different address.
Verify Redis is running:
# Test Redis connection
redis-cli ping
# Should return: PONG

# Or with Docker
docker ps | grep redis
Update the redis.addr in config/config.example.yaml if needed.
You need a valid JWT token for authentication. For development:
  1. Enable dev mode: export PM_DEV_MODE=true
  2. Restart the server
  3. Requests will bypass authentication (see warning in cmd/server/main.go:172)
For production, integrate with your JWT issuer and pass tokens in the Authorization: Bearer TOKEN header.
Check that your request body matches the schema definition:
  • All required: true fields must be present
  • Field types must match (string, number, boolean, etc.)
  • Values must satisfy constraints (min, max, enum, pattern)
The error response will indicate which field failed validation.

Build docs developers (and LLMs) love