Entwicklerhandbuch
Technische Architektur, Feature-Flag-Modell und Provider-Abstraktionen, die Owlat verwendet.
Dieses Handbuch behandelt die technische Architektur und die Entwicklungsmuster, die in Owlat verwendet werden. Owlat ist als eine Menge von Funktionsbereichen aufgebaut (Versand, Empfang, KI, Integrationen, Sicherheit, Zustellbarkeit), die sich eine gemeinsame Plattform teilen — das Convex-Backend, die E-Mail-Rendering-Engine und die Feature-Flag-Registry, die jeden Bereich ein- oder ausschaltet.
Schnellzugriff
Architektur & Kernsysteme
- Architekturüberblick — Systemdesign, Monorepo-Aufbau, Datenfluss
- Feature-Flags — Registry, Abhängigkeitsauflösung, Zuordnung zu Docker-Profilen
- Provider — austauschbare LLM- und E-Mail-/Versand-Provider
- Convex-Backend — Datenbankschema und API-Funktionen
- Authentifizierung — BetterAuth-Integration
- Umgebungsvariablen — vollständige Referenz
Ausgehende E-Mail
- E-Mail-System — Editor, Vorlagen und Versand
- E-Mail-Renderer — Rendering-Engine von Blöcken zu HTML
- E-Mail-Sicherheit — Inhaltsprüfung, Dateivalidierung, URL-Reputation, ClamAV
- MTA-System — ausgehender Mail Transfer Agent
- Wie E-Mail funktioniert — Einführung in SMTP, SPF, DKIM, DMARC
Eingehende E-Mail
- Postbox-Architektur — Schema persönlicher Postfächer, IMAP-Server, App-Passwort-Authentifizierung, ausgehendes Relay
Self-Hosting
- Self-Hosting — Installation auf einem VPS in 10 Minuten
- Self-Hosting-Konfiguration — Umgebungsvariablen und Overrides
- DNS & E-Mail — DNS-Einträge, rDNS, DKIM
- Produktion — Härtung und Tuning
- Wartung — Backups, Upgrades, Observability
Referenz
- Komponentenbibliothek — wiederverwendbare UI-Komponenten
- Scopes — Berechtigungsmodell
- Architekturentscheidungen — ADRs
- Mitwirken — wie Sie zu Owlat beitragen
Entwicklungsumgebung einrichten
Voraussetzungen
- Node.js 22+
- Bun als Paketmanager
- Docker + Docker Compose v2 (für den vollständigen Self-Host-Stack)
Lokale Entwicklung
- Abhängigkeiten installieren:
bun install - Das Convex-Backend starten (läuft dauerhaft weiter):
bun run dev:api - Das Nuxt-Frontend starten:
bun run dev
Umgebungsvariablen
Sowohl das Nuxt-Frontend als auch das Convex-Backend verwenden Umgebungsvariablen zur Konfiguration. Feature-Flags folgen einem Muster aus zwei Variablen: eine Convex-Umgebungsvariable für das Backend und eine NUXT_PUBLIC_*-Variable für das Frontend.
Auf der Seite Umgebungsvariablen finden Sie eine vollständige Referenz samt Einrichtungsanleitungen für Provider, Sicherheit und Analytics.
Kurzreferenz — wesentliche Variablen:
| Variable | Wo | Zweck |
|---|---|---|
BETTER_AUTH_SECRET | Convex | Secret zum Signieren von Sessions |
SITE_URL | Convex | Öffentliche Site-URL für Weiterleitungen |
EMAIL_PROVIDER | Convex | mta, ses, resend, smtp, mandrill oder emailit — kein impliziter Standardwert; nicht gesetzt bedeutet unkonfiguriert und Sendungen werden abgelehnt |
LLM_PROVIDER | Convex | openai (Standard), openrouter, ollama (alle OpenAI-kompatibel) — nur erforderlich, wenn das Flag ai aktiv ist. Ein Claude-Endpunkt ist nur erreichbar, indem Sie LLM_BASE_URL auf einen OpenAI-kompatiblen Proxy richten, nicht durch Setzen von LLM_PROVIDER=anthropic |
UNSUBSCRIBE_SECRET | Convex | HMAC-Secret für Abmelde-Token |
NUXT_PUBLIC_CONVEX_URL | Nuxt .env | URL des Convex-Deployments |
NUXT_PUBLIC_CONVEX_SITE_URL | Nuxt .env | Convex-Site-URL (für die Authentifizierung) |
NUXT_PUBLIC_SITE_URL | Nuxt .env | Öffentliche Site-URL |
Codequalität
bun run typecheck # TypeScript checking
bun run lint # Oxlint
bun run ox:fmt # Format with Oxfmt
Projektstruktur
owlat/
├── apps/
│ ├── web/ # Nuxt 4 dashboard
│ │ └── app/
│ │ ├── components/ # Vue components
│ │ │ └── ui/ # App-specific UI components
│ │ ├── composables/ # Vue composables
│ │ ├── layouts/ # Page layouts
│ │ ├── pages/ # File-based routing
│ │ └── plugins/ # Nuxt plugins
│ ├── api/ # Convex backend
│ │ └── convex/
│ │ ├── _generated/ # Auto-generated (don't edit)
│ │ ├── lib/ # Shared utilities + provider factories
│ │ │ ├── llm/ # LLM helpers
│ │ │ ├── llmProvider.ts # OpenAI-compatible LLM dispatch
│ │ │ ├── sendProviders/ # MTA, Resend, SES senders + routing/dispatch
│ │ │ ├── emailProviders/ # Identity + domain verification (mtaIdentity, sesIdentity, domainVerification)
│ │ │ └── posthog.ts # PostHog analytics
│ │ ├── schema.ts # Database schema
│ │ ├── mail/ # Postbox / mailbox modules
│ │ └── *.ts # API functions
│ ├── mta/ # Outbound Mail Transfer Agent (SMTP sender + scan endpoint)
│ ├── imap/ # IMAP4rev1 server (Postbox personal mail)
│ ├── mail-sync/ # Syncs users' external IMAP/SMTP accounts (IMAP IDLE inbound + outbound relay)
│ ├── setup-cli/ # `owlat-setup` — wizard, feature/pack/env management
│ ├── updater/ # In-place update sidecar
│ ├── docs/ # Nuxt Content documentation
│ ├── marketing/ # Marketing / landing page (Nuxt)
│ ├── desktop/ # Desktop client shell (Tauri)
│ └── code-worker/ # Code-task worker (for `codeWorkTasks`)
├── infra/
│ └── templates/ # Per-instance VPS compose, ACME (lego) sidecar, env template
├── docker-compose.yml # Root self-host stack (web/convex/mta + optional Caddy --profile tls)
├── Caddyfile.example # Reference reverse-proxy config for --profile tls
└── packages/
├── email-builder/ # Vue email editor component
├── email-renderer/ # JSON blocks → HTML renderer
├── email-scanner/ # Email security scanning
├── email-previewer/ # Email preview / compatibility analysis
├── channels/ # Notification channel abstractions
├── shared/ # Shared types, validation, feature flag registry
├── ui/ # Nuxt layer: shared UI components and composables
├── sdk-js/ # Official TypeScript SDK
└── sdk-java/ # Official Java SDK
Zentrale Technologien
| Technologie | Zweck |
|---|---|
| Nuxt 4 | Vue-3-Full-Stack-Framework |
| Convex | Serverloses Echtzeit-Backend |
| BetterAuth | Authentifizierung mit Organisationsunterstützung |
| Tailwind CSS 4 | Utility-First-Styling |
| @owlat/email-renderer | Eigenes Rendering für HTML-E-Mails |
| Hono | HTTP-Framework (MTA-Scan-/Relay-Endpunkte) |
| GroupMQ + Redis | MTA-Job-Queue |
| Caddy | Mitgelieferter HTTPS-Reverse-Proxy für Web/Convex/MTA (--profile tls) |
| lego / ACME | TLS im Self-Hosting über DNS-01 für IMAP-/SMTP-Mail-Zertifikate |
| Docker-Compose-Profile | Optionale Dienste je Feature-Flag |
| Lucide | Icon-Bibliothek |
Muster und Konventionen
Dateibenennung
- Vue-Komponenten:
PascalCase.vue - Composables:
useCamelCase.ts - Convex-Funktionen:
camelCase.ts - Seiten:
kebab-case.vueoder[param].vue
Imports
Verwenden Sie den Alias ~/ für Imports innerhalb der Nuxt-App:
import { useAuth } from '~/composables/useAuth';
Die Feature-Flag-Registry wird in jeder Schicht aus dem Shared-Package importiert:
import { FEATURE_FLAGS, resolveFlags, applyToggle } from '@owlat/shared/featureFlags';
TypeScript
Der gesamte Code ist TypeScript. Verwenden Sie explizite Typen für Funktionsparameter und Rückgabewerte:
function formatDate(timestamp: number): string {
return new Date(timestamp).toLocaleDateString();
}
Fehlerbehandlung
- Frontend:
useToast()für Rückmeldungen an die Nutzerin oder den Nutzer verwenden - Backend:
Errormit aussagekräftigen Meldungen werfen - API: strukturierte Fehlerantworten zurückgeben
// Frontend
const { showToast } = useToast();
try {
await mutation();
showToast('Saved successfully');
} catch (e) {
showToast('Failed to save', 'error');
}
// Backend (Convex)
if (!organizationId) {
throw new Error('Organization not found');
}
Feature-gesteuerte Routen
Seiten, die zu einer schaltbaren Funktion gehören, deklarieren dies über definePageMeta:
definePageMeta({
layout: 'dashboard',
middleware: 'auth',
requiresFeature: 'postbox',
});
Eine globale Middleware leitet auf eine „Funktion deaktiviert“-Seite um, wenn das Flag ausgeschaltet ist. Convex-Queries prüfen das Flag zusätzlich serverseitig, damit ein veralteter Client es nicht umgehen kann.