BYOC Number Pools Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans to implement task-by-task.Goal: Restrict all pool behavior to customer-owned telephony while preserving hosted legacy calls. Architecture: Bind each pool to an explicit custom SIP trunk. Keep optional encrypted customer Twilio replacement credentials on the pool; validate account and trunk ownership, and route every purchase/release/recovery through this binding. Never classify BYOC replacement numbers as platform-hosted. Tech Stack: Existing Fastify/Zod/Kysely/PostgreSQL, LiveKit SIP, Twilio SDK, React and generated SDK. Spec: docs/superpowers/specs/2026-10-18-byoc-number-pools.md
Global Constraints
- Existing worktree and PR; no unrelated changes or production mutations.
- One backend function per file; derived types; no any/as/nonnull assertions.
- Additive migration with lock_timeout; no required new API request fields at schema level.
- Tests use isolated local verification DB and stub vendor boundaries, never live vendors.
- Credentials encrypted and write-only; no hosted/global fallback for pools.
Review Focus
- Foreign-org, hosted and stale number/trunk references must reject at save and dialing.
- Invalid/missing credentials and mismatched provider trunk must fail before purchase/release.
- Replacement and cancellation races must retain account identity and purchased candidates.
- Single-number/trunk sequence steps remain single attempt and progress normally.
- Older clients and pre-existing hosted pool drafts fail safely without invoking hosted replacement.
Task 1: Backend ownership, routing and replacement
Files: backend/src/phone/number-pools/*; backend/src/phone/phone-service/set-agent-outbound-trunk.ts; backend/src/campaign/sender-binding-service/voice-sender-catalog.ts; backend/src/voice-channel/livekit/live-kit-service/make-outbound-call.ts; related exact specs; additive Kysely migration; generated DB types. Interfaces: Pool input gains optional outbound_trunk_id and optional nullable twilio_connection . Pool response exposes outbound_trunk_id and nullable twilio_connection , never auth_token. Backend requires valid custom-trunk binding for pool saves/calls. Add shared scoped pool-route and customer-client helpers, used by all replacement/cancellation paths.- Extend nearest regression tests for BYOC eligibility, hosted rejection, no fallback, encrypted credentials and foreign-account/trunk rejection; prove relevant new tests red.
- Implement migration, validation, safe customer credential storage, pool routing and replacement/recovery/cancellation on customer account.
- Adapt existing pool fixtures to intended BYOC scope while preserving their original assertions, and run exact affected specs plus backend typecheck/lint.
- Review backend against the spec before integrating UI.
Task 2: Dashboard and SDK
Files: dashboard phone-number NumberPoolsSection and related components; agent OutboundCallerSelector; generated SDK. Interfaces: Consume Task 1 schema and existing outbound-trunk listing. Select a custom trunk and verified BYOC members; expose optional Twilio credentials only for replacement, including saved-connection state and secure secret refresh/removal.- Generate SDK via root pnpm gensdk with pinned local/test env.
- Implement BYOC pool setup and accurate responsibility copy; exclude hosted members and trunks.
- Add/run focused UI behavior tests for member/trunk eligibility and replacement credential requirements; typecheck/lint changed dashboard files.
- Review UI and generated contract against backend.
Task 3: Documentation, integration verification and PR
Files: existing affected docs/phone and sequences guides; PR description.- Update guides for BYOC-only eligibility, explicit customer routing, optional Twilio credentials/replacement and unchanged hosted behavior.
- Run frontmatter/schema binding checks and preview affected UI/docs where available.
- Run focused regression checks, inspect final diff, obtain independent whole-change review and resolve material findings.
- Commit/push to existing feature branch and update PR #3714 description; never commit screenshots. Remove or replace obsolete PR screenshots if their claims no longer match.