# How Permissions and Share Permissions Are Managed in the Macro Codebase

> Discover how Macro manages permissions and share permissions using the SharePermissionV2 model, offering link defaults and per-channel overrides for fine-grained control.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: internals
- Published: 2026-08-15

---

**Macro implements a fine-grained permission system through the `SharePermissionV2` model in the `macro_db_client` crate, combining link-based defaults with optional per-channel overrides.**

The Macro repository uses a database-backed **share permission** architecture to control access across projects, chats, channels, and calls. This system separates global link permissions from contextual channel permissions, enabling both public sharing and scoped collaboration. The implementation resides primarily in the `macro_db_client` crate and supporting tooling.

---

## Core Data Model: SharePermissionV2

The permission system centers on `SharePermissionV2`, a struct with three controlling fields:

| Field | Purpose |
|-------|---------|
| `link_share` | Defines link visibility via the `LinkShare` enum (Public, Private, or limited audience) |
| `link_share_access_level` | Default access granted through links: **View**, **Comment**, or **Edit** |
| `channel_share_permissions` | Optional per-channel overrides stored as separate database rows |

These fields work together to determine effective permissions at runtime. The `LinkShare` and `AccessLevel` enums define the permission vocabulary used throughout the system.

---

## Permission Creation Flow

### Step 1: Create the Base Share Permission

When entities are persisted, the system first creates a `SharePermissionV2` record. In [`tooling/seed_cli/src/service/db/mod.rs`](https://github.com/macro-inc/macro/blob/main/tooling/seed_cli/src/service/db/mod.rs), the `create_project_link_share_permission` function handles this:

```rust
// Creates project-wide share permission at lines 424-428
macro_db_client::share_permission::create::create_project_permission(
    &share_permission,
)
.await?;

```

This pattern applies across entity types—projects, chats, calls—establishing the foundational permission record before entity creation completes.

### Step 2: Map High-Level Concepts to Concrete Permissions

The [`tooling/seed_cli/src/entity/scenario/apply.rs`](https://github.com/macro-inc/macro/blob/main/tooling/seed_cli/src/entity/scenario/apply.rs) file contains a `share_permission` helper (around line 492) that translates scenario-based `ShareLevel` values into `AccessLevel` variants:

```rust
// Mapping at lines 494-504
match share_level {
    ShareLevel::View => AccessLevel::View,
    ShareLevel::Comment => AccessLevel::Comment,
    ShareLevel::Edit => AccessLevel::Edit,
}

```

This abstraction layer separates business logic from database storage details.

### Step 3: Attach Permission ID to Entities

The generated `share_permission_id` becomes a foreign key on the created entity. Consumers resolving share links query this ID to determine access rights.

---

## Channel-Specific Permission Overrides

For entities appearing within channels, Macro supports **channel share permissions** that override the global link default.

### Creating Channel Overrides

The `insert_channel_share_permission` function in [`tooling/seed_cli/src/service/db/mod.rs`](https://github.com/macro-inc/macro/blob/main/tooling/seed_cli/src/service/db/mod.rs) (line 206) inserts these records:

```rust
let channel_sp = ChannelSharePermission {
    share_permission_id,
    channel_id,
    access_level: AccessLevel::Comment, // Override: comment-only in this channel
};

macro_db_client::share_permission::channel_permission::create::insert_channel_share_permission(
    &channel_sp,
).await?;

```

### Upsert Pattern for Idempotency

The `upsert_channel_share_permission` function (lines 335-345) implements create-or-update semantics, ensuring safe concurrent modifications:

```rust
// Handles existing rows gracefully
service::db::upsert_channel_share_permission(ctx, permission).await?;

```

### Permission Synchronization on Mentions

When entities are mentioned in channel messages, `update_share_permissions_for_mention` (lines 191-204) automatically creates or updates channel permissions to keep access in sync with the mention context.

### Duplicate Handling

The insertion functions are designed to be idempotent. `insert_channel_share_permission` logs a warning and continues if a permission already exists (line 214), preventing failures from race conditions.

---

## JWT Integration and Runtime Enforcement

Permissions flow through the authentication layer via JWT claims.

### Token Decoding

The `decode_jwt` crate parses tokens and extracts permission-related claims. This crate lives at [`crates/decode_jwt/src/lib.rs`](https://github.com/macro-inc/macro/blob/main/crates/decode_jwt/src/lib.rs) and serves as the entry point for permission validation in service boundaries.

### Unfurl Service Claims Enrichment

The [`services/unfurl_service/src/unfurl/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/unfurl_service/src/unfurl/mod.rs) file contains Macro-specific JWT claim handling. At line 461, a comment references ticket **M-3421**, indicating where custom permission claims are injected into tokens for downstream services.

This integration allows permission checks to occur at the edge, reducing database load for repeated requests.

---

## Complete Permission Example

Here's a runnable example combining the key operations:

```rust
use macro_db_client::share_permission::{SharePermissionV2, LinkShare, AccessLevel};
use macro_db_client::share_permission::channel_permission::ChannelSharePermission;

// Create base permission with public edit access
let base_permission = SharePermissionV2 {
    link_share: Some(LinkShare::Public),
    link_share_access_level: Some(AccessLevel::Edit),
    channel_share_permissions: None,
};

let share_permission_id = macro_db_client::share_permission::create::create_project_permission(
    &base_permission,
).await?;

// Add restrictive channel override
let channel_override = ChannelSharePermission {
    share_permission_id,
    channel_id: "channel_123".into(),
    access_level: AccessLevel::Comment, // Narrow to comment-only in this channel
};

macro_db_client::share_permission::channel_permission::create::upsert_channel_share_permission(
    &channel_override,
).await?;

```

---

## Key Implementation Files

| File Path | Responsibility |
|-----------|---------------|
| [`tooling/seed_cli/src/service/db/mod.rs`](https://github.com/macro-inc/macro/blob/main/tooling/seed_cli/src/service/db/mod.rs) | Core CRUD operations for share permissions, channel overrides, and mention-triggered updates |
| [`tooling/seed_cli/src/entity/scenario/apply.rs`](https://github.com/macro-inc/macro/blob/main/tooling/seed_cli/src/entity/scenario/apply.rs) | High-level permission construction and `ShareLevel` to `AccessLevel` mapping |
| [`crates/decode_jwt/src/lib.rs`](https://github.com/macro-inc/macro/blob/main/crates/decode_jwt/src/lib.rs) | JWT parsing and permission claim extraction |
| [`services/unfurl_service/src/unfurl/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/unfurl_service/src/unfurl/mod.rs) | Token enrichment with Macro-specific permission claims (M-3421) |

---

## Summary

- **SharePermissionV2** is the canonical permission model with `link_share`, `link_share_access_level`, and optional `channel_share_permissions` fields.
- **Link-based access** defaults are created first, then **channel overrides** provide contextual restrictions.
- **Idempotent operations** (`insert_channel_share_permission`, `upsert_channel_share_permission`) handle concurrent updates safely.
- **JWT integration** (`decode_jwt`, `unfurl_service`) embeds permissions in authentication tokens for distributed enforcement.
- **Mention synchronization** (`update_share_permissions_for_mention`) keeps channel permissions consistent with message references.

---

## Frequently Asked Questions

### What is the difference between link share permissions and channel share permissions?

**Link share permissions** define the default access level for anyone using a share link to the entity, controlled by `link_share` and `link_share_access_level`. **Channel share permissions** are optional overrides that apply when the entity appears within a specific channel, allowing narrower access (e.g., comment-only) than the global default. These are stored separately and resolved at runtime based on context.

### How does Macro handle concurrent permission updates?

The system uses **idempotent upsert operations**. Functions like `upsert_channel_share_permission` either create new records or update existing ones, while `insert_channel_share_permission` logs warnings and continues on duplicate key errors. This design prevents race conditions from causing failures during high-concurrency scenarios.

### Where are permissions enforced in the request lifecycle?

Permissions enter the request lifecycle through **JWT claims**. The `decode_jwt` crate parses tokens at service boundaries, and the `unfurl_service` enriches tokens with Macro-specific permission data. Downstream services validate these claims without requiring additional database queries, enabling scalable distributed enforcement.

### Can channel permissions grant broader access than link permissions?

**No.** The system assumes link permissions represent the maximum access level. Channel permissions are designed to **restrict** access further for specific contexts. If broader channel access is needed, the base `link_share_access_level` must be updated accordingly.