483 lines
12 KiB
Markdown
483 lines
12 KiB
Markdown
# React-UI Spezifikation für PowerOn Frontend
|
|
|
|
## Übersicht
|
|
|
|
Diese Spezifikation definiert die strukturellen und architektonischen Prinzipien für das React-UI für PowerOn und weitere UI's.
|
|
|
|
## 1. Architektur-Übersicht
|
|
|
|
### 1.1 Generische UI-Anforderungen
|
|
|
|
Das UI soll:
|
|
|
|
- **Modular und erweiterbar** sein: Neue Module können einfach hinzugefügt werden ohne bestehenden Code zu ändern
|
|
- **Konsistent und einheitlich** sein: Alle Module folgen den gleichen Design-Patterns und Verhaltensweisen
|
|
- **Responsive und zugänglich** sein: Funktioniert auf allen Geräten und ist barrierefrei
|
|
- **Performance-optimiert** sein: Schnelle Ladezeiten und flüssige Interaktionen
|
|
- **Wartbar und testbar** sein: Klare Struktur, umfassende Tests und Dokumentation
|
|
- **Sicher und robust** sein: Fehlerbehandlung, Input-Validierung und sichere API-Kommunikation
|
|
- **Internationalisierbar** sein: Mehrsprachige Unterstützung für alle UI-Elemente
|
|
- **Konfigurierbar** sein: Verhalten und Aussehen können über Konfiguration angepasst werden
|
|
|
|
### 1.2 React-Architektur-Spezifikation
|
|
|
|
Das React-UI MUSS folgende Kernelemente implementieren:
|
|
|
|
#### **1.2.1 FormGeneric-Komponente**
|
|
- EINE zentrale CRUD-Komponente für alle Module
|
|
- Automatische Formular-Generierung basierend auf Backend-Modell-Definitionen
|
|
- Einheitliche Validierung und Fehlerbehandlung
|
|
- Unterstützung für alle Standard-Feldtypen (Text, Number, Date, Select, etc.)
|
|
|
|
#### **1.2.2 Modul-Management-System**
|
|
- Zentrale Klasse für Modul-Loading, -Aktivierung und -Deaktivierung
|
|
- Dynamisches Laden von Modulen zur Laufzeit
|
|
- Modul-spezifische Konfiguration und State-Isolation
|
|
- Einheitliche Modul-Lifecycle-Verwaltung
|
|
|
|
#### **1.2.3 Globaler State-Management**
|
|
- EINE zentrale State-Management-Lösung für alle Module
|
|
- Konsistente Datenhaltung und -synchronisation
|
|
- Modul-übergreifende Datenfreigabe
|
|
- Optimistic Updates und Rollback-Mechanismen
|
|
|
|
#### **1.2.4 Timezone-Aware Timestamp-System**
|
|
- Alle Timestamps MÜSSEN timezone-aware sein
|
|
- Konsistente Darstellung in allen Modulen
|
|
- Automatische Konvertierung zwischen Zeitzonen
|
|
- Integration mit Backend-Timestamp-Format
|
|
|
|
#### **1.2.5 Zentrale API-Kommunikation**
|
|
- Einheitliche API-Call-Verwaltung
|
|
- Automatische Error-Handling und Retry-Mechanismen
|
|
- Request/Response-Interceptoren
|
|
- Caching-Strategien für Performance
|
|
|
|
#### **1.2.6 Konfigurationsverwaltung**
|
|
- Globale Konfiguration für UI-Verhalten
|
|
- Umgebungs-spezifische Konfiguration (dev/prod)
|
|
- Feature-Flags für modulare Aktivierung
|
|
- Zentrale Validierungsregeln
|
|
|
|
## 2. Konfigurationsverwaltung
|
|
|
|
### 2.1 Konfigurationsarchitektur
|
|
|
|
Das UI verwendet eine zweistufige Konfigurationsverwaltung:
|
|
|
|
#### **Globale Konfiguration (config.js)**
|
|
```typescript
|
|
// Zentrale Konfigurationsverwaltung für globale Variablen
|
|
interface GlobalConfig {
|
|
// API-Konfiguration
|
|
apiBaseUrl: string;
|
|
apiTimeout: number;
|
|
|
|
// UI-Konfiguration
|
|
defaultLanguage: string;
|
|
theme: 'light' | 'dark' | 'auto';
|
|
pageSize: number;
|
|
|
|
// Feature-Flags
|
|
features: {
|
|
enableAdvancedSearch: boolean;
|
|
enableBulkOperations: boolean;
|
|
enableRealTimeUpdates: boolean;
|
|
};
|
|
|
|
// Validierung
|
|
validation: {
|
|
maxFileSize: number;
|
|
allowedFileTypes: string[];
|
|
passwordMinLength: number;
|
|
};
|
|
}
|
|
|
|
// Konfigurationsservice
|
|
class ConfigService {
|
|
private config: GlobalConfig;
|
|
|
|
get(key: string): any;
|
|
set(key: string, value: any): void;
|
|
getApiBaseUrl(): string;
|
|
getFeatureFlag(flag: string): boolean;
|
|
}
|
|
```
|
|
|
|
#### **Umgebungs-spezifische Konfiguration (env)**
|
|
```typescript
|
|
// Umgebungsvariablen für spezifische Konfigurationen
|
|
interface EnvironmentConfig {
|
|
// Umgebung
|
|
NODE_ENV: 'development' | 'production' | 'test';
|
|
APP_ENV: 'dev' | 'int' | 'prod';
|
|
|
|
// API-Endpunkte
|
|
API_BASE_URL: string;
|
|
API_TIMEOUT: number;
|
|
|
|
// Debugging
|
|
DEBUG_MODE: boolean;
|
|
LOG_LEVEL: 'debug' | 'info' | 'warn' | 'error';
|
|
|
|
// Externe Services
|
|
GOOGLE_CLIENT_ID?: string;
|
|
MICROSOFT_CLIENT_ID?: string;
|
|
|
|
// Build-spezifisch
|
|
BUILD_VERSION: string;
|
|
BUILD_TIMESTAMP: string;
|
|
}
|
|
|
|
// Environment Service
|
|
class EnvironmentService {
|
|
get(key: keyof EnvironmentConfig): string | undefined;
|
|
isDevelopment(): boolean;
|
|
isProduction(): boolean;
|
|
getApiBaseUrl(): string;
|
|
}
|
|
```
|
|
|
|
### 2.2 Konfigurationshierarchie
|
|
|
|
```typescript
|
|
// Konfigurationspriorität (höchste zu niedrigste):
|
|
// 1. Umgebungsvariablen (env)
|
|
// 2. Globale Konfiguration (config.js)
|
|
// 3. Standardwerte (defaults)
|
|
|
|
class ConfigurationManager {
|
|
private envConfig: EnvironmentConfig;
|
|
private globalConfig: GlobalConfig;
|
|
private defaults: GlobalConfig;
|
|
|
|
get(key: string): any {
|
|
// Prüfe Umgebungsvariablen zuerst
|
|
if (this.envConfig[key]) {
|
|
return this.envConfig[key];
|
|
}
|
|
|
|
// Dann globale Konfiguration
|
|
if (this.globalConfig[key]) {
|
|
return this.globalConfig[key];
|
|
}
|
|
|
|
// Schließlich Standardwerte
|
|
return this.defaults[key];
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2.3 React-Integration
|
|
|
|
```typescript
|
|
// React Hook für Konfiguration
|
|
const useConfig = () => {
|
|
const [config, setConfig] = useState<GlobalConfig>();
|
|
|
|
useEffect(() => {
|
|
// Lade Konfiguration beim Mount
|
|
const loadConfig = async () => {
|
|
const configData = await configService.load();
|
|
setConfig(configData);
|
|
};
|
|
|
|
loadConfig();
|
|
}, []);
|
|
|
|
return {
|
|
config,
|
|
get: (key: string) => config?.[key],
|
|
isFeatureEnabled: (feature: string) => config?.features?.[feature] || false,
|
|
getApiBaseUrl: () => config?.apiBaseUrl || envService.getApiBaseUrl()
|
|
};
|
|
};
|
|
|
|
// Verwendung in Komponenten
|
|
const MyComponent = () => {
|
|
const { config, isFeatureEnabled, getApiBaseUrl } = useConfig();
|
|
|
|
return (
|
|
<div>
|
|
{isFeatureEnabled('enableAdvancedSearch') && <AdvancedSearch />}
|
|
<ApiClient baseUrl={getApiBaseUrl()} />
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
## 3. Strukturelle Prinzipien
|
|
|
|
### 3.1 Modulare Architektur
|
|
|
|
Jedes Modul folgt einer einheitlichen Struktur:
|
|
|
|
```typescript
|
|
ModuleName/
|
|
├── index.tsx // Hauptkomponente
|
|
├── ModuleName.tsx // Haupt-UI-Komponente
|
|
├── ModuleName.types.ts // TypeScript-Definitionen
|
|
├── ModuleName.hooks.ts // Custom Hooks
|
|
├── ModuleName.service.ts // API-Service
|
|
└── ModuleName.styles.css // Modul-spezifische Styles
|
|
```
|
|
|
|
### 3.2 State Management
|
|
|
|
```typescript
|
|
// Zustand-Management mit React Context + useReducer
|
|
interface ModuleState {
|
|
items: any[];
|
|
currentItem: any | null;
|
|
isEditing: boolean;
|
|
isCreating: boolean;
|
|
lifecycleState: 'active' | 'background' | 'unloaded' | 'stale';
|
|
lastActivated: number | null;
|
|
lastDataLoad: number | null;
|
|
}
|
|
|
|
// Zentrale Module-Management-Klasse
|
|
class ModuleManager {
|
|
private modules: Map<string, ModuleState> = new Map();
|
|
|
|
load(moduleName: string): Promise<boolean>;
|
|
unload(moduleName: string): boolean;
|
|
activate(moduleName: string): Promise<boolean>;
|
|
deactivate(moduleName: string): boolean;
|
|
}
|
|
```
|
|
|
|
## 4. FormGeneric React-Implementierung
|
|
|
|
### 4.1 Generische CRUD-Komponente
|
|
|
|
```typescript
|
|
interface FormGenericProps<T> {
|
|
entityType: string;
|
|
apiEndpoint: {
|
|
get: () => Promise<T[]>;
|
|
create: (data: Partial<T>) => Promise<T>;
|
|
update: (id: string, data: Partial<T>) => Promise<T>;
|
|
delete: (id: string) => Promise<void>;
|
|
};
|
|
config: {
|
|
fields: FieldDefinition[];
|
|
table: TableConfig;
|
|
ui: UIConfig;
|
|
};
|
|
events?: {
|
|
beforeActivation?: () => Promise<void>;
|
|
onActivation?: () => Promise<void>;
|
|
onDeactivation?: () => Promise<void>;
|
|
};
|
|
}
|
|
|
|
const FormGeneric = <T extends Record<string, any>>({
|
|
entityType,
|
|
apiEndpoint,
|
|
config,
|
|
events
|
|
}: FormGenericProps<T>) => {
|
|
// React-Implementierung der aktuellen formGeneric-Logik
|
|
};
|
|
```
|
|
|
|
### 4.2 Field-Definitionen aus Backend
|
|
|
|
```typescript
|
|
interface FieldDefinition {
|
|
name: string;
|
|
label: Record<string, string>; // Multi-language support
|
|
type: 'text' | 'email' | 'password' | 'checkbox' | 'select' | 'textarea' | 'timestamp';
|
|
required: boolean;
|
|
readonly: boolean;
|
|
options?: Array<{
|
|
value: string;
|
|
label: Record<string, string>;
|
|
}>;
|
|
}
|
|
```
|
|
|
|
## 5. Timezone-Aware Timestamps
|
|
|
|
### 5.1 Konsistente Timestamp-Behandlung
|
|
|
|
```typescript
|
|
// React Hook für Timestamp-Utilities
|
|
const useTimezoneUtils = () => {
|
|
const formatUtcForDisplay = (timestamp: number): string => {
|
|
// UTC timestamp in seconds -> formatted display string
|
|
};
|
|
|
|
const isExpiredUtc = (expiresAt: number): boolean => {
|
|
// Check if timestamp is expired
|
|
};
|
|
|
|
return { formatUtcForDisplay, isExpiredUtc, /* ... */ };
|
|
};
|
|
```
|
|
|
|
### 5.2 Backend-Model-Integration
|
|
|
|
```typescript
|
|
// Automatische Generierung von TypeScript-Interfaces aus Backend-Modellen
|
|
interface User {
|
|
id: string;
|
|
username: string;
|
|
email: string;
|
|
fullName?: string;
|
|
language: string;
|
|
enabled: boolean;
|
|
privilege: 'user' | 'admin' | 'sysadmin';
|
|
authenticationAuthority: 'local' | 'google' | 'msft';
|
|
mandateId?: string;
|
|
}
|
|
|
|
interface UserConnection {
|
|
id: string;
|
|
userId: string;
|
|
authority: 'local' | 'google' | 'msft';
|
|
externalUsername: string;
|
|
externalEmail?: string;
|
|
status: 'active' | 'expired' | 'revoked' | 'pending';
|
|
connectedAt: number; // UTC timestamp
|
|
lastChecked: number; // UTC timestamp
|
|
expiresAt?: number; // UTC timestamp
|
|
}
|
|
```
|
|
|
|
## 6. Fehlerbehandlung
|
|
|
|
### 6.1 Zentrale Error-Boundary
|
|
|
|
```typescript
|
|
class ErrorBoundary extends React.Component {
|
|
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
|
// Logging und Benutzer-Benachrichtigung
|
|
console.error('Module Error:', error, errorInfo);
|
|
// Toast-Benachrichtigung anzeigen
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6.2 API-Error-Handling
|
|
|
|
```typescript
|
|
// Service-Klasse für API-Aufrufe
|
|
class ApiService {
|
|
async request<T>(endpoint: string, options?: RequestInit): Promise<T> {
|
|
try {
|
|
const response = await fetch(endpoint, options);
|
|
if (!response.ok) {
|
|
throw new ApiError(response.status, await response.text());
|
|
}
|
|
return await response.json();
|
|
} catch (error) {
|
|
// Zentrale Fehlerbehandlung
|
|
this.handleError(error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 7. Styling-Ansatz
|
|
|
|
### 6.1 CSS-in-JS oder CSS-Module
|
|
|
|
```typescript
|
|
// Empfehlung: CSS-Module für bessere Performance
|
|
import styles from './FormGeneric.module.css';
|
|
|
|
const FormGeneric = () => (
|
|
<div className={styles.entityTable}>
|
|
<table className={styles.table}>
|
|
{/* ... */}
|
|
</table>
|
|
</div>
|
|
);
|
|
```
|
|
|
|
### 6.2 Design-System
|
|
|
|
```css
|
|
/* Design-Tokens */
|
|
:root {
|
|
--color-primary: #3b82f6;
|
|
--color-secondary: #6b7280;
|
|
--color-success: #10b981;
|
|
--color-warning: #f59e0b;
|
|
--color-error: #ef4444;
|
|
|
|
--spacing-xs: 0.25rem;
|
|
--spacing-sm: 0.5rem;
|
|
--spacing-md: 1rem;
|
|
--spacing-lg: 1.5rem;
|
|
|
|
--border-radius: 0.375rem;
|
|
--box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
}
|
|
```
|
|
|
|
## 7. Performance-Optimierungen
|
|
|
|
### 7.1 Lazy Loading
|
|
|
|
```typescript
|
|
// Lazy Loading für Module
|
|
const UsersModule = React.lazy(() => import('./modules/Users'));
|
|
const ConnectionsModule = React.lazy(() => import('./modules/Connections'));
|
|
|
|
// Suspense-Wrapper
|
|
<Suspense fallback={<LoadingSpinner />}>
|
|
<UsersModule />
|
|
</Suspense>
|
|
```
|
|
|
|
### 7.2 Memoization
|
|
|
|
```typescript
|
|
// Optimierte Komponenten mit React.memo
|
|
const DataTable = React.memo<DataTableProps>(({ data, columns }) => {
|
|
// Komponente wird nur neu gerendert wenn sich data oder columns ändern
|
|
});
|
|
```
|
|
|
|
## 8. Testing-Strategie
|
|
|
|
### 8.1 Unit Tests
|
|
|
|
```typescript
|
|
// Jest + React Testing Library
|
|
describe('FormGeneric', () => {
|
|
it('should render table with data', () => {
|
|
render(<FormGeneric {...mockProps} />);
|
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
|
});
|
|
});
|
|
```
|
|
|
|
### 8.2 Integration Tests
|
|
|
|
```typescript
|
|
// API-Integration Tests
|
|
describe('UserService', () => {
|
|
it('should fetch users from API', async () => {
|
|
const users = await userService.getUsers();
|
|
expect(users).toHaveLength(2);
|
|
});
|
|
});
|
|
```
|
|
|
|
## 9. Implementierungsrichtlinien
|
|
|
|
### 9.1 Code-Qualität
|
|
|
|
- **TypeScript**: Strikte Typisierung für alle Komponenten und Services
|
|
- **ESLint**: Code-Qualitätsregeln und Konsistenz
|
|
|
|
### 9.2 Dokumentation
|
|
|
|
- **Storybook**: Komponenten-Dokumentation
|
|
- **README**: Setup und Entwicklungsanweisungen
|
|
|