# Clavitor Edition System > **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-vault (this subproject). You are **Sarah**. Commercial-only code MUST be behind build tags so community builds cannot accidentally activate it. This directory implements build-time differentiation between **Community** (OSS) and **Commercial** (hosted) editions of Clavitor Vault. ## Architecture ``` edition/ ├── edition.go # Interface definition (build-agnostic) ├── community.go # Community Edition (default, !commercial build tag) └── commercial.go # Commercial Edition (commercial build tag) ``` ## Build Instructions ### Community Edition (Default) ```bash # Self-hosted, no telemetry, Elastic 2 go build -o clavitor ./cmd/clavitor/ ``` ### Commercial Edition ```bash # Managed by clavitor.ai, telemetry enabled, SCIM/SIEM support go build -tags commercial -o clavitor ./cmd/clavitor/ ``` ## Key Differences | Feature | Community | Commercial | |---------|-----------|------------| | Telemetry | Manual opt-in via CLI flags | Enabled by default, centralized | | Operator Alerts | Local logs only | POSTs to `/v1/alerts` endpoint | | **Replication** | **Not available** | **Real-time sync to backup POPs (Calgary/Zurich)** | | **Tarpit** | **Not available (simple 404)** | **30s connection drain (anti-scanner)** | | Central Management | None | Multi-POP dashboard at clavitor.ai | | SCIM/SIEM | No | Yes | | **License** | Elastic License 2.0 | Commercial license | ## Commercial-Only Features The following features are **only available in Commercial Edition** and do not exist in Community code: ### 1. Real-Time Replication to Backup POPs **Build constraint:** `//go:build commercial` Background replicator that: - Polls `EntryListUnreplicated()` every 30 seconds - POSTs encrypted entry blobs to backup POP (Calgary or Zurich) - Automatic retry with exponential backoff (max 5 retries) - Batching for efficiency (up to 100 entries per request) - Conflict resolution: last-write-wins by timestamp - Automatic failover: primary → backup POP switching **Community behavior:** No replication code. `ReplicatedAt` field exists in DB schema (for future compatibility) but is never populated or read. ### 2. Multi-POP Failover Commercial POPs register with the control plane. If primary POP fails, DNS routes to backup within 60 seconds. ### 3. Centralized Audit Log Aggregation All operator alerts across all POPs feed into central dashboard at clavitor.ai. ### 4. Tarpit (Anti-Scanner Defense) **Build constraint:** `//go:build commercial` Commercial edition includes a "tarpit" handler for 404/405 responses that: - Holds unrecognized requests for 30 seconds - Drips one byte per second to keep connection alive - Wastes scanner/bot resources (automated tools timeout waiting) - Capped at 1000 concurrent connections (drops excess immediately) - **Interruptible on shutdown** — checks `edition.ShutdownContext` each second **Community behavior:** Simple 404/405 responses. Fast, user-friendly, immediate shutdown. **Why this is commercial-only:** - Self-hosted users (community) don't need anti-scanner defense - Tarpit complicates shutdown (needs context cancellation) - Enterprise (commercial) faces more automated attacks ## Usage in Code ### Sending Operator Alerts ```go // Always use edition.Current.AlertOperator() instead of log.Printf edition.Current.AlertOperator(ctx, "auth_error", "message", map[string]any{ "key": "value", }) ``` **Community behavior:** Logs to stderr with `OPERATOR ALERT [type]: message` prefix. **Commercial behavior:** Logs locally + POSTs JSON to `{TelemetryHost}/v1/alerts`. ### Checking Edition ```go if edition.Current.Name() == "commercial" { // Commercial-only features } if edition.Current.IsTelemetryEnabled() { // Telemetry is active (commercial always, community if configured) } ``` ### Commercial Configuration Only valid for commercial builds. Community builds log a warning if called. ```go edition.SetCommercialConfig(&edition.CommercialConfig{ TelemetryHost: "https://hq.clavitor.com", TelemetryToken: "bearer-token", TelemetryFreq: 300, // 5 minutes POPRegion: "us-east-1", }) // Start periodic telemetry reporting ctx := context.Background() edition.StartTelemetry(ctx) ``` ## Environment Variables (Commercial) | Variable | Purpose | |----------|---------| | `TELEMETRY_HOST` | Base URL for telemetry (e.g., `https://hq.clavitor.com`) | | `TELEMETRY_TOKEN` | Bearer token for authentication | | `TELEMETRY_FREQ` | Seconds between POSTs (default: 300) | | `POP_REGION` | POP identifier for dashboards | ## Alert Endpoint (Commercial) Commercial builds POST to: ``` POST {TelemetryHost}/v1/alerts Authorization: Bearer {TelemetryToken} Content-Type: application/json ``` Payload: ```json { "edition": "commercial", "type": "auth_system_error", "message": "Agent lookup failed", "details": {"error": "..."}, "hostname": "pop-us-east-1-03", "pop_region": "us-east-1", "timestamp": "2026-04-02T00:11:45Z" } ``` ### Handling 404/Method Not Allowed The router uses edition-specific handlers for unmatched routes: ```go notFoundHandler := edition.Current.NotFoundHandler() r.NotFound(notFoundHandler) r.MethodNotAllowed(notFoundHandler) ``` **Community:** Returns simple 404. Fast shutdown, no resource waste. **Commercial:** Tarpit handler holds connections for 30s (anti-scanner), but exits immediately on `edition.ShutdownContext` cancellation. ## Important Notes for Opus 1. **Never remove the build tags** — they're essential for the dual-license model. 2. **Always use `edition.Current`** — don't branch on build tags in application code. 3. **Community is default** — if someone builds without tags, they get OSS edition. 4. **Commercial config is optional** — commercial builds work without telemetry (just logs). 5. **Telemetry is separate** — the old `lib/telemetry.go` still exists for community opt-in. ## Testing ```bash # Test community go test ./edition/... # Test commercial go test -tags commercial ./edition/... # Build both go build ./cmd/clavitor/ && go build -tags commercial ./cmd/clavitor/ ```