103 lines
4.8 KiB
Markdown
103 lines
4.8 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# 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:
|
|
```php
|
|
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.
|