# Neuen Store anlegen
Schritt-für-Schritt-Anleitung, um eine neue Entität mit Store, API-Service und WebSocket-Anbindung hinzuzufügen.
# Übersicht
Wenn du eine neue Entität in SeminarPlan einführst (z.B. "Zertifikate"), musst du mehrere Dateien anlegen und bestehende Dateien erweitern. Diese Anleitung führt dich durch alle Schritte.
# Checkliste
| # | Datei / Ort | Was |
|---|---|---|
| 1 | src/api/types/types.ts | Interface für die Entität definieren |
| 2 | src/api/<Entity>Service.ts | API-Service erstellen |
| 3 | src/stores/<Entity>Store.ts | Pinia-Store mit CRUD-Config anlegen |
| 4 | src/composables/autoload.ts | Store zum Autoloader hinzufügen (falls global benötigt) |
| 5 | src/composables/storeHelper.ts | WebSocket-Mapping eintragen |
| 6 | src/modules/Activity.ts | Aktivitätstypen registrieren |
| 7 | View / Modal / Tab | UI-Komponenten nach Bedarf |
# Schritt 1: Type Definition
Definiere das Interface in src/api/types/types.ts:
export interface ICertificateEntity extends IBaseEntity {
title: string;
description?: string;
seminar?: string; // Referenz auf ISeminarEntity
contact?: string; // Referenz auf IContactEntity
issuedAt?: string;
status: string;
}
Alle Entitäten erben von IBaseEntity, das _id, __v, status, createdAt, updatedAt, createdBy und updatedBy enthält.
# Schritt 2: API-Service
Erstelle src/api/CertificateService.ts:
import BaseApiService from './BaseApiService';
class CertificateService extends BaseApiService {
constructor() {
super('certificates');
}
}
export default new CertificateService();
Der super()-Parameter ist der API-Pfad (Plural, lowercase). BaseApiService stellt automatisch getAll(), get(id), store(item), delete(id) und weitere Methoden bereit.
# Schritt 3: Pinia-Store
Erstelle src/stores/CertificateStore.ts:
import { defineStore } from 'pinia';
import CertificateService from '../api/CertificateService';
import { ICertificateEntity } from '../api/types/types';
export const useCertificateStore = defineStore('certificateStore', {
state: () => ({
items: [] as ICertificateEntity[],
}),
crud: {
enable: true,
service: CertificateService,
searchFields: ['title'],
searchModal: 'CertificateModal',
listExclude: ['description'], // Schwere Felder von der Liste ausschließen
},
});
# CRUD-Config Optionen
| Option | Typ | Beschreibung |
|---|---|---|
enable | boolean | CRUD-Plugin aktivieren |
service | BaseApiService | Der zugehörige API-Service |
searchFields | string[] | Felder für die clientseitige Suche |
searchModal | string | Name der Modal-Komponente für Suchergebnisse |
tabName | string | Tab-Name für komplexe Bearbeitung (optional) |
listExclude | string[] | Felder, die beim Laden der Liste ausgeschlossen werden |
# Bereitgestellte Methoden
Das CRUD-Plugin stellt automatisch folgende Methoden bereit:
| Methode | Beschreibung |
|---|---|
load() | Alle Einträge laden |
loadIfNeeded() | Nur laden, wenn noch nicht geladen |
store(item) | Eintrag erstellen oder aktualisieren |
delete(id) | Soft Delete |
archive(id) | Archivieren |
getItemById(id) | Eintrag aus dem lokalen State holen |
search(query) | Clientseitige Suche |
showModalForId(id) | Modal für einen Eintrag öffnen |
showTabForId(id) | Tab für einen Eintrag öffnen |
showItemForId(id) | Modal oder Tab öffnen (je nach Config) |
isFieldUnique(field, value, excludeId) | Prüfen ob ein Feld-Wert eindeutig ist |
getPlaceholderReplacers(item) | Platzhalter-Werte für Vorlagen |
# Schritt 4: Autoload (optional)
Falls der Store global verfügbar sein soll, füge ihn in src/composables/autoload.ts hinzu:
// In der stores-Definition
certificateStore: useCertificateStore(),
Danach kannst du den Store über useAutoload() laden:
const { stores, loadIfNeeded } = useAutoload();
loadIfNeeded(['certificateStore']);
Nicht immer nötig
Nicht jeder Store muss im Autoloader sein. Stores, die nur in einem bestimmten View oder Programm gebraucht werden, können dort direkt geladen werden.
# Schritt 5: WebSocket-Mapping
Damit Echtzeit-Updates funktionieren, trage den Store in src/composables/storeHelper.ts ein:
const modelToStoreKeys = {
// ... bestehende Einträge
certificates: 'certificateStore',
};
Der Key ist der Server-Model-Name (wie er in WebSocket change-Events als model kommt). Der Value ist der Store-Name im Autoloader.
# Schritt 6: Activity-Tracking
Registriere die Entität in src/modules/Activity.ts, damit Aktivitäten korrekt angezeigt werden:
// In der modelNames-Map
certificates: 'Zertifikat',
# Schritt 7: UI-Komponenten
Je nach Anforderung:
- V1 View: Neue Vue-Komponente in
src/views/+ Route insrc/router/ - V1 Modal: Neue Komponente in
src/components/Modals/ - V2 Programm: Eintrag in
programRegistry.ts+ Komponente insrc/v2/programs/
# Backend
Im API-Repository (seminarplan-api/) musst du ebenfalls:
- Mongoose Model erstellen
- LookupService in
src/services/v2/anlegen - Routen über
createV2ResourceRoutes()odercreateV2LookupRoutes()registrieren - ACL-Rechte definieren
# Siehe auch
- API-Dokumentation - REST-Endpunkte und Response-Formate
- WebSocket - Echtzeit-Updates und Change-Events
- Extensions - API mit eigenen Plugins erweitern
- Icons - Icon für die neue Entität