# Coordinating Overlay Permissions

In my project, I’ve got overlays—things like movement paths, elevation indicators, and token’s boundary—that need to appear *only* when the viewer has permission to see them. To manage this, I’ve built a system called the `OverlayPermissionCoordinator`.

It bridges **Foundry VTT’s infrastructure** with my **domain logic**, keeping permissions clean, isolated, and easy to reason about.

Here’s a breakdown of how the whole thing works.

## Entry Points: Where the Flow Begins

Overlay view permission checks kick off in a few key methods:

```plaintext
graph TD
    A[UI/Rendering System] --> B{Which Method?}
    B --> C[canViewOverlayOnToken - Single Check]
    B --> D[canViewOverlaysOnToken - Batch Check]
    B --> E[getViewableOverlaysForToken - Get All Viewable]
```

## Single Overlay Check: `canViewOverlayOnToken`

This is the core function that checks **one overlay** on **one token**. Here's what it does under the hood:

```typescript
// Check if a single overlay is viewable by the user
canViewOverlayOnToken(
    overlayId: string,
    targetToken: Token,
    userId: string,
    isGM: boolean,
    viewerTokens: Token[] = []
): boolean {
    const config = this.registry.get(overlayId);

    if (!config) {
        this.logger.warn(`Overlay "${overlayId}" isn’t registered.`);
        return false;
    }

    // Quick exit if the overlay doesn't require permission checks
    if (!config.usePermissionSystem) {
        return true;
    }

    // Gather the necessary data for a proper check
    const targetData = this.getCachedTokenData(targetToken);
    const viewerData = this.getCachedTokensData(viewerTokens);
    const allVisibleTokens = this.getAllVisibleTokensData();

    // Let the domain service handle the actual decision
    return this.permissionService.canViewOverlaysOnToken(
        targetData,
        userId,
        isGM,
        viewerData,
        allVisibleTokens
    );
}
```

### Step-by-step:

1. **Registry Lookup**
    
    * Pulls the overlay config from the registry
        
    * If not found, returns `false`
        
2. **Fast Path Check**
    
    * If `usePermissionSystem === false`, returns `true` immediately
        
    * This skips heavy logic for overlays that don’t need it
        
3. **Data Conversion (Cached)**
    
    * Converts `targetToken` and `viewerTokens[]` into `TokenSightData`
        
    * Fetches all visible tokens if needed
        
4. **Domain Permission Check**
    
    * Calls `permissionService.canViewOverlays()`
        
    * This service lives in the pure domain layer—no Foundry types involved
        
5. **Return Result**
    
    * Comes back with a `boolean` based on the domain logic
        

## Caching Strategy: Keep It Fast, Keep It Simple

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">I've got a sneaking feeling this is just a case of good old-fashioned gold plating — but we’ve chosen the path, so let’s follow it and see if there’s a leprechaun at the end.</div>
</div>

To avoid re-converting tokens constantly, I’ve built a lightweight caching layer:

```typescript
// Token Data Cache Flow
    ┌─────────────────┐
    │  Foundry Token  │
    └────────┬────────┘
             ↓
┌────────────────────────┐
│   Generate Cache Key   │ → `${token.id}-${cacheGeneration}`
└────────────┬───────────┘
             ↓
        ┌────┴────┐
        │ Cached? │
        └────┬────┘
             ↓
         No ─┴── Yes
         ↓        ↓
      Convert    Return
      & Store    Cached
```

The key includes a generation number so I can invalidate it whenever needed (e.g. when tokens move or vision updates).

## Example Flow: Full Walkthrough

Let’s say a user hovers over a token. I want to know which overlays are visible to them:

```typescript
getViewableOverlaysForToken(token, userId, isGM, viewerTokens)
```

### Behind the scenes:

1. Grab all overlays from the registry:  
    `['movement-path', 'elevation-indicator', 'status-effects']`
    
2. Call the batch check:  
    `canViewOverlaysOnToken([...], token, userId, isGM, viewerTokens)`
    
3. For each overlay:
    
    * `movement-path`: needs permission → check domain
        
    * `elevation-indicator`: doesn’t need permission → allow
        
    * `status-effects`: needs permission → check domain
        
4. Result:  
    `['elevation-indicator', 'status-effects']`  
    (assuming `movement-path` was denied)
    

## Why This Works for Me

This setup gives me:

* **Separation of concerns**  
    Foundry stays out of my domain logic. My domain doesn’t even *know* Foundry exists.
    
* **Performance**  
    The system avoids unnecessary work and reuses data wherever possible.
    
* **Flexibility**  
    I can add new permission types or overlay rules without touching Foundry code.
    
* **Testability**  
    Domain services are testable in isolation, no mocks needed.
    
* **Maintainability**  
    All Foundry-specific stuff lives in one place—the coordinator.
    

If you’re wrangling overlays in a similar way or building on Foundry and trying to decouple things, I think this structure makes it much easier to reason about and test.
