Commit Graph

3 Commits

Author SHA1 Message Date
James 16045d5185 Mandatory config file for commercial replication (no env vars)
Replication is mandatory in Commercial Edition, configured via
/etc/clavitor/replication.yaml (not env vars or CLI flags).

Changes:
- edition/config.go: LoadReplicationConfig() for commercial - validates YAML
- edition/config_community.go: Community stub returning error
- edition/edition.go: Shared ReplicationConfig type with nested structure
- edition/replication.go: Use new nested config (BackupPOP.URL, etc.)
- edition/backup_mode.go: Fix X-Primary-Location header (TODO: add primary_pop to config)
- cmd/clavitor/main.go: Remove replication-* flags, load from /etc/clavitor/replication.yaml
- go.mod/go.sum: Add gopkg.in/yaml.v3 dependency

Config structure:
pop_id: calgary-01
region: north-america
role: primary  # or backup
backup_pop:
  id: zurich-01
  url: https://zurich-01.clavitor.ai
  auth_token_file: /etc/clavitor/replication.key
auth:
  token_file: /etc/clavitor/replication.key

Validation:
- pop_id, region, role are required
- primary role requires backup_pop.id and backup_pop.url
- backup role should NOT have backup_pop configured
- Auth token file must exist

Startup behavior:
- Commercial without config: vault refuses to start
- Community: ignores replication, single-node only

Documentation:
- SPEC-replication-config.md: Full config file design
2026-04-02 00:56:30 -04:00
James 00b7105e18 Event-driven async replication (Commercial Only)
Replaces wasteful 30s polling with event-driven design:
- No polling - worker sleeps until woken by SignalReplication()
- Replication triggers immediately on write operations
- Perfect for low-change vaults (could be days without writes)

Changes:
- edition/replication.go: Event-driven worker with channel signaling
- edition/edition.go: Add SignalReplication var
- edition/community.go: No-op SignalReplication stub
- edition/commercial.go: Wire up signalReplication

Architecture:
1. Write handler marks entry dirty (replication_dirty = 1)
2. Calls edition.SignalReplication() (non-blocking)
3. Worker wakes, batches ALL dirty entries
4. POSTs to backup POP
5. Clears dirty flags on success
6. Worker sleeps until next signal

Retry logic:
- Exponential backoff: 1s, 5s, 25s, 125s...
- Max 5 retries, then operator alert
- Dirty entries persist in DB until replicated

Resource efficiency:
- CPU: Only wakes on actual writes (not 2,880x/day polling)
- Network: Only sends when data changes
- For 10 writes/day: ~288x fewer wakeups than polling

Documentation:
- SPEC-replication-async.md: Full event-driven design spec
2026-04-02 00:51:51 -04:00
James 53b2770465 Commercial-only replication infrastructure
Replication is a COMMERCIAL-ONLY feature:
- Community Edition: No replication functionality (privacy-first, single-node)
- Commercial Edition: Real-time sync to backup POPs (Calgary/Zurich)

Changes:
- edition/replication.go: Commercial-only replication implementation stub
- edition/edition.go: Add ReplicationConfig and StartReplication stub
- edition/commercial.go: Wire up replication, use globalConfig
- edition/community.go: No-op StartReplication stub
- edition/CLAUDE.md: Document replication as commercial-only
- cmd/clavitor/main.go: Add replication flags (replication-*)
  - replication-primary, replication-backup, replication-token
  - Warning if used in Community Edition

Security:
- Replication requires inter-POP auth token
- 30-second poll interval, batch up to 100 entries
- Automatic retry with backoff

Note: Full implementation TBD - this is the infrastructure scaffolding.
The actual replicationBatch() logic needs to be implemented for production.
2026-04-02 00:42:40 -04:00