Two Platforms, One Vision
Kasha operates two distinct codebases: KashaCH (Heidi) — a full-stack Vite+Express monolith serving the Swiss CSP market — and the Kasha Platform — a 33-repo NestJS microservices architecture for the global SMB/Enterprise play. Both serve overlapping customers. Both need KYC, payments, CRM, and compliance. Building each twice is not an option.
The Challenge
- Two separate tech stacks (Vite/Express vs NestJS microservices)
- Different databases (Drizzle/PostgreSQL vs TypeORM/PostgreSQL)
- Duplicated business logic across platforms
- No shared identity for KYC, compliance, or onboarding
- Enterprise customers span both platforms
The Pattern
- Middleware Connector: standalone REST gateway per domain
- Shared library extracts provider-agnostic business logic
- TypeORM adapters bridge to shared PostgreSQL
- Both platforms consume the same REST API
- One truth, two consumers, zero duplication
The Middleware Connector Pattern
A Middleware Connector is a thin, standalone NestJS REST API that owns a single business domain. It sits between both platforms, providing a unified interface while the shared library encapsulates all provider logic, data models, and orchestration.
PLATFORM UNITY — MIDDLEWARE CONNECTOR PATTERN ──────────────────────────────────────────────────────────────── KashaCH (Heidi) Kasha Platform Swiss CSP Monolith Global Microservices Vite + Express + Drizzle NestJS + TypeORM + RabbitMQ company-formation.letscodenow.app app.kasha.io | | | HTTP REST | +──────────────┐ ┌──────────────────+ | | v v ┌──────────────────────────────┐ │ MIDDLEWARE CONNECTOR │ │ Standalone REST Gateway │ │ │ │ NestJS · Port 3001 · Docker │ │ Health checks · CI/CD │ └───────────────┬──────────────┘ | uses (npm link) | ┌───────────────┴──────────────┐ │ SHARED LIBRARY │ │ @kasha/kyc-service (GitHub) │ │ │ │ Orchestrator · Providers │ │ Store Interfaces · DTOs │ │ Events · Config · Enums │ └───────────────┬──────────────┘ | adapters (TypeORM) | ┌───────────────┴──────────────┐ │ SHARED POSTGRESQL │ │ Database: kyc_connector │ │ 10 tables · UUID PKs · JSONB │ │ Snake_case · Cascade deletes │ └──────────────────────────────┘ | external API | ┌───────────────┴──────────────┐ │ EXTERNAL PROVIDER │ │ SumSub (prod) / Mock (dev) │ │ Auto-detected from env vars │ └──────────────────────────────┘
Three Repos, Clear Boundaries
Each repo has a single responsibility. The shared library is the brain, the connector is the body, and the platform service is the existing consumer that gets upgraded.
Layered Design
The connector follows a clean layered architecture with dependency injection throughout. Each layer has a single concern and can be swapped independently.
REST Endpoints
All endpoints are under /api/kyc. Both platforms consume the same API — KashaCH via direct HTTP calls, Kasha Platform via the internal Docker network.
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /applicants | Create verification — register applicant with provider |
| GET | /applicants/:id | Get applicant record by provider ID |
| POST | /applicants/:id/link | Generate verification link (with TTL) |
| POST | /applicants/:id/token | Get Web SDK access token for frontend embed |
| POST | /applicants/:id/check | Request verification check from provider |
| POST | /applicants/:id/sync | Sync status from provider to local database |
| GET | /applicants/:id/documents | List uploaded documents for applicant |
| GET | /business/:businessId | Get all applicants for a business entity |
| POST | /webhook | Receive provider webhooks (HMAC validated) |
| GET | /admin/applicants | List applicants (paginated, filterable) |
| GET | /healthz/ready | Database connectivity health check |
Zero-Config Provider Switching
The connector auto-detects whether real SumSub credentials are present. If the token is missing or set to dev-placeholder, it seamlessly falls back to a mock provider — no code changes, no feature flags, no conditional logic in business code.
// kyc-orchestrator.provider.ts — automatic provider selection function isRealSumsubToken(token: string | undefined): boolean { if (!token || token.trim() === '') return false; if (token === 'dev-placeholder') return false; return true; } // Result: SumsubProvider in production, MockKycProvider in dev // MockKycProvider auto-approves, simulates latency, returns test data const provider = useSumsub ? new SumsubProvider({ apiUrl, apiToken, apiSecret, webhookSecret }) : new MockKycProvider({ latencyMs: 100, autoApproveOnCheck: true });
10-Entity Schema
The connector manages its own database (kyc_connector) on the shared PostgreSQL instance. Entities cover the full KYC lifecycle — from initial applicant creation through document uploads, risk scoring, review, and proof of address verification.
Applicant (main record — business_id indexed) | +── 1:1 ── ApplicantPersonalInfo name, dob, nationality, id docs (JSONB) +── 1:1 ── ApplicantCompanyInfo company name, reg number, beneficiaries (JSONB) +── 1:1 ── ApplicantReview review status, level, priority | +── 1:1 ── ApplicantReviewResult GREEN/YELLOW/RED, reject labels +── 1:1 ── ApplicantRiskLabel risk signals: email, phone, device, AML +── 1:1 ── ApplicantPoaResult proof of address review outcome +── 1:N ── ApplicantDocument[] 28+ doc types, metadata, GPS coords (CASCADE) +── 1:N ── ApplicantNote[] internal notes, created_by (CASCADE) +── 1:N ── ApplicantRiskMatrix[] 4 types x 13 factors, scored + blocked (CASCADE)
Docker + GitHub Actions CI/CD
The connector deploys as a standalone Docker container via GitHub Actions. Push to main triggers SSH deploy to VPS — pull, build, start, health check, clean up. Zero-downtime with automatic rollback on failure.
# docker-compose.yml — joins shared VPS network services: kyc-connector: build: . ports: "127.0.0.1:3002:3001" networks: kasha-network (external) healthcheck: /healthz/ready every 15s # deploy-dev.yml — GitHub Actions on: push to main steps: clone → pull → build → up -d → health check → prune
Repeatable for Every Shared Domain
KYC is the first connector. The same pattern applies to every domain that both platforms need. Each connector follows the same structure: shared library + middleware gateway + platform consumer.
KYC Connector
Identity verification, document uploads, risk scoring, SumSub integration. Proof of concept for the pattern.
BuiltPayments Connector
Unified payment processing — Stripe, TWINT, PIX. Shared transaction ledger, settlement rules, refund flows.
Next UpCRM Connector
Shared customer records, contact sync, interaction history. One customer view across both platforms.
PlannedCompliance Connector
AML screening, sanctions checks, regulatory reporting. Shared compliance engine across jurisdictions.
PlannedNotifications Connector
Unified email, SMS, push. Template engine, delivery tracking, preference management.
PlannedBilling Connector
Subscription management, invoice generation, usage metering. Shared billing across all products.
PlannedThe Formula
For any shared domain: (1) Extract business logic into a provider-agnostic shared library on GitHub. (2) Build a thin NestJS middleware connector that implements store adapters and exposes REST endpoints. (3) Both platforms consume the connector's API — same data, same rules, zero duplication. (4) Deploy as a standalone Docker container on the shared network with CI/CD. Each connector is independently deployable, testable, and scalable.