Skip to content

cuevaio/normal

Repository files navigation

Normal

Normal is a multi-tenant WhatsApp workflow product for teams that run operations through WhatsApp.

Teams use Normal to connect WhatsApp numbers, build visual automations, publish safe workflow versions, run those workflows from real WhatsApp events, and inspect what happened afterward: runs, messages, table changes, side effects, retries, waits, and failures.

Normal is built for operational workflows where correctness matters. A workflow should be testable before it is live, versioned once it is published, scoped to a workspace, and auditable after it runs.

What Normal Does

Normal gives each Workspace a governed automation environment for WhatsApp operations:

  • Workspace members authenticate, select an active Workspace, and work within Workspace-scoped data boundaries.
  • Admins connect WhatsApp Numbers through managed WhatsApp Connections.
  • Editors build Draft Workflows visually, test them safely, and publish immutable Workflow Versions.
  • Admins enable published Workflows for live WhatsApp events.
  • Webhook ingestion verifies provider events, stores raw and normalized facts, matches enabled Workflow Versions, and creates durable Run Intents.
  • The runner consumes Run Intents, executes one path through the target Workflow Version, records attempts and side effects, and supports waits without sleeping inside Worker requests.
  • Users inspect Run History, Message Store entries, WhatsApp Directory data, Workspace Tables, Side Effect Records, and failures.

Product Goal

Normal's goal is to make WhatsApp automation safe enough for real business operations.

The product should let teams automate conversations, updates, routing, table mutations, and AI-assisted work without losing visibility into why something happened, which workflow version ran, what data it used, and which side effects were attempted.

Normal is built around a few product and architecture constraints:

  • Workspaces are the tenant boundary.
  • WhatsApp Connections belong to a Workspace and resolve incoming provider events to that Workspace.
  • Draft Workflows can be edited freely, but live runs use immutable Published Workflow Versions.
  • Publishing stores validated Workflow JSON as data; it does not deploy generated Worker code.
  • Webhook ingestion, product API requests, and workflow execution are separate runtime responsibilities.
  • Runs are durable and auditable through Run Intents, Run History, Side Effect Records, Message Store data, and Workspace Tables.
  • The shared Normal core stays provider-agnostic; WhatsApp provider mechanics live behind runtime adapters.

Product direction lives in docs/prd/normal-production.md. Accepted architecture decisions live in docs/adr/.

Current Status

Normal is under active development. The core product architecture and runtime boundaries are in place, and the repository is organized around the production normal-* apps and shared packages.

Implemented foundations:

  • apps/normal-web: TanStack Start product UI.
  • apps/normal-api: authenticated Effect HTTP API Worker.
  • apps/normal-webhook: WhatsApp webhook ingestion Worker.
  • apps/normal-runner: queue consumer for workflow Run Intents.
  • apps/normal-ops: operational jobs Worker for Normal-owned maintenance work.
  • packages/normal: provider-agnostic workflow and product semantics.
  • packages/domain: shared schemas and domain errors.
  • packages/contracts: typed Effect API/RPC contracts and middleware tags.
  • packages/db: Drizzle schema, migrations, database service, and query programs.
  • packages/cloudflare: typed Effect accessors for Cloudflare bindings.

In place today:

  • Cloudflare Worker app boundaries for web, API, webhook ingestion, runner execution, and ops jobs.
  • Better Auth Organization-based Workspaces as the tenant boundary.
  • Postgres persistence through the shared @repo/db package.
  • Typed Effect contracts between the web app and API.
  • Durable Run Intent boundaries between webhook ingestion and runner execution.
  • Immutable Workflow JSON versions as the runnable workflow artifact.
  • Shared provider-agnostic Normal core for workflow semantics.
  • Managed WhatsApp Connection direction with per-connection provider credentials.

Roadmap

Normal is not feature-complete yet. The main missing areas are:

  • Workflow editor completion: richer block configuration, validation feedback, version preview, restore, and test-run UX.
  • Publish validation: complete server-side checks for graph structure, expressions, table references, resources, secrets, trigger scopes, and warnings.
  • Live WhatsApp runtime: full webhook normalization, idempotency, trigger matching, Run Intent creation, and queue dispatch coverage.
  • Runner behavior: complete block execution semantics, retries, waits, side effect records, dry-run vs live modes, replay, and failure handling.
  • Workspace Tables: stable schema management, row mutation APIs, workflow references, audit patches, and destructive-change protections.
  • Message and directory surfaces: reliable Message Store, Group Activity, WhatsApp Directory sync, contact/group pickers, and run-detail context.
  • Media processing: background media download/storage/processing and visible media status for workflows.
  • Permissions and operations: complete Owner/Admin/Editor/Viewer authorization, operational dashboards, smoke checks, and production diagnostics.
  • Deployment hardening: final Cloudflare resource wiring, secrets, monitoring, retention, and end-to-end verification.

The normal-* apps are the product runtime. Other apps under apps/ should not be treated as the target product surface unless explicitly documented.

Local Development

Install dependencies:

pnpm install

Run the main checks:

pnpm check
pnpm test
pnpm build

Run Postgres and all product apps locally with Docker:

pnpm dev:docker

This starts normal-web on 3000, normal-api on 8787, normal-webhook on 8788, normal-runner on 8789, and normal-ops on 8790.

Database commands live in packages/db:

pnpm --dir packages/db db:push
pnpm --dir packages/db db:studio
pnpm --dir packages/db db:generate
pnpm --dir packages/db db:migrate

Architecture Docs

Read these before changing product or architecture direction:

  • docs/prd/normal-production.md
  • docs/prd/managed-whatsapp-connections.md
  • docs/adr/0001-publish-workflow-json-not-worker-code.md
  • docs/adr/0002-effect-backend-runner-boundary.md
  • docs/adr/0003-split-normal-workers-managed-by-sst.md
  • docs/adr/0004-run-intent-webhook-runner-boundary.md
  • docs/adr/0005-normal-core-provider-boundary.md
  • docs/adr/0006-tanstack-start-normal-web.md
  • docs/adr/0007-workspace-tenancy-and-better-auth.md
  • docs/adr/0008-effect-contracts-normal-api-boundary.md
  • docs/adr/0009-normal-persistence-in-shared-db-package.md
  • docs/adr/0010-use-granular-whatsapp-provider-events.md
  • docs/adr/0011-separate-message-store-from-group-activity.md
  • docs/adr/0012-process-media-after-message-ingestion.md
  • docs/adr/0013-acyclic-single-path-workflow-execution.md
  • docs/adr/0014-workspace-tables-as-postgres-jsonb-rows.md
  • docs/adr/0015-managed-whatsapp-connections.md
  • docs/adr/0016-whatsapp-directory-sync.md

Tech Stack

Area Technology
Runtime Cloudflare Workers
Web app TanStack Start, React, TanStack Router, TanStack Query
Backend architecture Effect v4
API contracts Effect HTTP API and RPC contracts
Auth and tenancy Better Auth Organizations as Normal Workspaces
Database PostgreSQL, Cloudflare Hyperdrive, Drizzle ORM
Storage and queues Cloudflare R2 and Queues
Styling Tailwind CSS v4 and shadcn-style components
Testing Vitest and @effect/vitest
Package manager pnpm workspaces

License

See LICENSE for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages