Commit Graph

3 Commits

Author SHA1 Message Date
Alejandro Gutiérrez
c1fa3bcb5c feat: anthropic-style mesh + invite redesign (wave 1 checkpoint)
Ships the user-visible friction fixes and the foundation for the v2
invite protocol. API wiring + CLI client + email UI ship in wave 2.

Meshes — shipped
- Drop global UNIQUE on mesh.slug; mesh.id is canonical everywhere
- Server derives slug from name; create form has no slug field
- Two users can freely name their mesh "platform"; no collision errors
- Migration 0017

Invites v1 — shipped (URL shortener, backward compatible)
- New invite.code column (base62, 8 chars, nullable unique index)
- createMyInvite mints both token + short code; returns shortUrl
- GET /api/public/invite-code/:code resolves short code to token
- New route /i/[code] server-redirects to /join/[token]
- Invite generator UI shows short URL; QR encodes short URL
- Advanced fields (role/maxUses/expiresInDays) collapsed under disclosure
- Migration 0018

Invites v2 — foundation (broker + DB only; API+CLI+Web wiring in wave 2)
- Broker: canonicalInviteV2, verifyInviteV2, sealRootKeyToRecipient
- Broker: POST /invites/:code/claim endpoint (atomic single-use accounting)
- Broker tests: invite-v2.test.ts (signature, expiry, revocation, exhaustion)
- DB: mesh.invite gains version/capabilityV2/claimedByPubkey columns
- DB: new mesh.pending_invite table for email invites
- Migration 0019
- Contract locked in docs/protocol.md §v2 + SPEC.md §14b

Consent landing — shipped
- /join/[token] redesigned: explicit role, inviter, mesh stats, consent
- New server components: invite-card, role-badge, inviter-line, consent-summary
- "Join [mesh] as [Role]" primary action (not just "Join")

Error surfacing — shipped
- handle() now parses {error} responses from hono route catch blocks
- onError fallback includes timestamp so handle() can match apiErrorSchema
- Real error messages reach the UI instead of "Something went wrong"

Docs
- SPEC.md §14b: v2 invite protocol
- docs/protocol.md: v2 claim wire format
- docs/roadmap.md: status
- .artifacts/specs/2026-04-10-anthropic-vision-meshes-invites.md

Deferred to wave 2/3
- API claim route wiring (packages/api)
- createMyInvite v2 capability generation
- Email invite mutation + Postmark delivery
- CLI v2 join flow (x25519 keypair + unseal)
- Web invite-generator email field + v2 display

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:41:11 +01:00
Alejandro Gutiérrez
6acfc252b0 feat(web): public /join/[token] page + https invite url
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled
Clickable HTTPS invite URLs replace the raw ic://join/<token> as the
primary share format. Someone receiving a link in Slack now lands on
a friendly page with install instructions, not a dead-end.

Backend:
- createMyInvite returns a new joinUrl field
  (https://claudemesh.com/join/<token>) alongside the existing
  ic://join/<token> inviteLink and raw token. Schema + Hono route
  updated. ic:// scheme stays — CLI parses both.
- New GET /api/public/invite/:token in packages/api/src/modules/public/
  (unauthed). Decodes the base64url payload, verifies ed25519
  signature against owner_pubkey using the same canonicalInvite()
  contract the broker enforces on join, then joins mesh/invite/user
  to return the shape needed by the landing page. Does NOT mutate
  usedCount — this is a read-only preview.
- Error taxonomy: malformed | bad_signature | expired | revoked |
  exhausted | mesh_archived | not_found. Each returned with any
  metadata we CAN surface (meshName, inviterName, expiresAt) so the
  error page can be specific ("ask Jordan for a new one").
- cache-control: public max-age=30 on valid invites, no-store on
  errors (reasons flip as state changes).

Frontend:
- New public route /[locale]/join/[token] (no auth). Server
  Component fetches the preview endpoint, branches on valid/invalid,
  renders a minimal landing-design-language shell (wordmark header,
  clay accents, serif headlines, mono commands).
- Valid-invite view: "You're invited to {meshName}", inviter +
  role + member-count lede, install-toggle component.
- Invalid-invite view: per-reason error copy + inviter name when
  available + link back to /.
- InstallToggle client component: three-way state
  (unknown/yes/no). Asks "first time / already set up?", then shows
  either the 3-step install+init+join path with per-step copy
  buttons, or the single claudemesh join <token> command for users
  who have the CLI. Every code block has copy-to-clipboard.
- Security footer: "ed25519 keypair generated locally, you keep
  your keys, broker sees ciphertext only, leave anytime with
  claudemesh leave <mesh-slug>".

Invite generator (/dashboard/meshes/[id]/invite):
- QR code now encodes the HTTPS joinUrl instead of ic:// (phone
  cameras land on the web page → friendly path).
- Primary CTA copies the HTTPS URL. Secondary "Copy CLI command"
  for fast-path users. Footer explanation updated.

CLI coordination note: dispatched to broker/db lane — claudemesh CLI
needs to accept BOTH ic://join/<token> AND
https://claudemesh.com/join/<token> (extract <token> from pathname).
Server side already returns both.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:36:24 +01:00
Alejandro Gutiérrez
8a50e4fe56 feat(web): create-mesh form + invite-link generator with QR code
Some checks failed
CI / Tests / 🧪 Test (push) Has been cancelled
- create-mesh-form: RHF + zod + shadcn Form. Fields name, slug (auto-
  derived from name, editable), visibility, transport. Slug validation
  matches server (lowercase letters, digits, hyphens). Slug collision
  errors surface on the slug field.
- invite-generator: RHF + zod. Fields role, maxUses, expiresInDays.
  After generation: renders the ic://join/... invite link as a 256px
  QR code (PNG data URL, Claude-palette colors) + copy-to-clipboard
  button + "claudemesh join <link>" snippet for teammates.

Add: qrcode 1.5.4 + @types/qrcode 1.5.5 (QR generation runs client-side).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 22:56:49 +01:00