mailwolt/CLAUDE.md

4.8 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

# Development (starts PHP server + queue + logs + Vite concurrently)
composer dev

# Build assets for production
npm run build

# Vite dev server only
npm run dev

# Run all tests
composer test
php artisan test

# Run a single test file
php artisan test tests/Feature/ExampleTest.php

# Run a single test by name
php artisan test --filter=TestName

# Migrations
php artisan migrate

Architecture

Design

  • Tailwind CSS v4
  • Modals sind immer vom Livewire Modals
  • Kein Inline-Style nur wenn wirklich notwendig.
  • Immer prüfen das das Style nicht kaputt ist und wenn Icons in Buttons mit Text sind, sind diese immer nebeneinadner Nie übereinander.

What this is

Mailwolt is a self-hosted mail server administration panel (German UI). It manages domains, mailboxes, aliases, DNS records (DKIM/DMARC/SPF/TLSA), TLS, Fail2ban, IMAP, and email quarantine/queues. It also has a mail sandbox for testing Postfix transports.

Layout & Routing

  • resources/views/layouts/dvx.blade.php is the actual app layout (not app.blade.php). Livewire full-page components use #[Layout('layouts.dvx')].
  • Routes are in routes/web.php — each page maps directly to a Livewire full-page component via ->name().
  • Navigation structure is driven by config/ui-menu.php.
  • Für den Style wird Tailwind CSS v4

Livewire component structure

app/Livewire/Ui/
├── Nx/          — Current production UI (Dashboard, DomainList, MailboxList, AliasList, etc.)
├── Domain/      — Domain modals and DKIM/DNS views
├── Mail/        — Mailbox/alias modals, queue, quarantine
├── Security/    — Fail2ban, SSL, RSpamd, TLS, audit logs
├── System/      — Settings, users, API keys, webhooks, sandbox, backups
├── Search/      — Global search palette modal
└── Webmail/     — Webmail-specific components

Full-page components live in Ui/Nx/ and Ui/System/, Ui/Security/, etc. Modals are always in a Modal/ subfolder and extend LivewireUI\Modal\ModalComponent.

Modals (wire-elements/modal v2)

  • Open from outside a Livewire component: onclick="Livewire.dispatch('openModal', {component:'ui.system.modal.my-modal', arguments:{key:value}})"
  • Open from inside a Livewire component: $this->dispatch('openModal', component: '...', arguments: [...])
  • Never use wire:click="$dispatch('openModal',...)" outside a Livewire component context — it won't work.
  • Modal argument keys must match the mount(int $keyName) parameter names exactly.
  • To prevent closing on backdrop/Escape, override in the modal class:
    public static function closeModalOnClickAway(): bool        { return false; }
    public static function closeModalOnEscape(): bool           { return false; }
    public static function closeModalOnEscapeIsForceful(): bool { return false; }
    
  • To force-close the entire modal stack: $this->forceClose()->closeModal()

Livewire dependency injection

  • Never use constructor injection in Livewire components — Livewire calls new Component() with no args.
  • Use boot(MyService $service) instead: this is called on every request and supports DI.

CSS design system

The app uses a custom mw-* variable and class system defined in resources/css/app.css (Tailwind CSS v4, no tailwind.config.js):

CSS variables:

  • --mw-bg, --mw-bg3, --mw-bg4 — background layers
  • --mw-b1, --mw-b2, --mw-b3 — border shades
  • --mw-t1 through --mw-t5 — text shades (t1 = primary, t4/t5 = muted)
  • --mw-v, --mw-v2, --mw-vbg — purple accent (primary brand color)
  • --mw-gr — green (success)

Reusable component classes: .mw-btn-primary, .mw-btn-secondary, .mw-btn-cancel, .mw-btn-save, .mw-btn-del, .mbx-act-btn, .mbx-act-danger, .mw-modal-frame, .mw-modal-head, .mw-modal-body, .mw-modal-foot, .mw-modal-label, .mw-modal-input, .mw-modal-error, .mbx-badge-mute, .mbx-badge-ok, .mbx-badge-warn.

Services

app/Services/ contains: DkimService, DnsRecordService, ImapService, MailStorage, SandboxMailParser, SandboxService, TlsaService, TotpService, WebhookService.

API

REST API under /api/v1/ uses Laravel Sanctum. Token abilities map to scopes like mailboxes:read, domains:write, etc. Defined in routes/api.php.

Sandbox mail system

The mail sandbox intercepts Postfix mail via a pipe transport (php artisan sandbox:receive). SandboxRoute model controls which domains/addresses are intercepted. SandboxService::syncTransportFile() writes /etc/postfix/transport.sandbox and runs postmap.

Queue & real-time

  • Queue driver: database (configurable). Jobs in app/Jobs/.
  • Real-time updates use Laravel Reverb + Pusher.js. Livewire polls (wire:poll.5s) are used as fallback on some pages.