Add Migadu domain admin with shared lists, compaction, and safer apply.

Build the Go API and React UI for managing domain denylist/allowlist/recipient
deny and spam settings, plus shared lists that import/apply across domains with
wildcard compaction, entry verification, and Migadu-friendly list encoding
(including per-domain recipient filtering and rejection bisect on apply).
This commit is contained in:
2026-07-26 21:50:26 +02:00
parent 930f1f7b69
commit a79cb61104
55 changed files with 7600 additions and 1 deletions
+175
View File
@@ -0,0 +1,175 @@
import { Navigate, Route, Routes } from 'react-router-dom'
import { useAuth } from './auth/AuthContext'
import { DomainsProvider } from './auth/DomainsContext'
import { DomainDetailPage } from './pages/DomainDetailPage'
import { HomePage } from './pages/HomePage'
import { LoginPage } from './pages/LoginPage'
import { RegisterPage } from './pages/RegisterPage'
import { SharedListsPage } from './pages/SharedListsPage'
import { StubPage } from './pages/StubPage'
import type { ReactNode } from 'react'
function Protected({ children }: { children: ReactNode }) {
const { user, loading, status } = useAuth()
if (loading) {
return (
<div className="auth-layout">
<p className="muted">Loading</p>
</div>
)
}
if (!user) {
if (status?.registration_open) {
return <Navigate to="/register" replace />
}
return <Navigate to="/login" replace />
}
if (user.role !== 'admin') {
return (
<div className="auth-layout">
<div className="auth-panel">
<h1>Access denied</h1>
<p className="lede">
Your account is signed in but does not have admin permission for
domain controls.
</p>
</div>
</div>
)
}
return <DomainsProvider>{children}</DomainsProvider>
}
export default function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
<Route
path="/"
element={
<Protected>
<HomePage />
</Protected>
}
/>
<Route
path="/shared-lists"
element={
<Protected>
<SharedListsPage />
</Protected>
}
/>
<Route
path="/domains/:domain/settings"
element={
<Protected>
<DomainDetailPage />
</Protected>
}
/>
<Route
path="/domains/:domain/records"
element={
<Protected>
<StubPage
title="DNS records"
description="View Migadu DNS records for the selected domain."
domainScoped
/>
</Protected>
}
/>
<Route
path="/domains/:domain/diagnostics"
element={
<Protected>
<StubPage
title="Diagnostics"
description="Domain diagnostics from the Migadu API."
domainScoped
/>
</Protected>
}
/>
<Route
path="/domains/:domain/usage"
element={
<Protected>
<StubPage
title="Usage"
description="Domain usage statistics from the Migadu API."
domainScoped
/>
</Protected>
}
/>
<Route
path="/mailboxes"
element={
<Protected>
<StubPage
title="Mailboxes"
description="Manage mailboxes on administered domains."
domainScoped
/>
</Protected>
}
/>
<Route
path="/identities"
element={
<Protected>
<StubPage
title="Identities"
description="Manage mailbox identities."
domainScoped
/>
</Protected>
}
/>
<Route
path="/forwardings"
element={
<Protected>
<StubPage
title="Forwardings"
description="Manage address forwardings."
domainScoped
/>
</Protected>
}
/>
<Route
path="/aliases"
element={
<Protected>
<StubPage
title="Aliases"
description="Manage aliases on administered domains."
domainScoped
/>
</Protected>
}
/>
<Route
path="/rewrites"
element={
<Protected>
<StubPage
title="Rewrites"
description="Manage rewrite rules."
domainScoped
/>
</Protected>
}
/>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
)
}