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
The fastest way to get started is with Docker Compose, which starts Permission Mongo, MongoDB, and Redis: # Clone the repository
git clone https://github.com/KTS-o7/permission-mongo.git
cd permission-mongo
# Start all services
docker-compose -f docker/docker-compose.yaml up -d
# Check status
docker-compose -f docker/docker-compose.yaml ps
This starts:
Permission Mongo server on port 8080
MongoDB on port 27017
Redis on port 6379
The server reads configuration from the config/ directory mounted into the container.
Download the pre-built binary for your platform: # Linux
curl -LO https://github.com/KTS-o7/permission-mongo/releases/latest/download/pm-server-linux-amd64
chmod +x pm-server-linux-amd64
mv pm-server-linux-amd64 /usr/local/bin/pm-server
# macOS
curl -LO https://github.com/KTS-o7/permission-mongo/releases/latest/download/pm-server-darwin-amd64
chmod +x pm-server-darwin-amd64
mv pm-server-darwin-amd64 /usr/local/bin/pm-server
Ensure MongoDB and Redis are running, then start the server: pm-server --config ./config
Build from source if you want the latest development version: # Clone repository
git clone https://github.com/KTS-o7/permission-mongo.git
cd permission-mongo
# Install dependencies
go mod download
# Build server
make build
# Run server
./bin/pm-server --config ./config
The build command creates bin/pm-server executable (see cmd/server/main.go:10).
Configuration
Permission Mongo uses YAML files for configuration. The example configuration in config/ includes:
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.
Define your schema
Create config/schema.yml to define collections and fields: 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.
Define access policies
Create config/policy.yml to control who can access what: 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.
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).
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"
}
}
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
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.
Delete a document
curl -X DELETE http://localhost:8080/orders/507f1f77bcf86cd799439011 \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Response:
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
Connection refused to MongoDB
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:
Enable dev mode: export PM_DEV_MODE=true
Restart the server
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.