clavitor/clavitor.ai/admin/CLAUDE.md

2.5 KiB

clavitor.ai/admin — central admin / Paddle integration

Required reading before any work: CLAVITOR-AGENT-HANDBOOK.md — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavitor.ai/admin (this subproject). You are Emma.

Central admin service. Owns the customer hierarchy (MSP → end-customer → vault slots), the seat ledger, the Paddle webhook handler, and the vault registry mapping (customer, slot_index, l0, pop). This is the directory service — not a vault.

Hard rules specific to this subproject

  • Never hold any decryption material. Central is not a vault. The wrapped L3 stored centrally for distribution is opaque to central — no L3, no L2, no L1, no master_key, ever. If you find yourself wanting to decrypt vault content here, you are in the wrong process.
  • Never trust an inbound webhook without verifying its HMAC signature. Paddle webhook verification is mandatory. The secret comes from PADDLE_WEBHOOK_SECRET. If the env var is unset, every webhook is refused. There is no debug bypass.
  • Never accept admin operations from outside Tailscale. The vaults/claim, issue-token, wl3/since, wl3/full endpoints listen only on the tailnet interface. Public clavitor.ai serves users; the ops control plane is invisible to the internet.
  • Never expose the Paddle API key, webhook secret, or any service credentials in client-side code. Server-side env only.
  • Never delete vault data, WL3 files, or audit logs without an explicit GDPR request. The default lifetime is forever. Cancellation/downgrade marks slots archived; only an explicit one-shot deletion script touches the underlying files.

Vault slot lifecycle (canonical)

Pre-create at subscription time:

  1. Customer subscribes to a plan with N seats → INSERT INTO vault_slots N rows, all status='unused'.
  2. Owner names a slot ("Anna") and clicks "invite" → status moves to pending, central calls the POP's /admin/issue-token over Tailscale, POP returns the 6-char token, central displays it to the owner.
  3. Anna enrolls at the POP → status moves to active, l0 populated, enrolled_at set.
  4. Cancellation/downgrade → status moves to archived. Vault data and WL3 file persist.

Plan upgrade = INSERT more unused rows. Plan downgrade = refuse until the owner manually marks excess slots archived (no silent data loss).

See CLAVITOR-AGENT-HANDBOOK.md Section V → clavitor.ai/admin for the full subproject contract.