Aller au contenu principal

Architecture

ProBeya is built as a modern, multi-tenant SaaS platform using a TypeScript-first monorepo architecture. This page provides an overview of the system components and how they interact.

High-Level Architecture​

Browser / API client
|
| HTTPS: pages, Server Actions, tRPC, REST
v
Next.js 16 `web` (port 8000)
- React 19 application and Auth.js
- API routes from packages/api
- durable item-event outbox worker
|
+--------------------+
| |
v v
PostgreSQL 16 Redis 7
(Drizzle + FORCE RLS) (cache and pub/sub)
|
v
S3-compatible storage (private attachments)

Browser -- WSS --> `ws` (Node.js, port 8003) -- Redis pub/sub
Nginx (80/443) routes web, ws, docs, and file-storage hostnames

Technology Stack​

LayerTechnology
FrontendNext.js 16, React 19, TailwindCSS 4, shadcn/ui, Zustand
APItRPC v11 inside Next.js, Server Actions, Zod validation
DatabasePostgreSQL 16, Drizzle ORM, FORCE RLS
Cache / PubSubRedis 7
AuthAuth.js v5 (JWT sessions and optional OIDC)
File StorageS3-compatible (MinIO for local dev)
MonorepoTurborepo, pnpm workspaces
LanguageTypeScript 5.8 throughout

Multi-Tenancy​

ProBeya uses a shared database, shared schema multi-tenancy model:

  • Every tenant-scoped table includes an organization_id column.
  • Authenticated tenant procedures derive the organization from trusted session and membership state, then set transaction-local database context.
  • Canonical FORCE ROW LEVEL SECURITY policies restrict the probeya_app runtime role at the database level.
  • Tenant isolation is enforced at both the application and database layers.

Locale-Aware Subdomain Resolution​

The middleware supports locale-suffixed subdomains using the pattern {slug}-{locale}.probeya.com. The last hyphen-separated segment is checked against the supported locales (en, fr, nl, de, it, es, pt, ja, ko, zh, ar, ru, id). If it matches, the prefix becomes the tenant slug and the suffix becomes a locale override:

SubdomainResolved TenantLocale Override
acmeacme— (browser/cookie)
acme-fracmefr
my-companymy-company— (browser/cookie)
my-company-demy-companyde

Locale priority: subdomain suffix > NEXT_LOCALE cookie > Accept-Language header > default (en). The subdomain locale also persists into the cookie so subsequent visits to the plain subdomain retain the language choice.

Monorepo Structure​

probeya/
├── apps/
│ ├── web/ # Next.js UI plus tRPC/HTTP runtime
│ ├── ws/ # Node.js WebSocket service
│ ├── docusaurus-docs/ # Product/operator documentation
│ └── mintlify-docs/ # Developer documentation source
├── packages/
│ ├── api/ # tRPC routers and business logic
│ ├── db/ # Drizzle schema and database operations
│ ├── shared/ # Shared validators, constants, and types
│ ├── ui/ # Shared UI components
│ └── config/ # Shared TypeScript and lint configuration
└── docker/ # Docker and compose files

Data Flow​

  1. Client sends a request to the Next.js application.
  2. Next.js/tRPC middleware validates the session, resolves the organization, and checks permissions.
  3. tRPC router dispatches to the appropriate procedure handler.
  4. Service layer executes business logic, reads/writes the database via Drizzle ORM.
  5. Durable item events are committed to the PostgreSQL outbox in the same transaction as the mutation; the worker dispatches internal and external side effects with retries. Redis pub/sub carries realtime fan-out.
  6. Response is returned to the client with full type safety.

Real-Time Updates​

Real-time collaboration is powered by WebSocket connections:

  1. Clients establish a WebSocket connection on page load.
  2. The server publishes events to Redis PubSub when data changes.
  3. The WebSocket server subscribes to relevant channels and pushes updates to connected clients.
  4. The client applies optimistic updates and reconciles with server state.

See the Real-Time guide for implementation details.

ADR-016 Offline/PWA Strategy​

ProBeya treats offline resilience as a first-class product requirement for shop-floor and pharma/manufacturing use cases where connectivity is not always reliable.

  • The web app uses a Progressive Web App strategy for installability and offline shell behavior.
  • Edge-aware and offline-safe workflows prefer queued synchronization over direct online-only writes.
  • Local caches and sync queues are designed to preserve tenant isolation and replay mutations safely once connectivity returns.

This ADR drives the broader offline architecture described in the PWA Offline guide.

ADR-023​

ProBeya's AI architecture is designed around controlled, auditable assistance instead of opaque autonomous behavior.

  • AI features run behind explicit server-side orchestration and validation layers.
  • Tenant boundaries, permissions, and business rules still apply to AI-driven suggestions and document analysis flows.
  • AI outputs are treated as assistive recommendations that require product and user-visible review paths when the workflow is sensitive.

This ADR informs the implementation approach described in the AI Insights guide.

Phase 4: Integration & API Layer Architecture​

Phase 4 introduces a comprehensive external integration layer, enabling ProBeya to exchange data with enterprise systems (SAP, MES, QMS, LIMS) and third-party automation platforms (Zapier, Make, Slack, Teams).

Architecture Overview​

External Systems ProBeya Platform
┌──────────────┐ ┌──────────────────────┐
│ SAP / MES │──── API Key ────│ REST API (tRPC) │
│ QMS / LIMS │ Auth (Bearer) │ /api/v1/* │
│ Custom ETL │ │ │
└──────────────┘ │ ┌─ Ingest Router ─┐ │
│ │ Batch upsert │ │
┌──────────────┐ │ │ Audit logging │ │
│ Zapier/Make │──── Webhooks ───│ │ Threshold eval │ │
│ Slack/Teams │ (outgoing) │ └─────────────────┘ │
│ PagerDuty │ │ │
└──────────────┘ │ ┌─ Webhook Engine ┐ │
│ │ HMAC-SHA256 │ │
│ │ 3x retry │ │
│ │ Delivery log │ │
│ └─────────────────┘ │
└──────────────────────┘

Key Components​

ComponentPackageDescription
API Keyspackages/db/src/schema/api-keys.tsBearer token auth with bcrypt hash storage, scopes, rotation
Webhookspackages/db/src/schema/webhooks.tsHMAC-SHA256 signed outgoing events, 3x exponential backoff
Integrationspackages/api/src/routers/integrations.tsSlack & Teams incoming webhook notifications
Ingest Routerpackages/api/src/routers/ingest.tsBatch KPI data ingestion from external systems
Ingest Logpackages/db/src/schema/ingest-log.tsImmutable audit trail for all ingestion attempts
Item Event Outboxpackages/db/src/schema/item-event-outbox.tsTransactional source of item side effects
Outbox Workerpackages/api/src/workers/item-event-outbox-worker.tsClaimed delivery with retries and idempotency metadata
Webhook Senderpackages/api/src/lib/webhook-sender.tsSigned HTTP delivery and delivery logging

API Key Authentication​

API keys use a prefix-based lookup strategy for efficient authentication:

  1. Key format: probeya_sk_live_{40 random hex chars}
  2. Storage: Only the bcrypt hash + 8-char prefix are stored in the database
  3. Lookup: Extract prefix from incoming key, query by prefix + orgId, then bcrypt.compare
  4. Scopes: JSONB array restricting operations (e.g., ["read:kpis", "write:kpis"])

Webhook Delivery Pipeline​

Item mutations use a transactional outbox so a successful write cannot lose its required automation, notification, integration, or webhook side effects:

  1. The item mutation and versioned outbox event commit in the same PostgreSQL transaction.
  2. The production web process claims pending events with bounded locks.
  3. Internal effects run in tenant context before external delivery.
  4. External deliveries receive stable event/idempotency metadata and are retried with backoff.
  5. Failed events remain observable in the outbox instead of being silently dropped.

KPI Ingestion Flow​

The ingest endpoint (POST /api/v1/ingest/batch) processes external KPI data:

  1. Authentication: API key with write scope required
  2. Validation: Zod schema validates batch payload (max 500 items)
  3. Resolution: Each KPI is resolved within the caller's org context (tenant isolation)
  4. Upsert: Values are inserted/updated using INSERT ... ON CONFLICT DO UPDATE
  5. Audit: Every attempt (success/failure) is logged to ingest_log
  6. Events: kpi.value_entered webhook dispatched for each value
  7. Alerts: Threshold evaluation triggers kpi.threshold_breached webhooks

API Versioning Strategy​

ProBeya uses URL path versioning (/api/v1/, /api/v2/) with an additive change policy:

  • Non-breaking changes (new fields, new endpoints) are added to the current version
  • Breaking changes (removed fields, changed types) require a new version
  • Sunset header: Deprecated versions include Sunset: {date} in response headers
  • Migration window: Minimum 6 months between deprecation and removal

See the API Reference page for current endpoint conventions.