feat(PROJ-30): Xapian → Manticore Search Migration

- internal/index/manticore.go: ManticoreTenantManager + manticoreIndex (RT-Indizes, CGO-frei)
- internal/index/index.go: TenantIndexer Interface (Xapian + Manticore)
- internal/index/tenant_worker.go: mgr-Typ auf TenantIndexer Interface
- internal/api/server.go: idxMgr auf TenantIndexer Interface
- config/config.go: IndexConfig.ManticoreDSN Feld
- cmd/archivmail/cmd_reindex.go: reindex Subkommando
- cmd/archivmail/main.go: Manticore-Branch + reindex Case
- go.mod: github.com/go-sql-driver/mysql v1.8.1
- update.sh: Manticore auto-install, CGO_ENABLED=0, config.yml migration, auto-reindex

fix(IMAP): TCP-Deadline-Wrapper für steckengebliebene Imports
fix(auth): Email-Claim in JWT für User-Isolation
fix(search): User-Isolation via sess.Email (fail-safe)
fix(ui): Admin-Login Auth-Cache, Logout-Redirect, IMAP-Polling-Resilienz

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-04-03 21:19:36 +02:00
co-authored by Claude Sonnet 4.6
parent e90d588e30
commit a93a843506
19 changed files with 742 additions and 65 deletions
+14 -3
View File
@@ -3,7 +3,7 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { login } from "@/lib/api";
import { getCachedUser } from "@/lib/auth-cache";
import { getCachedUser, setCachedUser, clearAuthCache } from "@/lib/auth-cache";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -32,12 +32,14 @@ export default function LoginPage() {
setLoading(true);
try {
clearAuthCache();
const res = await login(username, password);
const role = res?.user?.role ?? "";
if (ADMIN_ROLES.includes(role)) {
setError("Admins und Auditoren bitte über /admin anmelden.");
setError("ADMIN_REDIRECT");
return;
}
setCachedUser({ username: res.user.username, email: res.user.email, role });
router.push("/search");
} catch {
setError("Anmeldung fehlgeschlagen. Bitte Zugangsdaten pruefen.");
@@ -83,11 +85,20 @@ export default function LoginPage() {
aria-label="Passwort"
/>
</div>
{error && (
{error && error !== "ADMIN_REDIRECT" && (
<p className="text-sm text-destructive" role="alert">
{error}
</p>
)}
{error === "ADMIN_REDIRECT" && (
<p className="text-sm text-destructive" role="alert">
Admins und Auditoren bitte{" "}
<a href="/admin/login" className="underline font-medium">
hier anmelden
</a>
.
</p>
)}
<Button type="submit" className="w-full" disabled={loading}>
{loading ? "Anmelden..." : "Anmelden"}
</Button>