# How Data Layers Are Registered in God's Eye View: A Complete Guide to the DataLayerManager System

> Discover how to register data layers in God's Eye View using DataLayerManager. This guide details the registration process, validation, and finalization steps.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: how-to-guide
- Published: 2026-09-06

---

**Data layers in God's Eye View are registered via the `DataLayerManager.register()` method, which validates unique IDs, stores layer modules in an internal map, and seals the registration list when `finalizeRegistrations()` is called.**

God's Eye View is an open-source geospatial visualization platform that overlays real-time data streams—from CCTV feeds to satellite imagery—onto a 3D globe. Understanding how data layers are registered is essential for extending the platform with new data sources. This article breaks down the registration pipeline implemented in `bilawalsidhu/gods-eye-view`, referencing actual source paths and the lifecycle methods that govern each layer.

## The DataLayerManager Architecture**

The core of layer registration lives in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js). The **`DataLayerManager`** class acts as a central registry and controller for all data overlays, enforcing a strict lifecycle from initialization through runtime toggling.

### Why a Dedicated Manager Matters

Without centralized registration, multiple data sources would compete for viewer resources, duplicate IDs would cause conflicts, and serialization state would become inconsistent. The manager solves this by:

- Validating layer uniqueness at registration time
- Locking the layer list after initialization to prevent runtime injection attacks
- Mediating all enable/disable/update calls through a single API

## Layer Module Structure: The Registration Contract**

Before registration, each data source must implement a standard module interface. These modules live in `src/data/*.js` and export a predictable set of properties and functions.

### Required Exports

Every layer module must provide:

- `id` – a unique string identifier used as the map key
- `init(viewer, { signal })` – one-time setup (called once)
- `enable(viewer, { signal })` – activate the overlay
- `disable(viewer, { signal })` – deactivate the overlay
- `update(viewer, { signal })` – refresh data on demand

### Optional Exports

Additional capabilities include:

- `getStats()` – return telemetry for debugging
- `setLifecyclePresentation(presentation)` – customize visual feedback during state changes

Here's a production layer module from the codebase:

```javascript
// src/data/traffic.js – a typical layer module
export const id = 'traffic';

export async function init(viewer, { signal }) {
  // Load static resources, establish WebSocket connections
}

export async function enable(viewer, { signal }) {
  // Add primitives to Cesium viewer, start animation loops
}

export async function disable(viewer, { signal }) {
  // Remove primitives, pause expensive operations
}

export async function update(viewer, { signal }) {
  // Fetch fresh data, update visible entities
}

export function getStats() {
  return { count: vehicleEntityCount, lastUpdate: timestamp };
}

```

Additional layer modules like [`src/data/cctv.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/cctv.js) and [`src/data/satellites.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/satellites.js) follow this identical pattern, differing only in their data fetching and rendering logic.

## Step-by-Step Registration Process**

The registration flow spans three phases: manager instantiation, layer registration, and finalization.

### Phase 1: Create the DataLayerManager

In [`src/main.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js), the application bootstraps the manager early in startup:

```javascript
// src/main.js – creating the manager
import { DataLayerManager } from './data/manager.js';

const viewer = /* Cesium viewer instance */;
const dataManager = new DataLayerManager(viewer);

```

The constructor stores the Cesium viewer reference and initializes internal state: an empty `layers` Map, `_registrationsFinalized = false`, and empty arrays for lifecycle tracking.

### Phase 2: Register Individual Layers

Immediately after instantiation, the application registers each available layer:

```javascript
// src/main.js – registering production layers
import * as trafficLayer from './data/traffic.js';
import * as cctvLayer from './data/cctv.js';
import * as satellitesLayer from './data/satellites.js';

dataManager.register(trafficLayer);
dataManager.register(cctvLayer);
dataManager.register(satellitesLayer);

```

The `register()` method performs validation before accepting a module:

1. Checks that `_registrationsFinalized === false` (throws if registrations are locked)
2. Delegates to `_registerLayer()` for actual processing
3. `_registerLayer()` validates that `module.id` exists and is unique
4. Throws `Error` if duplicate IDs are detected
5. Stores the module in `this.layers` with initial state: `{ module, initialized: false, enabled: false, … }`

Registration is **order-sensitive**—layers are stored in insertion order and initialized in that sequence during finalization.

### Phase 3: Finalize and Lock Registrations

After all production layers are added, the application calls:

```javascript
// src/main.js – finalizing registration
dataManager.finalizeRegistrations([
  { id: 'traffic',    disposition: 'enabled+options' },
  { id: 'cctv',       disposition: 'enabled-only' },
  { id: 'satellites', disposition: 'enabled+options' },
]);

```

The `finalizeRegistrations(serializationRegistry)` method:

- Verifies every registered layer has a matching disposition entry
- Supports three disposition types: `'enabled-only'`, `'enabled+options'`, and `'full-state'`
- Sets `_registrationsFinalized = true` to prevent subsequent `register()` calls
- Triggers `init()` on each layer in registration order

Once finalized, the layer list is immutable. This design prevents runtime code injection and ensures serialization state remains consistent across sessions.

## Runtime Layer Control API**

After registration and finalization, the manager exposes methods to control layer visibility and refresh operations. These are typically invoked from UI handlers in [`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js) or voice command processors.

### Common Operations

| Method | Purpose | Async |
|--------|---------|-------|
| `toggle(id)` | Flip enabled/disabled state | Yes |
| `setEnabled(id, boolean)` | Explicitly set visibility | Yes |
| `refreshLayer(id)` | Request data update | Yes |
| `getLayerState(id)` | Retrieve current metadata | No |
| `getRegistry()` | List all registered IDs | No |

Example usage:

```javascript
// Toggling a layer at runtime (e.g., from UI or voice command)
await dataManager.toggle('traffic');          // flips enabled/disabled
await dataManager.setEnabled('cctv', true);   // explicitly enable
await dataManager.refreshLayer('satellites'); // request fresh update

```

All runtime methods validate that the provided `id` exists in `this.layers` and throw descriptive errors for unknown layers.

## Error Handling and Validation**

The registration system includes defensive checks at multiple stages:

- **Pre-finalization registration**: Prevents adding layers after the application state is sealed
- **Duplicate ID detection**: Catches copy-paste errors in `src/data/*.js` exports
- **Missing disposition**: Ensures every layer has defined serialization behavior
- **Unknown layer access**: Runtime methods fail fast with clear error messages

These validations make debugging extension development significantly easier, as errors surface during initialization rather than at runtime.

## Summary**

- **DataLayerManager** in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) centralizes all layer lifecycle operations
- Layer modules in `src/data/*.js` export `id` plus `init`/`enable`/`disable`/`update` functions
- Registration occurs via `dataManager.register(module)` before `finalizeRegistrations()` locks the system
- The serialization registry defines how each layer's state persists across sessions
- Runtime control uses `toggle()`, `setEnabled()`, and `refreshLayer()` mediated through the manager

## Frequently Asked Questions**

### What happens if I call `register()` after `finalizeRegistrations()`?

The manager throws a runtime error. Once `finalizeRegistrations()` completes, `_registrationsFinalized` becomes `true` and all subsequent `register()` calls are rejected with an explicit exception. This prevents state corruption and ensures the serialization registry remains stable.

### Can I unregister a layer dynamically?

No. The current `DataLayerManager` implementation does not expose an `unregister()` method. Layer removal would require modifying [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) to delete entries from the internal `layers` Map and handle cleanup ordering. For most use cases, `disable()` provides sufficient control without full removal.

### How does the disposition in `finalizeRegistrations()` affect behavior?

The disposition controls state serialization. `'enabled-only'` persists just the on/off status; `'enabled+options'` includes configuration values; `'full-state'` captures complete internal data. This determines what restores when a user reloads the application or shares a session link.