# MeridianKV

MeridianKV is a distributed key-value store designed for small to medium clusters that need predictable reads, durable writes, and simple operational behavior. It uses Raft for consensus, replicates data across nodes, and exposes both HTTP and gRPC APIs.

## Features

- Strongly consistent writes using Raft consensus
- Linearizable and follower-read modes
- Namespaced keys with prefix scans
- TTL support for expiring keys
- Watch streams for key and prefix changes
- Snapshotting and log compaction
- TLS support for client and peer traffic
- Prometheus metrics endpoint
- Single static binary deployment

## Install

### Binary

```sh
curl -L https://example.com/meridiankv/releases/latest/meridiankv-linux-amd64 -o meridiankv
chmod +x meridiankv
sudo mv meridiankv /usr/local/bin/
```

### Docker

```sh
docker pull ghcr.io/example/meridiankv:latest
```

### From Source

```sh
git clone https://github.com/example/meridiankv.git
cd meridiankv
make build
```

The compiled binary will be available at:

```sh
./bin/meridiankv
```

## Usage

Start a single-node development server:

```sh
meridiankv server \
  --node-id node-1 \
  --data-dir ./data/node-1 \
  --client-addr 127.0.0.1:8080 \
  --peer-addr 127.0.0.1:9090
```

Start a three-node cluster:

```sh
meridiankv server \
  --node-id node-1 \
  --data-dir ./data/node-1 \
  --client-addr 127.0.0.1:8081 \
  --peer-addr 127.0.0.1:9091 \
  --initial-cluster node-1=127.0.0.1:9091,node-2=127.0.0.1:9092,node-3=127.0.0.1:9093

meridiankv server \
  --node-id node-2 \
  --data-dir ./data/node-2 \
  --client-addr 127.0.0.1:8082 \
  --peer-addr 127.0.0.1:9092 \
  --initial-cluster node-1=127.0.0.1:9091,node-2=127.0.0.1:9092,node-3=127.0.0.1:9093

meridiankv server \
  --node-id node-3 \
  --data-dir ./data/node-3 \
  --client-addr 127.0.0.1:8083 \
  --peer-addr 127.0.0.1:9093 \
  --initial-cluster node-1=127.0.0.1:9091,node-2=127.0.0.1:9092,node-3=127.0.0.1:9093
```

Write a key:

```sh
curl -X PUT http://127.0.0.1:8081/v1/kv/app/config \
  -H "Content-Type: application/json" \
  -d '{"value":"enabled"}'
```

Read a key:

```sh
curl http://127.0.0.1:8081/v1/kv/app/config
```

Delete a key:

```sh
curl -X DELETE http://127.0.0.1:8081/v1/kv/app/config
```

Scan by prefix:

```sh
curl http://127.0.0.1:8081/v1/kv?prefix=app/
```

Set a key with a TTL:

```sh
curl -X PUT http://127.0.0.1:8081/v1/kv/sessions/abc123 \
  -H "Content-Type: application/json" \
  -d '{"value":"active","ttl_seconds":300}'
```

## Configuration

MeridianKV can be configured with flags, environment variables, or a YAML file.

Example `meridiankv.yaml`:

```yaml
node_id: node-1
data_dir: /var/lib/meridiankv

client:
  addr: 0.0.0.0:8080
  tls:
    enabled: true
    cert_file: /etc/meridiankv/client.crt
    key_file: /etc/meridiankv/client.key

peer:
  addr: 10.0.1.10:9090
  tls:
    enabled: true
    cert_file: /etc/meridiankv/peer.crt
    key_file: /etc/meridiankv/peer.key
    ca_file: /etc/meridiankv/ca.crt

cluster:
  initial_members:
    node-1: 10.0.1.10:9090
    node-2: 10.0.1.11:9090
    node-3: 10.0.1.12:9090

storage:
  max_log_entries: 100000
  snapshot_interval: 300s
  compaction_interval: 60s

metrics:
  enabled: true
  addr: 0.0.0.0:9100
```

Run with a configuration file:

```sh
meridiankv server --config /etc/meridiankv/meridiankv.yaml
```

Common options:

| Option | Environment Variable | Description | Default |
| --- | --- | --- | --- |
| `--node-id` | `MERIDIANKV_NODE_ID` | Unique node identifier | required |
| `--data-dir` | `MERIDIANKV_DATA_DIR` | Directory for logs, snapshots, and state | `./data` |
| `--client-addr` | `MERIDIANKV_CLIENT_ADDR` | Address for client API traffic | `127.0.0.1:8080` |
| `--peer-addr` | `MERIDIANKV_PEER_ADDR` | Address for Raft peer traffic | `127.0.0.1:9090` |
| `--initial-cluster` | `MERIDIANKV_INITIAL_CLUSTER` | Comma-separated peer list for bootstrap | empty |
| `--metrics-addr` | `MERIDIANKV_METRICS_ADDR` | Prometheus metrics listener | `127.0.0.1:9100` |
| `--log-level` | `MERIDIANKV_LOG_LEVEL` | Log level: debug, info, warn, error | `info` |

## Operational Notes

Use at least three nodes for production clusters. A cluster can tolerate the failure of `(n - 1) / 2` nodes, where `n` is the total number of voting members.

Back up snapshots from each node regularly. Restores should be performed into a new cluster unless all existing members are offline and confirmed to be using the same snapshot generation.