Skip to main content

Architecture

Permission Mongo is designed as a high-performance middleware layer between your application and MongoDB, providing REST API, RBAC, versioning, and audit logging.

System overview

┌─────────────────────────────────────────────────────────────────────┐
│                           Clients                                    │
│          (Web App, Mobile App, FastAPI, External Services)           │
└───────────────────────────────┬─────────────────────────────────────┘
                                │ HTTPS + JWT

┌─────────────────────────────────────────────────────────────────────┐
│                    Permission Mongo Service                          │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │                      Configuration                             │ │
│  │  ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────────┐  │ │
│  │  │schema.yml │ │policy.yml │ │ hooks.yml │ │ server.yml    │  │ │
│  │  │           │ │           │ │           │ │               │  │ │
│  │  │• Types    │ │• Roles    │ │• pre/post │ │• Storage      │  │ │
│  │  │• Computed │ │• Policies │ │• Webhooks │ │• Audit config │  │ │
│  │  │• Indexes  │ │• Hierarchy│ │• Validate │ │• Cache TTLs   │  │ │
│  │  │• Version  │ │• Actions  │ │           │ │• Auth config  │  │ │
│  │  └───────────┘ └───────────┘ └───────────┘ └───────────────┘  │ │
│  └────────────────────────────────────────────────────────────────┘ │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │                      REST API Layer                            │ │
│  │                                                                │ │
│  │  Single Document         Batch Operations        Queries       │ │
│  │  ┌────────────────┐     ┌────────────────┐     ┌────────────┐ │ │
│  │  │POST /:coll     │     │POST /:coll/batch│    │GET /:coll  │ │ │
│  │  │GET  /:coll/:id │     │PUT  /:coll/batch│    │POST /:coll/│ │ │
│  │  │PUT  /:coll/:id │     │DEL  /:coll/batch│    │  aggregate │ │ │
│  │  │DEL  /:coll/:id │     └────────────────┘     │POST /:coll/│ │ │
│  │  └────────────────┘                            │  count     │ │ │
│  │                                                └────────────┘ │ │
│  │  Versioning                                                   │ │
│  │  ┌────────────────────────────────────────────────────────┐   │ │
│  │  │ GET  /:coll/:id/versions                               │   │ │
│  │  │ GET  /:coll/:id/versions/:v                            │   │ │
│  │  │ GET  /:coll/:id/diff/:v1/:v2                           │   │ │
│  │  │ POST /:coll/:id/restore/:v                             │   │ │
│  │  └────────────────────────────────────────────────────────┘   │ │
│  └────────────────────────────────────────────────────────────────┘ │
│                                                                      │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │                        Core Engine                             │ │
│  │                                                                │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐ │ │
│  │  │ JWT Auth     │  │ RBAC Engine  │  │ Schema Validator     │ │ │
│  │  │ • Validate   │  │ • Policies   │  │ • Type checking      │ │ │
│  │  │ • Extract    │  │ • Hierarchy  │  │ • Constraints        │ │ │
│  │  │   user ctx   │  │ • $subord.   │  │ • References         │ │ │
│  │  └──────────────┘  └──────────────┘  └──────────────────────┘ │ │
│  │                                                                │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐ │ │
│  │  │ Query Builder│  │ Computed     │  │ Hook Executor        │ │ │
│  │  │ • Filters    │  │ Fields       │  │ • Sync/Async         │ │ │
│  │  │ • Projection │  │ • Virtual    │  │ • HTTP calls         │ │ │
│  │  │ • Pagination │  │ • Stored     │  │ • Conditions         │ │ │
│  │  │ • Aggregation│  │ • Recompute  │  │                      │ │ │
│  │  └──────────────┘  └──────────────┘  └──────────────────────┘ │ │
│  │                                                                │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐ │ │
│  │  │ Version      │  │ Audit Logger │  │ Field Mask           │ │ │
│  │  │ Manager      │  │ • MongoDB    │  │ • Email              │ │ │
│  │  │ • Snapshot   │  │ • Webhook    │  │ • Phone              │ │ │
│  │  │ • Diff       │  │ • Stdout     │  │ • Partial            │ │ │
│  │  │ • Restore    │  │              │  │                      │ │ │
│  │  └──────────────┘  └──────────────┘  └──────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────┬──────────────────────────────────┘

                   ┌───────────────┴───────────────┐
                   ▼                               ▼
          ┌───────────────┐               ┌───────────────┐
          │    Redis      │               │   MongoDB     │
          │               │               │               │
          │ • Policies    │               │ • App Data    │
          │ • Hierarchy   │               │ • _pm_versions│
          │ • Rate limits │               │ • _pm_audit   │
          └───────────────┘               │ • _pm_hier    │
                                          └───────────────┘
From SPECIFICATION.md:88-170.

Core components

HTTP server

Permission Mongo uses fasthttp for high-performance HTTP handling. Key characteristics:
  • 10x faster than net/http for high-throughput scenarios
  • Optimized for 256K concurrent connections
  • Zero-allocation routing with atomic operations
Implementation: pkg/api/server.go
pkg/api/server.go
// Server initialization from cmd/server/main.go:176-182
server := api.NewServer(cfg.Server, serverOpts...)
server.RegisterHandlers(&api.Handlers{
    Store: mongoStore,
    RBAC:  rbacEngine,
})

MongoDB store

The MongoDB store layer (pkg/store/mongo.go) provides:
  • Connection pooling (default: 100 connections)
  • CRUD operations with RBAC filter injection
  • Aggregation pipeline execution
  • Index management
Connection: See cmd/server/main.go:62-77
mongoStore := store.NewMongoStore(mongoURI, mongoDatabase)
if err := mongoStore.Connect(ctx); err != nil {
    return fmt.Errorf("failed to connect to MongoDB: %w", err)
}

Redis cache

Redis is used for caching frequently accessed data: Cache keys:
  • pm:policy:{tenant}:compiled - Compiled RBAC policies (TTL: 60s)
  • pm:hier:{tenant}:{user}:subs - User subordinates (TTL: 300s)
  • pm:schema:compiled - Schema definitions (TTL: 60s)
Connection: See cmd/server/main.go:80-91
redisCache := cache.NewRedisCache(redisURL, cfg.Server.Redis.Password, cfg.Server.Redis.DB)
if err := redisCache.Connect(ctx); err != nil {
    return fmt.Errorf("failed to connect to Redis: %w", err)
}
From SPECIFICATION.md:1436-1451.

Schema validator

Validates documents against schema definitions before write operations. Features:
  • Type checking (string, number, boolean, date, objectId, array, object)
  • Constraints (required, min/max, pattern, enum)
  • Nested object and array validation
  • Computed field evaluation
Implementation: pkg/schema/validator.go Initialization: cmd/server/main.go:94-95
schemaValidator := schema.NewValidator(cfg.Schema)
Field types from examples/config/schema.yml:18-415.

RBAC engine

The Role-Based Access Control engine enforces permissions at multiple levels: Permission checks:
  1. Collection-level: Can user perform action on collection?
  2. Document-level: Does document match when clause?
  3. Field-level: Which fields can user read/write?
Expression evaluation:
policy.yml
when: |
  doc.company_id == user.tenant_id &&
  (doc.created_by == user.id || doc.created_by in user.$subordinates)
The expression is compiled to a MongoDB query filter and cached. Special variables:
  • user.id - Current user ID
  • user.tenant_id - User’s tenant
  • user.roles - User’s roles array
  • user.$subordinates - All subordinate user IDs (from hierarchy)
Implementation: pkg/rbac/engine.go Initialization: cmd/server/main.go:104-105
rbacEngine := rbac.NewEngine(cfg.Policy)
From examples/config/policy.yml:1-178.

Hierarchy resolver

Resolves organizational hierarchy for manager-subordinate relationships. How it works:
  1. Hierarchy defined in schema: users.manager_id references users._id
  2. Transitive closure stored in _pm_hierarchy collection
  3. Cached in Redis for fast lookups
Data structure:
// _pm_hierarchy collection
{
  tenant_id: "acme-corp",
  user_id: "dave",
  ancestor_id: "alice",  // Dave reports to Alice (directly or indirectly)
  depth: 2                // 2 levels up
}
Implementation: pkg/hierarchy/resolver.go Initialization: cmd/server/main.go:98-101
hierTTL := time.Duration(cfg.Server.Cache.HierarchyTTLSeconds) * time.Second
hierResolver := hierarchy.NewResolver(mongoStore, redisCache, hierTTL)
From SPECIFICATION.md:771-808.

Version manager

Tracks document change history in the _pm_versions collection. Version storage:
// _pm_versions collection
{
  _id: ObjectId("..."),
  collection: "orders",
  doc_id: "order-123",
  version: 3,
  mode: "full",           // "full" snapshot or "diff" changes
  data: { /* complete document snapshot */ },
  tenant_id: "acme-corp",
  updated_by: "user-alice",
  updated_at: ISODate("2026-03-04T12:00:00Z")
}
API endpoints:
  • GET /{collection}/{id}/versions - List versions
  • GET /{collection}/{id}/versions/{v} - Get specific version
  • GET /{collection}/{id}/diff/{v1}/{v2} - Compare versions
  • POST /{collection}/{id}/restore/{v} - Restore to version
Implementation: pkg/version/manager.go, pkg/api/handlers_version.go Initialization: cmd/server/main.go:108-109
versionMgr := version.NewManager(mongoStore)
From SPECIFICATION.md:810-1017.

Audit logger

Records all operations for compliance and debugging. Audit log entry:
// _pm_audit collection
{
  _id: ObjectId("..."),
  tenant_id: "acme-corp",
  user_id: "user-alice",
  action: "update",        // create, read, update, delete
  collection: "orders",
  doc_id: "order-123",
  changes: [
    { field: "status", from: "pending", to: "shipped" }
  ],
  timestamp: ISODate("2026-03-04T14:00:00Z"),
  success: true
}
Storage options:
  • MongoDB collection with TTL
  • Webhook (batch HTTP POST)
  • Stdout (for development)
Implementation: pkg/audit/logger.go Initialization: cmd/server/main.go:112-113
auditLogger := audit.NewLogger(&cfg.Server.Audit, mongoStore)
From SPECIFICATION.md:1072-1243.

Hooks manager

Executes pre/post operation hooks for validation, transformation, and notifications. Hook types:
  • pre_create, post_create
  • pre_update, post_update
  • pre_delete, post_delete
Built-in actions:
  • set_field - Set field to value or expression
  • validate - Check condition or fail
  • validate_ref - Verify reference exists
  • http - Call external webhook
Implementation: pkg/hooks/executor.go Initialization: cmd/server/main.go:116-120
var hooksMgr *hooks.Manager
if cfg.Hooks != nil {
    hooksMgr = hooks.NewManager()
}

Request flow

Typical request lifecycle for an update operation:
┌─────────────────────────────────────────────────────────────────────┐
│  1. Client sends request                                            │
│     PUT /orders/order-123 { "status": "shipped" }                   │
│     Authorization: Bearer <jwt>                                      │
│                               │                                      │
│                               ▼                                      │
│  2. JWT Authentication                                              │
│     • Validate signature                                            │
│     • Extract: user_id, tenant_id, roles                            │
│     • Build AuthContext                                             │
│                               │                                      │
│                               ▼                                      │
│  3. RBAC Check                                                      │
│     • Load policy (from cache)                                      │
│     • Check: can user.roles do "update" on "orders"?                │
│     • If denied → 403 Forbidden                                     │
│                               │                                      │
│                               ▼                                      │
│  4. Load Existing Document                                          │
│     • Fetch current state for versioning                            │
│     • Check document-level permission (when clause)                 │
│                               │                                      │
│                               ▼                                      │
│  5. Schema Validation                                               │
│     • Type checking                                                 │
│     • Constraints (min, max, enum)                                  │
│     • Immutable field check                                         │
│                               │                                      │
│                               ▼                                      │
│  6. Pre-Update Hooks                                                │
│     • Validation rules                                              │
│     • Field transformations                                         │
│     • HTTP calls (sync)                                             │
│                               │                                      │
│                               ▼                                      │
│  7. Save Version Snapshot                                           │
│     • Store previous state in _pm_versions                          │
│     • Increment _version field                                      │
│                               │                                      │
│                               ▼                                      │
│  8. Compute Stored Fields                                           │
│     • Recalculate affected computed fields                          │
│     • Update updated_at timestamp                                   │
│                               │                                      │
│                               ▼                                      │
│  9. MongoDB Update                                                  │
│     • Execute update                                                │
│                               │                                      │
│                               ▼                                      │
│  10. Post-Update Hooks (async)                                      │
│      • Webhook notifications                                        │
│                               │                                      │
│                               ▼                                      │
│  11. Audit Log                                                      │
│      • Record: user, action, collection, doc_id, changes            │
│      • Ship to configured destinations                              │
│                               │                                      │
│                               ▼                                      │
│  12. Compute Virtual Fields                                         │
│      • Calculate non-stored computed fields                         │
│                               │                                      │
│                               ▼                                      │
│  13. Apply Field Projection                                         │
│      • Remove denied fields                                         │
│      • Apply masks                                                  │
│                               │                                      │
│                               ▼                                      │
│  14. Return Response                                                │
│      { "_id": "order-123", "status": "shipped", "_version": 4 }     │
└─────────────────────────────────────────────────────────────────────┘
From SPECIFICATION.md:256-333. See handler implementation in pkg/api/handlers_crud.go.

Data storage

MongoDB collections

MongoDB Database

├── orders                      ← Your application data
├── customers                   ← Your application data
├── products                    ← Your application data
├── users                       ← Your application data

├── _pm_versions                ← All version history (single collection)
│   Indexes:
│   - { tenant_id: 1, collection: 1, doc_id: 1, version: -1 }
│   - { updated_at: 1 } with TTL (optional)

├── _pm_audit                   ← Audit logs (optional)
│   Indexes:
│   - { tenant_id: 1, timestamp: -1 }
│   - { tenant_id: 1, user_id: 1, timestamp: -1 }
│   - { timestamp: 1 } with TTL

├── _pm_hierarchy               ← Org chart closure table
│   Indexes:
│   - { tenant_id: 1, ancestor_id: 1 }
│   - { tenant_id: 1, user_id: 1 }

└── _pm_policies                ← Compiled policies cache
    Indexes:
    - { tenant_id: 1 } unique
From SPECIFICATION.md:1245-1277.

Redis keys

Redis

├── pm:policy:{tenant_id}:compiled     ← Compiled policy (TTL: 60s)
├── pm:policy:{tenant_id}:version      ← Policy version for invalidation

├── pm:hier:{tenant_id}:{user_id}:subs    ← Subordinates list (TTL: 300s)
├── pm:hier:{tenant_id}:{user_id}:direct  ← Direct reports (TTL: 300s)
├── pm:hier:{tenant_id}:{user_id}:anc     ← Ancestors (TTL: 300s)

└── pm:schema:compiled                     ← Schema cache (TTL: 60s)
From SPECIFICATION.md:1279-1291.

Project structure

permission-mongo/
├── cmd/
│   ├── server/main.go              # Main server entry point
│   └── pmctl/main.go               # CLI tool
├── pkg/
│   ├── api/
│   │   ├── server.go               # fasthttp server
│   │   ├── handlers_crud.go        # CRUD handlers
│   │   ├── handlers_batch.go       # Batch handlers
│   │   ├── handlers_query.go       # List/aggregate handlers
│   │   ├── handlers_version.go     # Version history handlers
│   │   └── middleware.go           # Auth, logging, recovery
│   ├── auth/
│   │   ├── jwt.go                  # JWT validation
│   │   └── context.go              # User context extraction
│   ├── config/
│   │   ├── schema.go               # Schema parsing
│   │   ├── policy.go               # Policy parsing
│   │   └── loader.go               # Config file loader
│   ├── schema/
│   │   ├── validator.go            # Document validation
│   │   └── computed.go             # Computed field evaluation
│   ├── rbac/
│   │   ├── engine.go               # Permission engine
│   │   ├── evaluator.go            # Condition evaluation
│   │   ├── compiler.go             # Expression → MongoDB
│   │   └── fields.go               # Field projection/masking
│   ├── hierarchy/
│   │   ├── resolver.go             # Subordinate lookups
│   │   └── closure.go              # Transitive closure
│   ├── version/
│   │   ├── manager.go              # Version management
│   │   ├── diff.go                 # Diff calculation
│   │   └── restore.go              # Restore logic
│   ├── audit/
│   │   ├── logger.go               # Audit log interface
│   │   └── mongodb.go              # MongoDB storage
│   ├── hooks/
│   │   ├── executor.go             # Hook execution
│   │   └── http.go                 # HTTP call handling
│   ├── store/
│   │   └── mongo.go                # MongoDB operations
│   └── cache/
│       └── redis.go                # Redis client
├── config/
│   ├── schema.yml                  # Example schema
│   ├── policy.yml                  # Example policy
│   └── config.example.yaml         # Server configuration
├── docker/
│   ├── Dockerfile
│   └── docker-compose.yaml
└── Makefile
From README.md:181-205 and SPECIFICATION.md:172-254.

Performance characteristics

Throughput targets

OperationTarget LatencyThroughput
GET (cached)Less than 10ms50K+ QPS
POST (create)Less than 25ms25K+ QPS
PUT (update with versioning)Less than 30ms20K+ QPS
Batch (100 docs)Less than 100ms5K+ QPS

Optimizations

Lock-free router (pkg/api/router.go):
  • Atomic operations for route registration
  • Zero allocations in hot path
Connection pooling:
  • MongoDB: 100 connections (configurable)
  • Redis: 500 connections (configurable)
Async audit logging:
  • Batched inserts to MongoDB
  • No latency impact on user requests
AST caching:
  • RBAC expressions compiled once and cached
  • Reduces CPU usage by 80% vs. parsing on every request
From README.md:207-214.

Scalability

Permission Mongo scales to:
  • 50-100M documents per collection (single instance)
  • 500M total documents across all collections
  • 1M users in hierarchy
  • 25K QPS sustained on standard hardware
For larger scale, use MongoDB sharding and horizontal scaling of Permission Mongo instances (stateless). From SPECIFICATION.md:1515-1531.

Security

Authentication

JWT-based authentication with configurable algorithms:
  • RS256 (asymmetric, recommended for production)
  • HS256 (symmetric, simpler setup)
JWT claims:
{
  "sub": "user-456",           // User ID
  "tenant_id": "acme-corp",    // Tenant ID
  "roles": ["manager"],        // User roles
  "iat": 1707220800,
  "exp": 1707224400
}

Authorization

Multi-level RBAC enforcement:
  1. Collection-level - Can user access this collection?
  2. Action-level - Can user perform this action (create/read/update/delete)?
  3. Document-level - Does document match when clause?
  4. Field-level - Which fields are allowed/denied/masked?

Data protection

Field masking:
fields:
  mask:
    email: email        # j***@example.com
    phone: phone        # +1-***-***-1234
    ssn: partial        # ***-**-1234
Immutable fields:
fields:
  created_at:
    type: date
    immutable: true     # Cannot be changed after creation

Next steps

Configuration

Learn how to configure schema, policies, and hooks

API Reference

Complete REST API documentation

RBAC Guide

Master role-based access control

Performance Tuning

Optimize for high throughput

Build docs developers (and LLMs) love