@cincoai/vox-api
v0.1.0
Published
NestJS library for Vox campaign management (contributor responses, manager synthesis, sharing)
Readme
@cincoai/vox-api
NestJS library for the Vox organizational voice campaign system: catalog (packs, items, policies), contributor responses, manager synthesis, sharing, cron notifications, and REST agent endpoints.
Installation
npm install @cincoai/vox-apiPeer dependencies (install in the host app):
npm install @nestjs/common @nestjs/core @nestjs/graphql @nestjs/mongoose \
@nestjs/config @nestjs/schedule @nestjs/event-emitter @nestjs/platform-express \
@nestjs/swagger @nestjs/axios mongoose graphql graphql-subscriptions dataloader \
class-validator class-transformer rxjs reflect-metadata graphql-scalarsQuick integration
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { GraphQLModule } from '@nestjs/graphql';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { ScheduleModule } from '@nestjs/schedule';
import {
VoxManagementModule,
VoxDataLoaderFactory,
PUBSUB_PROVIDER,
} from '@cincoai/vox-api';
@Module({
imports: [
MongooseModule.forRoot(process.env.MONGODB_URI!),
EventEmitterModule.forRoot(),
ScheduleModule.forRoot(),
HostModule,
VoxManagementModule.forRoot({ imports: [HostModule] }),
GraphQLModule.forRootAsync({
inject: [VoxDataLoaderFactory, PUBSUB_PROVIDER],
useFactory: (loaderFactory: VoxDataLoaderFactory, pubSub) => ({
autoSchemaFile: true,
subscriptions: { 'graphql-ws': true },
context: ({ req, extra }) => ({
req: req ?? extra?.request,
loaders: loaderFactory.create(),
pubSub,
}),
}),
}),
],
})
export class AppModule {}The host must provide port implementations (VOX_IDENTITY_PORT, VOX_AUTHORIZATION_PORT, …) — see exemples/vox-demo/INTEGRATION.md.
Host prerequisites
Integration ports (required)
The package does not store host users. Implement and register:
| Token | Responsibility |
|-------|----------------|
| VOX_IDENTITY_PORT | Resolve users by host id / external id (Keycloak sub) |
| VOX_AUTHORIZATION_PORT | Global VOX roles, roleCode, admin checks |
| VOX_MEMBERSHIP_PORT | Source user↔org memberships (optional listAll for sync) |
| VOX_ORG_MIGRATION_PORT | Export host organization tree for initial import |
Reference adapters: exemples/vox-demo/apps/api/src/host/adapters/.
Authentication guards
Resolvers use decorators exported by this package:
@Public()— skip auth (e.g. subscriptions with server-side filter)@Roles({ roles: [UserRole.user] })— role check@ApiKeyAllowed()— REST agent endpoints (/vox-manager/*)
The host app must register global guards that read these metadata keys (same pattern as owliance CustomAuthGuard / CustomRoleGuard).
MongoDB collections
The library registers Mongoose models for:
| Collection area | Models |
|-----------------|--------|
| Vox domain | VoxCampaign, VoxPack, VoxItem, VoxQuestion, VoxPolicy, VoxResponse, VoxManagerShare, … |
| Package-owned | Organization (with externalId), VoxMembership (cache), NotificationRecord, File |
Run VoxOrganizationImportService.runFullMigration() after seeding host data to import organizations and sync memberships.
Notifications (optional)
Campaign and share services emit NOTIFICATION_CREATED_EVENT via EventEmitter2. Listen in the host app:
The event payload is a plain object whose shape depends on the emitting
service (it always includes at least a type discriminator):
import { OnEvent } from '@nestjs/event-emitter';
import { NOTIFICATION_CREATED_EVENT } from '@cincoai/vox-api';
@OnEvent(NOTIFICATION_CREATED_EVENT)
handleNotification(payload: { type: string; [key: string]: unknown }) {
// route to your NotificationModule
}Real-time subscriptions
Subscription voxResponseItemUpdated requires pubSub in the GraphQL context (see integration example above).
Environment variables
File uploads (attachments)
| Variable | Description |
|----------|-------------|
| AWS_S3_ENDPOINT | S3 endpoint (default: s3.amazonaws.com) |
| AWS_ACCESS_KEY_ID | AWS access key |
| AWS_SECRET_ACCESS_KEY | AWS secret |
| AWS_REGION | AWS region (default: us-east-1) |
| AWS_S3_BUCKET | Bucket name |
| MINIO_ENDPOINT, MINIO_PORT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET | MinIO alternative |
Manager AI synthesis (optional)
| Variable | Description |
|----------|-------------|
| TASK_FRAMEWORK_ENDPOINT | Task Framework base URL |
| TASK_FRAMEWORK_ADMIN_API_KEY | API key for thread creation |
| TASK_FRAMEWORK_APP_ID | App ID sent in synthesis requests |
Without Task Framework configuration, synthesis mutations will fail at runtime.
Public API
export {
VoxManagementModule,
VoxModule,
VoxRoleModule,
VoxService,
VoxRoleService,
VoxDataLoaderFactory,
Public, Roles, Resource, AuthenticatedUser, AuthToken,
ApiKeyAllowed, ApiKeyOnly, TrackApiCall,
PUBSUB_PROVIDER,
PUB_SUB_TRIGGERS,
NOTIFICATION_CREATED_EVENT,
};REST endpoints
| Prefix | Purpose |
|--------|---------|
| POST /vox-response-attachments/upload | Contributor file upload (JWT) |
| GET/POST /vox-manager/* | AI agent context and synthesis payloads (API key) |
Development
npm install
npm run build
npm testMigration
src/migrations/vox-campaign-access-init.ts initializes VoxCampaignAccess from existing campaigns and shares.
Note: migration scripts are not shipped in the published package (they are excluded from the build). Run them from a checkout of this repository with
MONGODB_URIset:
MONGODB_URI=mongodb://localhost:27017/mydb \
npx ts-node -r tsconfig-paths/register src/migrations/vox-campaign-access-init.tsPackage structure
src/
├── vox/ # Core Vox module (resolvers, services, DTOs)
├── vox-role/ # VoxRole CRUD
├── schemas/ # Mongo + GraphQL entity definitions
├── enums/
├── infrastructure/ # Decorators, pubsub, dataloaders, types
├── adapters/ # Pluggable file, user, synthesis integrations
└── migrations/Replacing adapters
Default adapters are sufficient for standalone use. Override in the host app:
@Module({
imports: [
VoxManagementModule,
// your custom FileModule / UserModule
],
})
export class AppModule {}Use NestJS module overrides if you need custom FileService or UserService implementations.
