Proferprofer

Architecture

Technical architecture and design decisions

Architecture

System overview

npm package (profer)
  ├── MCP server (3 tools: publish, get, update)
  └── API client (HTTP to Supabase edge functions)

Supabase
  ├── cp_pages     (id, title, html, questions, version, status, webhook_url)
  ├── cp_feedback  (id, page_id, version, answers, reviewer, source)
  ├── Edge function: /pages    (auth CRUD)
  └── Edge function: /v/:id    (public page + feedback submit)

Design decisions

Why Supabase

  • Postgres + Edge Functions in one service
  • No extra hosting or infrastructure to manage
  • Edge functions run close to users globally
  • Built-in auth and row-level security (available if needed)

Why the agent generates HTML

  • No templates to maintain
  • No renderer to debug
  • Works with any agent (Claude, GPT, Gemini, etc.)
  • Agents are already good at generating HTML
  • Maximum flexibility for content type

Why sandboxed iframes

Agent HTML could contain anything — including malicious JavaScript. We render it inside:

<iframe sandbox="allow-same-origin" srcdoc="...">

Plus Content Security Policy headers:

script-src 'nonce-{random}'; style-src 'unsafe-inline';

This means agent scripts can't execute, but styling works fine.

Why short IDs

PF-K8M3N format uses:

  • 2-letter prefix (PF = Profer)
  • 5 characters from an unambiguous alphabet (A-Z + 2-9, excluding 0/O/I/1/L)
  • Rejection sampling eliminates modulo bias from crypto.getRandomValues()
  • ~24M possible IDs — sufficient for the foreseeable future

Why structured questions over comments

Unstructured comments are hard for agents to parse. "I think option B is better but we should also consider..." — is that an approval? A rejection? A maybe?

Structured questions give agents typed data:

  • approve"yes" | "no" | "needs_changes"
  • choice → one of the provided options
  • multi → array of selected options
  • text → free string (when structure isn't possible)

Security model

LayerProtection
PublishingAPI key in Authorization header
Page viewingPublic (by design)
Feedback submissionPublic (no auth, validated against question schema)
Agent HTMLSandboxed iframe + CSP
API key comparisonConstant-time to prevent timing attacks
Answer validationServer-side validation against question types and options

On this page