feat: fix signature editor init and expand README
Build and Push Multi-Platform Images / build-and-push (push) Successful in 18s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 18s
- Pass initialContent prop to WysiwygEditor instead of imperative setContent to ensure mail signature loads correctly on mount - Rewrite README to reflect full project scope (scanner inbox, email import, postprocessing rules, label printing, OIDC auth) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,80 @@
|
|||||||
# Paperless Manager
|
# Paperless Manager
|
||||||
|
|
||||||
Ein Erweiterungstool für Paperless-ngx zur automatisierten Verarbeitung von E-Mails und Dokumenten.
|
Eine Erweiterungsplattform für [Paperless-NGX](https://github.com/paperless-ngx/paperless-ngx) zur automatisierten Dokumentenverarbeitung – von der Scanner-Eingangsbox bis zur regelbasierten Ablage.
|
||||||
|
|
||||||
|
## Was ist Paperless Manager?
|
||||||
|
|
||||||
|
Paperless-NGX ist ein leistungsstarkes DMS, bietet aber wenig Automatisierung beim Erfassen und Verarbeiten eingehender Dokumente. Paperless Manager schließt diese Lücke:
|
||||||
|
|
||||||
|
- Dokumente kommen per Scanner, E-Mail oder Dateiablage herein
|
||||||
|
- Sie werden aufbereitet, gesplittet, per OCR erkannt und klassifiziert
|
||||||
|
- Regelwerke entscheiden automatisch über Tags, Export und Weiterleitung
|
||||||
|
- Etiketten werden direkt aus dem System heraus gedruckt
|
||||||
|
|
||||||
|
Der Paperless Manager läuft als eigenständige Anwendung neben Paperless-NGX und kommuniziert über dessen REST API.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Automatischer E-Mail Import mit Barcode-Erkennung
|
|
||||||
- PDF Splitting und Metadaten-Anreicherung
|
### Scanner-Eingangsbox
|
||||||
- Multi-Plattform Docker-Unterstützung (AMD64 & ARM64)
|
- Überwachung eines Scan-Verzeichnisses per Filesystem-Watcher
|
||||||
- Gitea Actions CI/CD Integration
|
- PDF-Vorschau, Seitenrotation und Splitting direkt im Browser
|
||||||
|
- Barcode- und QR-Code-Erkennung zur automatischen Dokumententrennung
|
||||||
|
- OCR über Ollama (llava Vision-Modell) für handschriftliche und gescannte Seiten
|
||||||
|
- GoBD-konformes Archivieren der Originaldokumente
|
||||||
|
|
||||||
|
### E-Mail-Import
|
||||||
|
- IMAP-Anbindung zum automatischen Abruf von Postfächern
|
||||||
|
- Extraktion von E-Mail-Anhängen (PDF, ZUGFeRD-Rechnungen)
|
||||||
|
- Zuordnung von Absendern zu Paperless-Korrespondenten
|
||||||
|
|
||||||
|
### Regelbasierte Nachbearbeitung
|
||||||
|
- Konfigurierbare Filterregeln (Feld-Operatoren: eq, contains, in, …)
|
||||||
|
- Aktionen: Tags setzen, Felder aktualisieren, E-Mail senden, WebDAV-Export
|
||||||
|
- Priorisierbare Regelketten mit Stop-Bedingung
|
||||||
|
|
||||||
|
### Etikettendruck-Agent
|
||||||
|
- SVG-Vorlagen → PNG-Rendering via `@resvg/resvg-js`
|
||||||
|
- SSE-basierte Job-Queue für angebundene Druckagenten
|
||||||
|
- Automatische Job-Sperrung zur Vermeidung von Race Conditions
|
||||||
|
|
||||||
|
### Authentifizierung & Berechtigungen
|
||||||
|
- OIDC-Integration (z. B. Authentik) mit JWT-Validierung
|
||||||
|
- API-Key-Unterstützung für maschinellen Zugriff
|
||||||
|
- Granulares Berechtigungssystem auf Basis von OIDC-Gruppen
|
||||||
|
|
||||||
|
## Technologie
|
||||||
|
|
||||||
|
| Schicht | Stack |
|
||||||
|
|---------|-------|
|
||||||
|
| Backend | NestJS (TypeScript), TypeORM, MySQL 8 |
|
||||||
|
| Frontend | React 19, Ant Design, Vite |
|
||||||
|
| OCR | Ollama (llava) |
|
||||||
|
| Deployment | Docker Compose, Gitea Actions CI/CD |
|
||||||
|
| Auth | OIDC (Authentik), JWT, API Keys |
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# .env anpassen (DB, Paperless-URL, OIDC, Ollama, …)
|
||||||
|
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Backend läuft auf Port `3100`, Frontend wird über nginx ausgeliefert.
|
||||||
|
|
||||||
|
Eine vollständige Beschreibung aller Umgebungsvariablen findet sich in `.env.example`.
|
||||||
|
|
||||||
|
## Entwicklung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backend
|
||||||
|
cd paperless-backend
|
||||||
|
npm install
|
||||||
|
npm run start:dev
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
cd paperless-frontend
|
||||||
|
npm install
|
||||||
|
npm run dev # Proxy auf localhost:3100
|
||||||
|
```
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export interface WysiwygEditorHandle {
|
|||||||
|
|
||||||
interface WysiwygEditorProps {
|
interface WysiwygEditorProps {
|
||||||
minHeight?: number;
|
minHeight?: number;
|
||||||
|
initialContent?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToolBtn({
|
function ToolBtn({
|
||||||
@@ -69,14 +70,14 @@ const HEADING_OPTIONS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(
|
export const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(
|
||||||
({ minHeight = 200 }, ref) => {
|
({ minHeight = 200, initialContent }, ref) => {
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
extensions: [
|
extensions: [
|
||||||
StarterKit,
|
StarterKit,
|
||||||
Underline,
|
Underline,
|
||||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||||
],
|
],
|
||||||
content: '',
|
content: initialContent ?? '',
|
||||||
});
|
});
|
||||||
|
|
||||||
useImperativeHandle(
|
useImperativeHandle(
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ function MailSettingsTab() {
|
|||||||
const [testing, setTesting] = useState(false);
|
const [testing, setTesting] = useState(false);
|
||||||
const [testResult, setTestResult] = useState<{ ok: boolean; error?: string } | null>(null);
|
const [testResult, setTestResult] = useState<{ ok: boolean; error?: string } | null>(null);
|
||||||
const [passSet, setPassSet] = useState(false);
|
const [passSet, setPassSet] = useState(false);
|
||||||
|
const [signatureHtml, setSignatureHtml] = useState<string | null>(null);
|
||||||
const editorRef = useRef<WysiwygEditorHandle>(null);
|
const editorRef = useRef<WysiwygEditorHandle>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -81,9 +82,7 @@ function MailSettingsTab() {
|
|||||||
smtpFromName: data.smtpFromName ?? '',
|
smtpFromName: data.smtpFromName ?? '',
|
||||||
});
|
});
|
||||||
setPassSet(data.smtpPassSet);
|
setPassSet(data.smtpPassSet);
|
||||||
if (data.mailSignatureHtml) {
|
setSignatureHtml(data.mailSignatureHtml ?? null);
|
||||||
editorRef.current?.setContent(data.mailSignatureHtml);
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
message.error('Einstellungen konnten nicht geladen werden');
|
message.error('Einstellungen konnten nicht geladen werden');
|
||||||
}).finally(() => setLoading(false));
|
}).finally(() => setLoading(false));
|
||||||
@@ -167,7 +166,7 @@ function MailSettingsTab() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="Signatur">
|
<Form.Item label="Signatur">
|
||||||
<WysiwygEditor ref={editorRef} minHeight={180} />
|
<WysiwygEditor ref={editorRef} initialContent={signatureHtml ?? ''} minHeight={180} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
|
|||||||
Reference in New Issue
Block a user