Architecture
Markdown file
docs/ARCHITECTURE.md
Architecture
High-level overview
This system is a small “growth agent” service for a Shopify app:
- Discovery: find potential leads (e.g., Reddit posts) for merchants with pain.
- Outreach: draft compliant messages, optionally require manual approval, then send.
- Telemetry: ingest events from the Shopify app, compute activation/value, decide review prompts.
Components
Web app (Next.js)
- UI:
src/app/*pages for dashboard + approvals/installs/leads + context packs + run traces. - API routes:
src/app/api/agent/run/route.ts: enqueue campaign ticks (and sweep approved drafts).src/app/api/webhooks/shopify-events/route.ts: ingest app telemetry and enqueue recompute.src/app/api/messages/[messageId]/approve|reject/route.ts: manual approval workflow.
Worker (BullMQ)
- Entry:
src/queue/worker.ts - Queue client:
src/queue/client.ts - Task names:
src/queue/tasks.ts - Responsibilities:
- run campaign tick loop
- recompute activation metrics
- send outbound messages
Agent logic
- Orchestration:
src/lib/agent/orchestrator.ts(plan → qualify → draft → critique → dispatch) - LLM client + prompts:
src/lib/llm/* - Context packs:
src/lib/agent/context.ts+AppContext/CampaignContextmodels - Jobs:
src/lib/agent/jobs.ts - Guardrails:
src/lib/guardrails.ts(policy lint + cadence helpers) - Scoring:
src/lib/scoring.ts
Data model (Prisma + Postgres)
- Schema:
prisma/schema.prisma - Orchestration traces:
AgentRun,AgentStep,LlmCall - Telemetry ingestion:
src/lib/telemetry/ingest.ts - Activation compute:
src/lib/telemetry/compute.ts
Primary flows (sequence)
Campaign tick (acquisition loop)
POST /api/agent/run- Enqueue
CAMPAIGN_TICKjobs for active campaigns - Worker processes
CAMPAIGN_TICK:- discover leads
- create outreach drafts
- if policy passes + approval gates allow, send
Telemetry → activation → review prompt
- Shopify app posts event to
POST /api/webhooks/shopify-events - API writes
AppEventand upsertsInstall - Enqueue
RECOMPUTE_INSTALL - Worker recomputes
ActivationMetricand maybe createsReviewPrompt
Trust & compliance boundaries
- No incentivized review language: content lint blocks disallowed patterns.
- Manual approval (default for Reddit DMs): prevents accidental sending.
- Cadence caps: prevents spam (per-campaign and/or per-channel).
Connectors
- Connector:
src/lib/connectors/email.ts - Call sites:
src/lib/agent/jobs.ts(send step) - Provider selection:
EMAIL_PROVIDER="postmark" | "resend"- If unset, the connector prefers Postmark when configured.
- Connector:
src/lib/connectors/reddit.ts(snoowrap)