09 · Hub v2

The hub humans review work in

Live at hubv2.apphappenventures.com — ECS Fargate dev. Today it covers ~30% of the vision: 4 read-only domains shipped, the unified human-in-loop task queue with bot identity still missing. This page is the discovery brief in one screen.

Shipped

4 read-only domains

Airtable meetings, HubSpot tasks, Robin AI tasks, R3 + Notion tickets. Google OAuth gated to @happenventures.com.

Missing

The actual queue

Unified human-in-loop view over the 8 task_queue_* tables, bot identity + signature, real send with delay + retries.

Plan

4 phases · 6 weeks · 4 devs

F0 stabilize · F1 unified queue · F2 identity + tools · F3 KPI + training. F0 can start in parallel today.

3 most expensive problems

Integrity before UX

Risk #1

“Approved → Send” redundancy

Event-driven workflow yjrMZbNwqbNTslrD is INACTIVE. Cron workflow wV1Kk3RUwBViEHQP polls every 5min and sends. Both target the same table. Reactivate without deprecating = double send.

Risk #2

ClawBot 76% reject

On task_queue_sales. Humans spend more time fixing drafts than writing from scratch. Pause autonomy_enabled until prompts are recalibrated.

Risk #3

Single points of failure

Jess (ClawBot), Daniela (Paloma), Joan (Robin) — no rotation. Only Olivia has backups. One vacation = backlog.

Stack · verified in code

What's actually running

API

NestJS 11

Prefix /api. Services: hubspot, ai-tasks, tickets, meetings.

Web

Next.js 15 + React 19

App Router, Tailwind v4, shadcn/ui, TanStack Query, Zustand.

LLM

Bedrock Claude

claude-sonnet-4-6 SSE for chat. Second client uses Anthropic API direct — needs consolidation.

Data

5 Airtable bases

HV Ops (27), AI Hub (22), R3 Ops (32), HV Hub Base (24), SSOT Finance (10).

Runtime substrate

n8n + Make

323 workflows backed up, ~130 active. Make.com 46 scenarios. Most automation lives here, not in V2.

Infra

ECS Fargate us-east-2

ALB + ECR + Terragrunt. Cluster hv-hub-v2-development, services hv-hub-v2-{api,web}.

Tech debt · concrete

6 things to fix before scaling

#WhereIssueEffort
1tickets.service.ts:27process.env.NOTION_API_KEY bypasses ConfigService.30 min
2Chat vs ClaudeServiceTwo clients, two models: Bedrock claude-sonnet-4-6 vs Anthropic claude-sonnet-4-20250514.½ day
3meetings.service.tsFirst-name filter — collision risk (Mario vs Mariana).2 h
4Airtable / HubSpot callsZero cache — every refresh hits API, rate-limit risk.½ day
5ObservabilityNo consistent Logger, no metrics, no traces.1 day
6CLAUDE.mdDocuments Auth.js v5; code uses manual Google OAuth. Pick one.1 h doc
Flow · current vs target

Where the queue is going

Today

Two queues, callback is no-op

1. n8n writes to task_queue_* (pending).

2. Hub V2 GET /api/ai-tasks — only Robin + Sales surfaced.

3. User approves/edits/rejects → PATCH Airtable.

4. fireCallback() POSTs to n8n. Today the event-driven workflow is off, so the callback is functionally a no-op — the 5-min cron picks the row up later.

Target post-F1

One queue, owned send path

1. GET /api/queue?assigned_to=me unifies all 8 + finance.

2. UI tabs per bot with identity, signature, word-cap visible.

3. QueueService.resolve() — idempotent: PATCH + audit_log + enqueue.

4. BullMQ + Redis send worker → Gmail send-as with delay + retries + dead-letter.

Roadmap · 6 weeks

F0 → F3

week 1 F0 Stabilize

Independent, low-risk

Reactivate or rewrite “Approved → Send” with stuck-approval monitor. Fix tickets.service.ts:27. Consolidate Claude client. Move OWNER_MAP + USER_TICKET_CONFIG to user_integrations table. Add 60s cache on Airtable/HubSpot.

weeks 2-3 F1 Unified queue

The core feature

QueueModule: GET /api/queue?assigned_to&bot&status aggregating 8 task_queue_* + Robin + Sales. QueueService.resolve() idempotent with audit_log. UI /queue with tabs per bot. BullMQ + Gmail send-as.

weeks 4-5 F2 Identity + tools

Bots get faces

BotIdentityService reads tblRiSakPTB4cVJSr (Bot Settings). UI shows avatar + signature + word-cap. Markdown editor for system_prompt with versioning. Tools panel per bot with RBAC. HV Bot Q&A: RAG over Notion wiki.

week 6 F3 KPI + training

Close the loop

Dashboard /kpi: % approved without edit, time-to-action, throughput per bot. Nightly job exports (draft, edited) pairs to S3 for fine-tune. View-as-user impersonation with audit.

Blocking decisions · need Jess

8 questions that gate F1

#QuestionTrade-off
1Functional owner of the unified Task Queue?Defines default RBAC.
2Send delay scope: per bot, per user, or per playbook?Sales wants 30-90s; Account Manager can be 0s.
3“Approved → Send”: reactivate n8n or migrate to V2 worker?Speed vs ownership.
4Bot identity: one signature per bot, or per (bot × playbook)?Bot Settings has one slot today.
5Consolidate on Bedrock or Anthropic API direct?One client, one model.
6Word-cap 150 vs 250 (Account Mgr vs Sales)?Freeze one or store per bot.
7Operating hours 7-8pm vs 8am-6pm ET?Drives nightly suppression.
8Hub V2 reads Airtable directly or via hv-data-platform?Cache + scalability ceiling.
9Event-driven (reactivate v2 + kill cron) or cron (deprecate v2)?Event = 0s latency + idempotency burden. Cron = works today, 0-5min latency, no explicit retries.
Quick wins · ≤ 1 day each

High ROI, low risk

30 min

Fix Notion ConfigService

tickets.service.ts:27 — coherence + secret management.

½ day

60s cache

Airtable + HubSpot responses. Instant UX, fewer rate-limits.

½ day

Stuck-approval monitor

Slack alert if >30min without send. Catches Risk #1.

2 h

Queue counts endpoint

/api/queue/counts for sidebar badges. Jess asked for it.

1 h

Pause ClawBot autonomy

Set autonomy_enabled=false until recalibrated. Stops the 76% reject bleed.

1 h

CODEOWNERS + PR template

Onboarding for 4 devs.

Appendix K · n8n forensics

The two-workflow truth

There is no silent email loss — there is unowned redundancy on tblPXhWpS79NvLmh9.

WorkflowIDActiveTriggerPath
ClawBot: Approved → Send → Log (v2)yjrMZbNwqbNTslrDoffAirtable poll “Approved Ready to Send”Filter → Signature → Set Sending → RFC-2822 → Gmail → HubSpot log → Mark Sent
Send Approved TaskswV1Kk3RUwBViEHQPonSchedule every 5 minHTTP proxy → Limit → Loop → Suppression → 14d cooldown → Gmail → Cadence stepper
Consequence: emails do go out (cron picks them up within 5 min) but with no explicit retry path post-Gmail. Reactivating the v2 workflow without deprecating the cron causes double-send. Neither workflow consumes fireCallback() from V2 — both are Airtable-polled, which is why the callback is a no-op today.
n8n → Hub v2 backend

NestJS absorbs the 16 cron callers

Hub v2's NestJS API is the natural home for everything n8n does today. Three roles collapse into native modules: @Cron decorators for schedules, controllers for webhooks, services for integrations. No infra additions — ECS Fargate + Secrets Manager are already provisioned.

Today · n8n role 1

16 cron → ClawBot

scheduleTrigger fires → POST to 187.77.29.73:8788 with HTTP Basic in URL. Same password in every JSON.

In Hub v2: ClawbotScheduleModule with one @Cron method per playbook. Secrets Manager injects auth. ~1 day per batch of 5 callers.

Today · n8n role 2

~8 webhook routers

Inbound email/forms/Slack → parse → write Airtable robin_tasks. Real logic lives in n8n nodes.

In Hub v2: @Controller('/ingest/*') + class-validator DTOs + AirtableService. Versioned, testable. 3-5 days.

Today · n8n role 3

Misc integration glue

HubSpot ↔ Airtable sync, WhatsApp notifs, ad-hoc one-offs. Lowest volume, highest variety.

In Hub v2: dedicated IntegrationsModule per surface, behind feature flags. 1-2 weeks rolling.

// apps/api/src/clawbot/clawbot-schedule.service.ts @Injectable() export class ClawbotScheduleService { constructor( private readonly http: HttpService, private readonly secrets: SecretsService, ) {} @Cron('0 */6 * * *', { name: 'cl-01-close-lost' }) async runCloseLost() { const auth = await this.secrets.get('clawbot/basic'); await this.http.post('https://clawbot.hv/pipeline/list', { list_id: '7661', playbook_id: 'recCloseLost', source_workflow: 'hub-v2-scheduler', enrich: true, }, { auth }); } }

Why Hub v2, not EventBridge

The target architecture originally proposed EventBridge for the 16 schedules. Re-evaluation: Hub v2 already runs NestJS on ECS Fargate with Secrets Manager and CloudWatch. Adding @nestjs/schedule is one dependency — EventBridge is an extra surface to wire, monitor and pay for. Keep EventBridge as the fallback if we ever need cross-service triggers; for now the scheduler lives where the code lives.

Next

30 min with Jess

Unblock F1

Take questions 1–8 (plus K's question 9) to a 30-min session with Jess. With those answered, F0 can start in parallel today — all six F0 tasks are independent and low-risk. Workspace audit coverage: 80% (pending: 17 Netlify legacy functions, full system_prompts, executive docs, drawio renders).