feat: add database indexes, implement CORS configuration, and lazy-load frontend routes
Build and Push Multi-Platform Images / build-and-push (push) Successful in 35s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 35s
This commit is contained in:
@@ -44,3 +44,9 @@ VITE_API_URL=
|
|||||||
# Platzhalter {Jahr} wird zur Laufzeit durch das Jahr des Eingangsdatums ersetzt
|
# Platzhalter {Jahr} wird zur Laufzeit durch das Jahr des Eingangsdatums ersetzt
|
||||||
BELEGNUMMER_GET_URL=https://beispiel-api.de/get-number/{Jahr}
|
BELEGNUMMER_GET_URL=https://beispiel-api.de/get-number/{Jahr}
|
||||||
BELEGNUMMER_SET_URL=https://beispiel-api.de/set-number/{Jahr}/{Nummer}
|
BELEGNUMMER_SET_URL=https://beispiel-api.de/set-number/{Jahr}/{Nummer}
|
||||||
|
|
||||||
|
# --- CORS ---
|
||||||
|
# Erlaubte Frontend-Origin für CORS. In Produktion PFLICHT (z.B. https://paperless.example.com).
|
||||||
|
# Leer lassen für lokale Entwicklung (erlaubt alle Origins).
|
||||||
|
# NODE_ENV=production ohne CORS_ORIGIN blockiert alle Cross-Origin-Anfragen.
|
||||||
|
CORS_ORIGIN=
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, Index, OneToMany } from 'typeorm';
|
||||||
import { Attachment } from './attachment.entity';
|
import { Attachment } from './attachment.entity';
|
||||||
|
|
||||||
@Entity('Emails')
|
@Entity('Emails')
|
||||||
@@ -18,12 +18,14 @@ export class Email {
|
|||||||
@Column({ type: 'varchar', length: 500 })
|
@Column({ type: 'varchar', length: 500 })
|
||||||
Subject!: string;
|
Subject!: string;
|
||||||
|
|
||||||
|
@Index()
|
||||||
@Column({ type: 'datetime' })
|
@Column({ type: 'datetime' })
|
||||||
Date!: Date;
|
Date!: Date;
|
||||||
|
|
||||||
@Column({ type: 'longtext' })
|
@Column({ type: 'longtext' })
|
||||||
Body!: string;
|
Body!: string;
|
||||||
|
|
||||||
|
@Index()
|
||||||
@Column({ type: 'int', default: 0 })
|
@Column({ type: 'int', default: 0 })
|
||||||
Status!: number;
|
Status!: number;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
Entity,
|
Entity,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
Column,
|
Column,
|
||||||
|
Index,
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ export class LabelPrintJob {
|
|||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
Id!: number;
|
Id!: number;
|
||||||
|
|
||||||
|
@Index()
|
||||||
@Column({ type: 'varchar', length: 20, default: 'pending' })
|
@Column({ type: 'varchar', length: 20, default: 'pending' })
|
||||||
Status!: 'pending' | 'printed' | 'error';
|
Status!: 'pending' | 'printed' | 'error';
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ export class LabelPrintJob {
|
|||||||
@Column({ type: 'simple-json', nullable: true })
|
@Column({ type: 'simple-json', nullable: true })
|
||||||
LabelVariables!: Record<string, string> | null;
|
LabelVariables!: Record<string, string> | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
@Column({ type: 'datetime', nullable: true })
|
@Column({ type: 'datetime', nullable: true })
|
||||||
LockedAt!: Date | null;
|
LockedAt!: Date | null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
|
||||||
|
|
||||||
@Entity('tasks')
|
@Entity('tasks')
|
||||||
export class Task {
|
export class Task {
|
||||||
@PrimaryColumn({ type: 'varchar', length: 36 })
|
@PrimaryColumn({ type: 'varchar', length: 36 })
|
||||||
TaskId!: string;
|
TaskId!: string;
|
||||||
|
|
||||||
|
@Index()
|
||||||
@Column({ type: 'varchar', length: 50 })
|
@Column({ type: 'varchar', length: 50 })
|
||||||
InterneBelegnummer!: string;
|
InterneBelegnummer!: string;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ export class Task {
|
|||||||
@Column({ type: 'datetime', nullable: true })
|
@Column({ type: 'datetime', nullable: true })
|
||||||
Eingangsdatum!: Date | null;
|
Eingangsdatum!: Date | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
@Column({ type: 'tinyint', nullable: true })
|
@Column({ type: 'tinyint', nullable: true })
|
||||||
Fertig!: number | null;
|
Fertig!: number | null;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ async function bootstrap(): Promise<void> {
|
|||||||
const port = process.env.PORT ?? 3100;
|
const port = process.env.PORT ?? 3100;
|
||||||
|
|
||||||
app.enableCors({
|
app.enableCors({
|
||||||
origin: '*', // Für lokale Entwicklung zulassen, oder spezifisch: 'http://localhost:8080'
|
origin: process.env.CORS_ORIGIN ?? (process.env.NODE_ENV === 'production' ? false : '*'),
|
||||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
|
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
|
||||||
credentials: true,
|
credentials: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { lazy, Suspense } from 'react';
|
||||||
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';
|
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { ConfigProvider, theme, App as AntdApp } from 'antd';
|
import { ConfigProvider, theme, App as AntdApp } from 'antd';
|
||||||
import deDE from 'antd/locale/de_DE';
|
import deDE from 'antd/locale/de_DE';
|
||||||
@@ -6,18 +7,19 @@ import { saveReturnUrl } from './auth/sessionRedirect';
|
|||||||
import { ThemeProvider, useTheme } from './theme/ThemeContext';
|
import { ThemeProvider, useTheme } from './theme/ThemeContext';
|
||||||
import AuthCallback from './auth/AuthCallback';
|
import AuthCallback from './auth/AuthCallback';
|
||||||
import AppLayout from './layouts/AppLayout';
|
import AppLayout from './layouts/AppLayout';
|
||||||
import InboxPage from './pages/InboxPage';
|
|
||||||
import InboxDetailPage from './pages/InboxDetailPage';
|
|
||||||
import PosteingangPage from './pages/PosteingangPage';
|
|
||||||
import ManuellBearbeitenPage from './pages/ManuellBearbeitenPage';
|
|
||||||
import MailpostfachPage from './pages/MailpostfachPage';
|
|
||||||
import MailDetailPage from './pages/MailDetailPage';
|
|
||||||
import SettingsPage from './pages/SettingsPage';
|
|
||||||
import UserSettingsPage from './pages/UserSettingsPage';
|
|
||||||
import LoginPage from './pages/LoginPage';
|
|
||||||
import DashboardPage from './pages/DashboardPage';
|
|
||||||
import { Spin, Result, Button } from 'antd';
|
import { Spin, Result, Button } from 'antd';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
const InboxPage = lazy(() => import('./pages/InboxPage'));
|
||||||
|
const InboxDetailPage = lazy(() => import('./pages/InboxDetailPage'));
|
||||||
|
const PosteingangPage = lazy(() => import('./pages/PosteingangPage'));
|
||||||
|
const ManuellBearbeitenPage = lazy(() => import('./pages/ManuellBearbeitenPage'));
|
||||||
|
const MailpostfachPage = lazy(() => import('./pages/MailpostfachPage'));
|
||||||
|
const MailDetailPage = lazy(() => import('./pages/MailDetailPage'));
|
||||||
|
const SettingsPage = lazy(() => import('./pages/SettingsPage'));
|
||||||
|
const UserSettingsPage = lazy(() => import('./pages/UserSettingsPage'));
|
||||||
|
const LoginPage = lazy(() => import('./pages/LoginPage'));
|
||||||
|
const DashboardPage = lazy(() => import('./pages/DashboardPage'));
|
||||||
import { Permission } from './auth/permissions';
|
import { Permission } from './auth/permissions';
|
||||||
|
|
||||||
function UnauthorizedPage() {
|
function UnauthorizedPage() {
|
||||||
@@ -109,28 +111,30 @@ function ThemedApp() {
|
|||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<AntdApp>
|
<AntdApp>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Suspense fallback={<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}><Spin size="large" /></div>}>
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Routes>
|
||||||
<Route path="/auth/callback" element={<AuthCallback />} />
|
<Route path="/login" element={<LoginPage />} />
|
||||||
<Route
|
<Route path="/auth/callback" element={<AuthCallback />} />
|
||||||
element={
|
<Route
|
||||||
<ProtectedRoute>
|
element={
|
||||||
<AppLayout />
|
<ProtectedRoute>
|
||||||
</ProtectedRoute>
|
<AppLayout />
|
||||||
}
|
</ProtectedRoute>
|
||||||
>
|
}
|
||||||
<Route index element={<DashboardPage />} />
|
>
|
||||||
<Route path="/dashboard" element={<DashboardPage />} />
|
<Route index element={<DashboardPage />} />
|
||||||
<Route path="/inbox" element={<PermissionRoute permission={Permission.VIEW_SCANNER}><InboxPage /></PermissionRoute>} />
|
<Route path="/dashboard" element={<DashboardPage />} />
|
||||||
<Route path="/inbox/:id" element={<PermissionRoute permission={Permission.VIEW_SCANNER}><InboxDetailPage /></PermissionRoute>} />
|
<Route path="/inbox" element={<PermissionRoute permission={Permission.VIEW_SCANNER}><InboxPage /></PermissionRoute>} />
|
||||||
<Route path="/posteingang" element={<PermissionRoute permission={Permission.VIEW_INBOX}><PosteingangPage /></PermissionRoute>} />
|
<Route path="/inbox/:id" element={<PermissionRoute permission={Permission.VIEW_SCANNER}><InboxDetailPage /></PermissionRoute>} />
|
||||||
<Route path="/manuell" element={<PermissionRoute permission={Permission.PROCESS_MANUALLY}><ManuellBearbeitenPage /></PermissionRoute>} />
|
<Route path="/posteingang" element={<PermissionRoute permission={Permission.VIEW_INBOX}><PosteingangPage /></PermissionRoute>} />
|
||||||
<Route path="/mailpostfach" element={<PermissionRoute permission={Permission.VIEW_MAIL}><MailpostfachPage /></PermissionRoute>} />
|
<Route path="/manuell" element={<PermissionRoute permission={Permission.PROCESS_MANUALLY}><ManuellBearbeitenPage /></PermissionRoute>} />
|
||||||
<Route path="/mailpostfach/:id" element={<PermissionRoute permission={Permission.VIEW_MAIL}><MailDetailPage /></PermissionRoute>} />
|
<Route path="/mailpostfach" element={<PermissionRoute permission={Permission.VIEW_MAIL}><MailpostfachPage /></PermissionRoute>} />
|
||||||
<Route path="/settings" element={<PermissionRoute permission={Permission.MANAGE_SETTINGS}><SettingsPage /></PermissionRoute>} />
|
<Route path="/mailpostfach/:id" element={<PermissionRoute permission={Permission.VIEW_MAIL}><MailDetailPage /></PermissionRoute>} />
|
||||||
<Route path="/user-settings" element={<UserSettingsPage />} />
|
<Route path="/settings" element={<PermissionRoute permission={Permission.MANAGE_SETTINGS}><SettingsPage /></PermissionRoute>} />
|
||||||
</Route>
|
<Route path="/user-settings" element={<UserSettingsPage />} />
|
||||||
</Routes>
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
</Suspense>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</AntdApp>
|
</AntdApp>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
|||||||
Reference in New Issue
Block a user