Repository navigation
Architecture
Dokene starts as a modular monolith in a monorepo.
This is intentional. The product needs strong module boundaries and clear ownership, but it does not yet need the operational cost of distributed services.
The repository contains separately buildable frontend and backend applications:
dokene/
├── backend/
├── frontend/
├── docs/
├── infra/
└── .github/
Frontend and backend are deployed as separate runtime components even though they live in the same repository.
┌──────────────────────┐
│ Web Browser │
└──────────┬───────────┘
│ HTTPS
▼
┌──────────────────────┐
│ React + TypeScript │
│ Frontend │
└──────────┬───────────┘
│ REST / OpenAPI
▼
┌──────────────────────────────────────────────┐
│ Spring Boot modular monolith │
│ │
│ identity tenant customer followup │
│ messaging template ai integration audit │
│ security │
└───────┬────────────────┬─────────────────────┘
│ │
▼ ▼
┌───────────────┐ ┌──────────────────────────┐
│ PostgreSQL │ │ External providers │
│ + RLS │ │ AI / WhatsApp / future │
└───────────────┘ └──────────────────────────┘
The backend is organized around business capabilities rather than only technical layers.
Authentication identity, principals, memberships, and login/session-related boundaries.
Tenant lifecycle, membership, roles, tenant context, and tenant-scoped policy.
Customer profile, contact data, consent state, business relationship metadata, and purchase history ownership.
Follow-up eligibility, timing, candidate selection, recommendation orchestration, and follow-up lifecycle.
Message lifecycle, approval, queueing, send idempotency, provider-independent delivery contracts, and delivery state.
Message templates, versioning, categories, language, provider-template references, and rendered-message provenance.
AI provider abstraction, structured request/response contracts, model invocation, schema validation, bounded retry, and AI-specific telemetry (privacy-safe metrics; see ADR 0019). This module must not own authorization or side-effect policy.
External integration configuration, provider metadata, webhook ingestion boundaries, and secret references. Secrets themselves must not be stored as ordinary plaintext values.
Append-oriented audit records for security-sensitive and externally visible actions.
Cross-cutting security policy, authorization helpers, tenant enforcement, rate-limit/policy integration points, and secure defaults.
Business orchestration should depend on abstractions, not vendor SDKs.
Example:
followup
├──> customer contracts
├──> AI port
└──> messaging port
ai adapter
└──> OpenAI / future provider
messaging adapter
└──> Meta WhatsApp / future provider
The AI module must not directly decide that an external action is authorized.
The messaging provider adapter must not decide business eligibility.
Since Phase 3 the arrow between followup and messaging points the other way: messaging depends on followup (eligibility snapshot, draft grounding, the follow-up touch recorder) and followup never depends on messaging. The audit module's application layer may adapt messaging events into audit records, while audit.domain and audit.persistence stay free of messaging types. ModuleDependencyArchitectureTest (ArchUnit) fails the build when any of these directions is violated (ADR 0023).
A typical follow-up flow is:
Scheduler / operator request
↓
Follow-up candidate query
↓
Eligibility + consent + tenant policy
↓
Context assembly
↓
AI structured recommendation/draft
↓
Schema validation
↓
Action policy / authorization gate
↓
PENDING_APPROVAL
↓
Human approval
↓
Queued send
↓
Messaging provider adapter
↓
Provider webhook / delivery status
↓
Audit + message state update
The frontend uses React + TypeScript and is organized primarily by business feature.
Preferred shape:
frontend/src/
├── app/
├── features/
│ ├── auth/
│ ├── customers/
│ ├── followups/
│ ├── messages/
│ ├── templates/
│ ├── integrations/
│ └── settings/
├── components/
├── api/
└── security/
The frontend is not a security boundary. Tenant isolation and authorization must always be enforced in the backend/database even when the UI hides unavailable actions.
Backend and frontend are separate systems connected through an explicit API contract.
Preferred direction:
Spring backend
↓
OpenAPI specification
↓
Generated/validated TypeScript client/types
↓
React frontend
This minimizes DTO drift and keeps the API contract machine-checkable.
PostgreSQL is the system of record for SaaS business state.
The initial multi-tenant strategy is:
- one shared database;
- one shared application schema;
-
tenant_idon tenant-owned tables; - application-level tenant scoping;
- PostgreSQL Row Level Security as defense in depth.
Scheduled follow-up work must be safe when multiple application instances are running.
Rules:
- do not rely on a single in-memory scheduler lock;
- use database-backed claiming/locking or a coordination mechanism such as a scheduler library designed for clustered execution;
- make send operations idempotent;
- make retries explicit;
- preserve a durable state machine for external messages.
Early deployment may use Docker Compose or a simple platform deployment with:
frontend
backend
postgres
Future separation into services is justified only when there is evidence such as:
- independently scaling workloads;
- strict operational isolation requirements;
- different release cadences;
- team ownership boundaries;
- failure-domain requirements;
- enterprise tenancy requirements.
Microservices are not a roadmap milestone by themselves.
Durable decisions belong in docs/adr/.
The Wiki explains the current system in an accessible form; ADRs record why durable choices were made and what alternatives were rejected.
- Home
- Product Vision
- Architecture
- Security Model
- Multi Tenancy and Data
- AI and Automation
- Messaging and Integrations
- Development Model
- Roadmap
Canonical source: docs/wiki/ in stevdrey/dokene.
Durable decisions: docs/adr/.