logicspike/docs

Forms

Forms Service — Documentation Index

Last Updated: 2026-06-28 Status: Active Service: apps/forms-service Public submit URL: https://api.vlozi.app/forms/f/:form_id


What this is

Vlozi Forms is a multi-tenant, Web3Forms-grade form backend. A tenant creates a form in the dashboard, gets a public form_id, and embeds a <form> (or AJAX call, or SDK) on any website. The service filters spam, stores submissions, bills credits, notifies the owner via email, fires webhooks, and exposes analytics — all without any tenant-side backend code.


Doc Index

File What's in it
architecture.md System diagram, three request surfaces, middleware pipeline, submission flow sequence, service boundaries, caching model, gateway wiring, environment bindings
database.md All 5 tables with every column, indexes, JSONB shapes, migration history
api-spec.md Every HTTP route — public submit, admin CRUD, MCP tools, analytics, webhooks, health endpoints
billing.md Credit rate (0.25 cr/submission), accumulator model, settlement idempotency, fail-open behavior
permissions.md Permission strings, full route → permission matrix, gateway headers, role bundles
embedding.md Four embedding surfaces: hosted page, script embed, SDK, plain HTML; field types
webhooks.md Setup, payload shape, headers, HMAC signing, retry policy, delivery log, known gaps
backlog.md Bugs, gaps, improvement scope, scorecard
forms-vision.md Product vision, three pillars, target personas, phased roadmap (Phases 2–5 deferred)
implementation-plan.md Phase 1 completion checklist, deferred items, net-new vs reused summary

Reading Paths

New dev getting started:

  1. architecture.md §1–4 — what the service is, three surfaces, middleware
  2. database.md — 5 tables in 10 minutes
  3. api-spec.md §3 — public submit flow (most complex handler)
  4. billing.md — accumulator model

Adding or changing a route:

  1. api-spec.md — where the route lives
  2. permissions.md — what permission to require
  3. billing.md if it touches credit charges

Debugging a submission problem:

  1. architecture.md §6 — full submission sequence diagram
  2. webhooks.md — if webhook delivery is suspect
  3. billing.md §2 — if it's a 402

Planning future work:

  1. backlog.md — bugs and gaps with priority
  2. forms-vision.md — phases 2–5 roadmap

Codebase Quick Map

apps/forms-service/
├── src/
│   ├── index.ts                  — Hono app, gateway guard, route mounts
│   ├── context.ts                — RequestContext type
│   ├── db/
│   │   ├── client.ts             — Neon connection + QueryLogger
│   │   └── schema.ts             — 5 tables: forms, form_submissions,
│   │                               form_webhook_deliveries, form_views_daily,
│   │                               tenant_forms_usage
│   ├── middleware/
│   │   ├── auth.middleware.ts    — requireTenant, requirePermission
│   │   └── db.middleware.ts      — per-isolate DB cache
│   ├── routes/
│   │   ├── public/
│   │   │   └── submit.ts         — POST /f/:id, GET /f/:id/schema,
│   │   │                           GET /f/:id/page, GET /f/embed.js
│   │   ├── admin/
│   │   │   ├── forms.ts          — CRUD + duplicate + analytics
│   │   │   ├── submissions.ts    — inbox, export, reply
│   │   │   └── webhooks.ts       — delivery log
│   │   └── mcp/
│   │       └── tools.ts          — 15 tools mirroring admin REST
│   ├── services/
│   │   ├── form.utils.ts         — ID gen, slug gen, uniqueness
│   │   ├── schema.ts             — zodFromSchema() validator builder
│   │   ├── notify.ts             — owner email via comms-service
│   │   ├── webhook.ts            — deliverWebhook(), HMAC signing
│   │   ├── credits.ts            — canSubmissionProceed(), meterSubmission()
│   │   └── analytics.ts          — overview + per-form aggregation
│   ├── lib/
│   │   └── embed.ts              — self-contained embed.js string
│   └── utils/
│       ├── errors.ts             — jsonError, ErrorCode
│       └── logger.ts             — structured logger
├── drizzle/
│   └── migrations/               — 5 SQL files (0000–0004)
├── test/                         — 11 test files (vitest + PGLite)
└── wrangler.toml                 — bindings: COMMS_SERVICE, MEDIA_SERVICE,
                                    FORM_RATE_LIMITER (20 req/60s)

Four Things Every Developer Must Know

  1. form_id is the only public credential. It's safe to embed in client HTML. Abuse is contained by allowed_origins (CORS), honeypot, Turnstile, and native rate limiting — not by a secret.
  2. Submissions cost 0.25 credits. The credit gate runs before storage (fail-open on core DB outage). Spam submissions are never billed. See billing.md.
  3. All side effects run in waitUntil(). Owner email, webhook delivery, and credit metering are non-blocking — they never delay the 200 to the visitor. A Worker crash after the response is sent will not roll back the submission.
  4. Webhook secret is set once and cannot be rotated without clearing and resetting webhookUrl. This is backlog.md B6.

Public Docs

User-facing documentation lives at logicspike/public-docs/08-forms/.

Forms