# 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 in src/router/
  • V1 Modal: Neue Komponente in src/components/Modals/
  • V2 Programm: Eintrag in programRegistry.ts + Komponente in src/v2/programs/

# Backend

Im API-Repository (seminarplan-api/) musst du ebenfalls:

  1. Mongoose Model erstellen
  2. LookupService in src/services/v2/ anlegen
  3. Routen über createV2ResourceRoutes() oder createV2LookupRoutes() registrieren
  4. ACL-Rechte definieren

# Siehe auch

Last Updated: 4/16/2026, 8:54:41 AM