# Permission Engine

A flexible and powerful permission management system for TypeScript applications. This engine provides comprehensive role-based access control (RBAC) with support for conditional permissions, role inheritance, and policy-based access control.

## Features

- 🔐 **Role-Based Access Control (RBAC)**: Define roles with specific permissions
- 🎯 **Conditional Permissions**: Add conditions to permissions for fine-grained control
- 🔗 **Role Inheritance**: Create role hierarchies with inherited permissions
- 📜 **Policy-Based Access Control**: Define complex policies with custom logic
- ⚡ **Performance**: Efficient permission checking with minimal overhead
- 🛡️ **Type-Safe**: Full TypeScript support with comprehensive type definitions
- 🧪 **Well-Tested**: Designed with testability in mind

## Installation

```bash
npm install
```

## Architecture

This package provides **two versions** to fit different needs:

### V1: PermissionEngine (In-Memory)

Simple, fast, in-memory storage. Great for getting started or small applications.

### V2: PermissionEngineV2 (Repository-Based)

Scalable, stateless, database-backed. **Recommended for production.**

See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed comparison.

## Quick Start (V1 - Simple)

```typescript
import { PermissionEngine, Role, User } from "./src";

// Create the engine
const engine = new PermissionEngine();

// Define a role
const editorRole: Role = {
  id: "editor",
  name: "Editor",
  permissions: [
    { resource: "post", action: "create" },
    { resource: "post", action: "read" },
    { resource: "post", action: "update" },
  ],
};

// Add role to engine
engine.roles.addRole(editorRole);

// Create a user with the role
const user: User = {
  id: "user-1",
  roles: ["editor"],
};

// Add user to engine
engine.addUser(user);

// Check permissions
const canUpdate = engine.checkPermission("user-1", "post", "update");
console.log(canUpdate.granted); // true

const canDelete = engine.checkPermission("user-1", "post", "delete");
console.log(canDelete.granted); // false
```

## Quick Start (V2 - Scalable/Production)

```typescript
import {
  PermissionEngineV2,
  InMemoryUserRepository, // Replace with your DB repository
  InMemoryRoleRepository,
  InMemoryPolicyRepository,
  User,
  Role,
} from "./src";

// Create repositories (implement these with your database)
const userRepo = new InMemoryUserRepository();
const roleRepo = new InMemoryRoleRepository();
const policyRepo = new InMemoryPolicyRepository();

// Create stateless engine
const engine = new PermissionEngineV2(userRepo, roleRepo, policyRepo);

// Set up a role in your database
const editorRole: Role = {
  id: "editor",
  name: "Editor",
  permissions: [
    { resource: "post", action: "create" },
    { resource: "post", action: "update" },
  ],
};
await roleRepo.saveRole(editorRole);

// User stored in your database
const user: User = {
  id: "user-1",
  roles: ["editor"],
};
await userRepo.saveUser(user);

// Check permissions (engine fetches from DB)
const result = await engine.checkPermission("user-1", "post", "update");
console.log(result.granted); // true

// 🎯 Engine is stateless - scales horizontally!
// 💾 All data in your database, not in memory
// ⚡ Add caching layer at repository level for performance
```

## Core Concepts

### Permissions

A permission defines access to a specific action on a resource:

```typescript
{
  resource: 'post',    // The resource being accessed
  action: 'update',    // The action being performed
  conditions: []       // Optional conditions
}
```

### Roles

Roles group permissions together and can be assigned to users:

```typescript
const adminRole: Role = {
  id: "admin",
  name: "Administrator",
  description: "Full system access",
  permissions: [
    { resource: "*", action: "*" }, // Wildcard for all resources and actions
  ],
};
```

### Users

Users are assigned roles and can have direct permissions:

```typescript
const user: User = {
  id: "user-1",
  roles: ["editor", "reviewer"],
  permissions: [
    // Optional direct permissions
    { resource: "settings", action: "read" },
  ],
  attributes: {
    // Optional attributes for condition evaluation
    department: "engineering",
  },
};
```

### Policies

Policies provide fine-grained access control with custom logic:

```typescript
const policy: Policy = {
  id: "business-hours-only",
  name: "Business Hours Policy",
  effect: PolicyEffect.DENY,
  resources: ["sensitive-data"],
  actions: ["read", "update"],
  conditions: [
    {
      evaluate: (context) => {
        const hour = new Date().getHours();
        return hour < 9 || hour > 17; // Outside business hours
      },
      description: "Deny access outside business hours",
    },
  ],
};

engine.policies.addPolicy(policy);
```

## Advanced Features

### Conditional Permissions

Add conditions to permissions for context-aware access control:

```typescript
const authorRole: Role = {
  id: "author",
  name: "Author",
  permissions: [
    {
      resource: "post",
      action: "update",
      conditions: [
        {
          field: "postAuthorId",
          operator: ConditionOperator.EQUALS,
          value: "userId",
        },
      ],
    },
  ],
};

// Check with context
const result = engine.checkPermission("author-1", "post", "update", {
  context: {
    postAuthorId: "userId",
    userId: "author-1",
  },
});
```

### Supported Condition Operators

- `EQUALS`: Exact match
- `NOT_EQUALS`: Not equal
- `IN`: Value in array
- `NOT_IN`: Value not in array
- `GREATER_THAN`: Numeric comparison
- `LESS_THAN`: Numeric comparison
- `GREATER_THAN_OR_EQUAL`: Numeric comparison
- `LESS_THAN_OR_EQUAL`: Numeric comparison
- `CONTAINS`: String contains substring
- `NOT_CONTAINS`: String doesn't contain substring
- `STARTS_WITH`: String starts with
- `ENDS_WITH`: String ends with
- `MATCHES`: Regular expression match

### Role Inheritance

Create role hierarchies where child roles inherit parent permissions:

```typescript
const userRole: Role = {
  id: "user",
  name: "User",
  permissions: [
    { resource: "profile", action: "read" },
    { resource: "profile", action: "update" },
  ],
};

const moderatorRole: Role = {
  id: "moderator",
  name: "Moderator",
  permissions: [{ resource: "comment", action: "delete" }],
  inherits: ["user"], // Inherits all user permissions
};

engine.roles.addRole(userRole);
engine.roles.addRole(moderatorRole);
```

### Multiple Permission Checks

Check multiple permissions at once:

```typescript
// Check if user has ALL permissions
const hasAll = engine.checkAllPermissions("user-1", [
  { resource: "post", action: "create" },
  { resource: "post", action: "publish" },
]);

// Check if user has ANY permission
const hasAny = engine.checkAnyPermission("user-1", [
  { resource: "post", action: "delete" },
  { resource: "post", action: "publish" },
]);
```

### Direct Permission Management

Grant or revoke permissions directly to users:

```typescript
// Grant permission
engine.grantPermission("user-1", {
  resource: "admin-panel",
  action: "access",
});

// Revoke permission
engine.revokePermission("user-1", "admin-panel", "access");
```

## API Reference

### PermissionEngine

Main class for managing users, roles, and permissions.

#### Methods

- `addUser(user: User): void` - Add a user
- `getUser(userId: string): User | undefined` - Get a user
- `removeUser(userId: string): boolean` - Remove a user
- `assignRole(userId: string, roleId: string): boolean` - Assign role to user
- `removeRole(userId: string, roleId: string): boolean` - Remove role from user
- `checkPermission(userId: string, resource: string, action: string, options?: CheckOptions): PermissionCheckResult` - Check permission
- `checkAllPermissions(userId: string, checks: Array<{resource: string, action: string}>, options?: CheckOptions): PermissionCheckResult` - Check multiple permissions (AND)
- `checkAnyPermission(userId: string, checks: Array<{resource: string, action: string}>, options?: CheckOptions): PermissionCheckResult` - Check multiple permissions (OR)
- `grantPermission(userId: string, permission: Permission): boolean` - Grant direct permission
- `revokePermission(userId: string, resource: string, action: string): boolean` - Revoke direct permission

### RoleManager

Accessed via `engine.roles`

#### Methods

- `addRole(role: Role): void` - Add a role
- `getRole(roleId: string): Role | undefined` - Get a role
- `getAllRoles(): Role[]` - Get all roles
- `removeRole(roleId: string): boolean` - Remove a role
- `updateRole(roleId: string, updates: Partial<Role>): boolean` - Update a role
- `getRolePermissions(roleId: string): Permission[]` - Get all permissions (including inherited)
- `addPermissionToRole(roleId: string, permission: Permission): boolean` - Add permission to role
- `removePermissionFromRole(roleId: string, resource: string, action: string): boolean` - Remove permission from role

### PolicyManager

Accessed via `engine.policies`

#### Methods

- `addPolicy(policy: Policy): void` - Add a policy
- `getPolicy(policyId: string): Policy | undefined` - Get a policy
- `getAllPolicies(): Policy[]` - Get all policies
- `removePolicy(policyId: string): boolean` - Remove a policy

## Examples

See the [examples](./examples) directory for comprehensive examples:

```bash
npm run example
```

## Building

```bash
npm run build
```

The compiled JavaScript will be in the `dist/` directory.

## Which Version Should I Use?

### Use V1 (PermissionEngine) if:

- ✅ Getting started or prototyping
- ✅ Small application (< 1,000 users)
- ✅ Single server deployment
- ✅ All permission data fits in memory
- ✅ You want the simplest setup

### Use V2 (PermissionEngineV2) if:

- ✅ **Production application** (recommended)
- ✅ Large user base (1,000s - millions)
- ✅ Multi-server / microservices deployment
- ✅ Need data persistence
- ✅ Want horizontal scalability
- ✅ Need caching strategies

**See [ARCHITECTURE.md](./ARCHITECTURE.md) and [docs/DATABASE_INTEGRATION.md](./docs/DATABASE_INTEGRATION.md) for details.**

## Use Cases

- **Web Applications**: Control access to routes, API endpoints, and resources
- **Content Management Systems**: Manage user roles and content permissions
- **Multi-Tenant Applications**: Isolate permissions between tenants
- **API Services**: Protect API endpoints with fine-grained access control
- **Admin Panels**: Control access to administrative features
- **Microservices**: Centralized permission service with database backend

## Best Practices

1. **Use Roles for Common Permissions**: Group common permissions into roles
2. **Use Policies for Complex Logic**: Implement business rules with policies
3. **Use Conditions for Context-Aware Access**: Add conditions when access depends on context
4. **Keep Permissions Granular**: Define specific resources and actions
5. **Test Permission Logic**: Thoroughly test your permission rules
6. **Document Roles and Policies**: Maintain clear documentation of your access control model

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.
