Outreach Service
@nx/outreachcaptures contact-form inquiries and newsletter subscriptions from the public marketing site. On submission it broadcasts a real-time WebSocket event to admin observation rooms. It is a leaf service with no Kafka and only@nx/coreas an internal dependency.
1. Quick Reference
| Property | Value |
|---|---|
| Package | @nx/outreach |
| Code | SVC-00110-OUTREACH ⚠️ collides with @nx/licensing (SVC-00110); not registered in core ServiceCodes |
| Type | Microservice |
| Runtime | Bun |
| Base Class | VerifierApplication |
| Location | packages/outreach |
| Base Path | /v1/api/outreach |
| Dev Port | 31110 |
| Container Port | 3000 (external 31110) |
| Snowflake ID | 10 |
| DB Schema | outreach (2 tables: Inquiry, Subscriber) |
| Binding Namespace | @nx/outreach |
| Owner | outreach-team |
2. Purpose & Scope
| Included | Excluded |
|---|---|
| Capture contact / sales / demo / partner inquiries | Email delivery / SMTP (no mail component) |
| Newsletter subscribe / unsubscribe (idempotent) | Kafka event publishing (none) |
| Subscriber statistics for admin dashboard | CRM pipeline automation (manual via CRUD fields) |
| Real-time WebSocket notification on new inquiry | Multi-tenant merchant scoping (global tables) |
3. Tech Stack
External:
| Library | Purpose |
|---|---|
@venizia/ignis | IoC container, DI, BaseService, ControllerFactory, VerifierApplication |
@venizia/ignis-helpers | WebSocketEmitter, HTTP, env helpers |
hono | HTTP server framework (via IGNIS) |
@hono/zod-openapi | Route schemas → OpenAPI spec |
@scalar/hono-api-reference | /doc interactive viewer |
drizzle-orm | DB access via PostgresCoreDataSource |
pg | PostgreSQL driver |
Internal:
| Package | Purpose |
|---|---|
@nx/core | All schemas/repositories (Inquiry, Subscriber), VerifierApplication, BaseSocketEventService, Redis factory, migration loader, permission/role/policy repositories |
@nx/coreis the only internal dependency. No sister-service clients.
4. Project Structure
packages/outreach/
├── src/
│ ├── application.ts # Application extends VerifierApplication
│ ├── index.ts # Entry → bootstrapApplication()
│ ├── migrate.ts # Migration entry → bootstrapMigration()
│ ├── common/ # RestPaths, constants, keys
│ ├── components/
│ │ └── websocket/ # ApplicationWebSocketComponent + OutreachSocketEventService
│ ├── controllers/
│ │ ├── inquiry/ # InquiryController (+ /submit)
│ │ ├── subscriber/ # SubscriberController (+ subscribe/unsubscribe/statistics)
│ │ └── permissions.ts # OutreachPermissions (CRUD perms for both entities)
│ ├── datasources/ # PostgresCoreDataSource binding
│ ├── errors/ # SubscriberErrors, WorkerErrors
│ ├── migrations/processes/ # 0001 seed-permissions, 0002 seed-role-permissions
│ ├── repositories/ # SubscriberRepository (custom getStatistics) + re-exports
│ └── services/ # SubscriberService
├── package.json
└── tsconfig.json5. Architecture
Detail: see Architecture.
6. Domain Snapshot
No foreign keys between entities — both are independent capture tables. Full ERD + per-entity tables: see Domain Model.
7. Surface Summary
REST controllers (full reference rendered live from /v1/api/outreach/doc/openapi.json):
| Controller | Base path | Endpoints |
|---|---|---|
InquiryController | /inquiries | 7 (CRUD + /submit) |
SubscriberController | /subscribers | 9 (CRUD + /subscribe, /unsubscribe, /statistics) |
Async topics (full reference in API Events):
| Direction | Count |
|---|---|
| Inbound (Kafka) | 0 (none) |
| Outbound (Kafka) | 0 (none) |
| WebSocket out | 1 (INQUIRY_SUBMITTED) |
| BullMQ jobs in | 0 |
| BullMQ jobs out | 0 |
8. Components
| Component | File | Purpose |
|---|---|---|
ApplicationWebSocketComponent | src/components/websocket/component.ts | Builds Redis-backed WebSocketEmitter (single/cluster), binds it, registers OutreachSocketEventService |
9. Services
| Service | File | One-liner |
|---|---|---|
SubscriberService | src/services/subscriber.service.ts | Idempotent subscribe, token-based unsubscribe, statistics aggregation |
OutreachSocketEventService | src/components/websocket/socket-event.service.ts | Broadcasts INQUIRY_SUBMITTED to observation rooms (bound by component, not in configureServices) |
10. Repositories
| Repository | Table | Source | Custom Methods |
|---|---|---|---|
InquiryRepository | outreach.Inquiry | @nx/core (re-export) | — |
SubscriberRepository | outreach.Subscriber | extends core repo | getStatistics() — single-query rollup (total / monthlyNew / by-status) |
11. Entry Points
| File | Purpose |
|---|---|
src/index.ts | Service entry → bootstrapApplication() |
src/migrate.ts | Migration entry → bootstrapMigration() |
src/application.ts | Application class extending VerifierApplication |
12. Configuration
Env vars + feature flags + seeded data: see Configuration.
13. Operations
Deployment + observability + security + runbook: see Operations.
14. Related Pages
- Architecture
- Domain Model
- API Events
- Integration
- Configuration
- Operations
- Decisions
- REST endpoints — live OpenAPI at
/v1/api/outreach/doc/openapi.json