# Storage & Persistence

Nord Doorlock supports persistence without requiring a database.

## JSON Mode

Default:

```lua
Config.Storage = 'json'
```

Despite the name, the authoritative store is FiveM Resource KVP.

KVP key:

```text
nord_doorlock:doors:v2
```

The resource also mirrors data to:

```text
data/doors.json
data/doors.backup.json
```

This design allows doors to survive resource/server restarts even when the resource directory is not writable.

## Source Selection on Load

When using JSON mode, Nord Doorlock can read:

- KVP
- `data/doors.json`
- `data/doors.backup.json`

The newest valid source is selected.

Legacy JSON arrays are accepted and migrated to the newer persisted wrapper.

## JSON Payload Shape

Current mirror structure:

```json
{
  "version": 2,
  "savedAt": 1700000000,
  "doors": []
}
```

## MySQL Mode

Configure:

```lua
Config.Storage = 'mysql'
```

oxmysql must be started.

The table is auto-created.

Optional SQL:

```sql
CREATE TABLE IF NOT EXISTS `nord_doorlock` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `data` LONGTEXT NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

Each database row stores the door payload in the `data` column.

## Auto Mode

```lua
Config.Storage = 'auto'
```

If oxmysql is running, MySQL is used.

Otherwise Nord Doorlock falls back to KVP/JSON.

## Persistence Safety

For authoritative changes, the server saves before broadcasting success.

If persistence fails, state-changing API operations attempt to roll back the in-memory change rather than pretending the operation succeeded.

## Storage Diagnostics

Console or administrator command:

```text
doors_storage
```

Typical fields:

```text
mode
ready
doors
error
```

Developer export:

```lua
local health = exports.nord_doorlock:GetStorageHealth()
```

Returned data includes values such as:

```lua
{
    mode = 'json',
    configuredMode = 'json',
    lastError = nil,
    kvpKey = 'nord_doorlock:doors:v2',
    ready = true,
    serverError = nil,
    doorCount = 10
}
```

## Reloading From Persistence

Server export:

```lua
local ok, count, removedDuplicates =
    exports.nord_doorlock:ReloadDoors()
```

This reloads definitions, performs duplicate cleanup and broadcasts a full synchronization.
