mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 23:14:12 +00:00
Hybrid solution for process visualization: ## Timeline Collection (Simple Processes) Enhanced with process-specific fields for simple linear flows: - Step number, duration, responsible person - Action required indicator (customer/internal/both/automatic) - Deliverables/documents per step Ideal for: Onboarding, Bewerbungsprozess, simple customer journeys ## Workflows Collection (Complex Processes) New dedicated collection for multi-phase workflows with: **Phases:** - Named sections with icons, colors, estimated duration - Responsible person/role assignment - Phase-level deliverables **Steps:** - Multiple types: task, decision, milestone, approval, wait, automatic - Priority levels: critical, high, normal, low, optional - Dependencies between steps (blocking, parallel) - Conditions/branches for decision steps - Checklists with required/optional items - Resources (documents, templates, links, tools) - Outputs per step **Properties:** - Workflow types: project, business, approval, onboarding, support, development, marketing - Complexity levels, iterative flag, parallel phases flag - Display options: vertical, horizontal, flowchart, kanban, gantt layouts **API Features:** - Public endpoint at /api/workflows with tenant isolation - Filter by type, complexity - Statistics: phase count, step count, checklist count, step type breakdown Database: 20 new tables (18 for workflows, 2 for timeline process fields) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
581 lines
16 KiB
TypeScript
581 lines
16 KiB
TypeScript
import type { CollectionConfig } from 'payload'
|
|
|
|
/**
|
|
* Timelines Collection
|
|
*
|
|
* Dedizierte Collection für komplexe Timeline-Ereignisse
|
|
* - Unternehmensgeschichte
|
|
* - Projektmeilensteine
|
|
* - Produkt-Releases
|
|
* - Historische Ereignisse
|
|
*
|
|
* Multi-Tenant-fähig mit flexiblen Kategorisierungen
|
|
*/
|
|
export const Timelines: CollectionConfig = {
|
|
slug: 'timelines',
|
|
labels: {
|
|
singular: 'Timeline',
|
|
plural: 'Timelines',
|
|
},
|
|
admin: {
|
|
useAsTitle: 'name',
|
|
group: 'Inhalte',
|
|
defaultColumns: ['name', 'type', 'status', 'updatedAt'],
|
|
description: 'Chronologische Darstellungen für Unternehmensgeschichte, Meilensteine, etc.',
|
|
},
|
|
access: {
|
|
read: () => true, // Öffentlich lesbar
|
|
},
|
|
fields: [
|
|
// Timeline-Metadaten
|
|
{
|
|
name: 'name',
|
|
type: 'text',
|
|
required: true,
|
|
label: 'Timeline-Name',
|
|
localized: true,
|
|
admin: {
|
|
description: 'Interner Name zur Identifikation (z.B. "Unternehmensgeschichte")',
|
|
},
|
|
},
|
|
{
|
|
name: 'slug',
|
|
type: 'text',
|
|
required: true,
|
|
unique: true,
|
|
label: 'Slug',
|
|
admin: {
|
|
description: 'URL-freundlicher Identifier (z.B. "company-history")',
|
|
},
|
|
},
|
|
{
|
|
name: 'description',
|
|
type: 'textarea',
|
|
label: 'Beschreibung',
|
|
localized: true,
|
|
admin: {
|
|
description: 'Optionale Beschreibung der Timeline',
|
|
},
|
|
},
|
|
{
|
|
name: 'type',
|
|
type: 'select',
|
|
required: true,
|
|
defaultValue: 'history',
|
|
label: 'Timeline-Typ',
|
|
options: [
|
|
{ label: 'Unternehmensgeschichte', value: 'history' },
|
|
{ label: 'Projektmeilensteine', value: 'milestones' },
|
|
{ label: 'Produkt-Releases', value: 'releases' },
|
|
{ label: 'Karriere/Lebenslauf', value: 'career' },
|
|
{ label: 'Ereignisse', value: 'events' },
|
|
{ label: 'Prozess/Ablauf', value: 'process' },
|
|
],
|
|
},
|
|
{
|
|
name: 'status',
|
|
type: 'select',
|
|
required: true,
|
|
defaultValue: 'draft',
|
|
label: 'Status',
|
|
options: [
|
|
{ label: 'Entwurf', value: 'draft' },
|
|
{ label: 'Veröffentlicht', value: 'published' },
|
|
{ label: 'Archiviert', value: 'archived' },
|
|
],
|
|
admin: {
|
|
position: 'sidebar',
|
|
},
|
|
},
|
|
|
|
// Display-Optionen
|
|
{
|
|
name: 'displayOptions',
|
|
type: 'group',
|
|
label: 'Darstellungsoptionen',
|
|
fields: [
|
|
{
|
|
name: 'layout',
|
|
type: 'select',
|
|
defaultValue: 'vertical',
|
|
label: 'Layout',
|
|
options: [
|
|
{ label: 'Vertikal (Standard)', value: 'vertical' },
|
|
{ label: 'Alternierend (links/rechts)', value: 'alternating' },
|
|
{ label: 'Horizontal (Zeitleiste)', value: 'horizontal' },
|
|
{ label: 'Kompakt (Liste)', value: 'compact' },
|
|
],
|
|
},
|
|
{
|
|
name: 'sortOrder',
|
|
type: 'select',
|
|
defaultValue: 'desc',
|
|
label: 'Sortierung',
|
|
options: [
|
|
{ label: 'Neueste zuerst', value: 'desc' },
|
|
{ label: 'Älteste zuerst', value: 'asc' },
|
|
],
|
|
},
|
|
{
|
|
name: 'showConnector',
|
|
type: 'checkbox',
|
|
defaultValue: true,
|
|
label: 'Verbindungslinie anzeigen',
|
|
},
|
|
{
|
|
name: 'showImages',
|
|
type: 'checkbox',
|
|
defaultValue: true,
|
|
label: 'Bilder anzeigen',
|
|
},
|
|
{
|
|
name: 'groupByYear',
|
|
type: 'checkbox',
|
|
defaultValue: false,
|
|
label: 'Nach Jahr gruppieren',
|
|
},
|
|
{
|
|
name: 'markerStyle',
|
|
type: 'select',
|
|
defaultValue: 'dot',
|
|
label: 'Marker-Stil',
|
|
options: [
|
|
{ label: 'Punkt', value: 'dot' },
|
|
{ label: 'Nummer', value: 'number' },
|
|
{ label: 'Icon', value: 'icon' },
|
|
{ label: 'Datum', value: 'date' },
|
|
],
|
|
},
|
|
{
|
|
name: 'colorScheme',
|
|
type: 'select',
|
|
defaultValue: 'primary',
|
|
label: 'Farbschema',
|
|
options: [
|
|
{ label: 'Primär (Brand)', value: 'primary' },
|
|
{ label: 'Sekundär', value: 'secondary' },
|
|
{ label: 'Neutral (Grau)', value: 'neutral' },
|
|
{ label: 'Bunt (je nach Kategorie)', value: 'colorful' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
|
|
// Timeline-Einträge
|
|
{
|
|
name: 'events',
|
|
type: 'array',
|
|
required: true,
|
|
minRows: 1,
|
|
label: 'Ereignisse',
|
|
admin: {
|
|
description: 'Die einzelnen Einträge der Timeline',
|
|
initCollapsed: false,
|
|
},
|
|
fields: [
|
|
// Datum-Optionen
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{
|
|
name: 'dateType',
|
|
type: 'select',
|
|
defaultValue: 'year',
|
|
label: 'Datumstyp',
|
|
admin: {
|
|
width: '30%',
|
|
},
|
|
options: [
|
|
{ label: 'Nur Jahr', value: 'year' },
|
|
{ label: 'Monat & Jahr', value: 'monthYear' },
|
|
{ label: 'Vollständiges Datum', value: 'fullDate' },
|
|
{ label: 'Zeitraum', value: 'range' },
|
|
{ label: 'Freitext', value: 'custom' },
|
|
],
|
|
},
|
|
{
|
|
name: 'year',
|
|
type: 'number',
|
|
label: 'Jahr',
|
|
admin: {
|
|
width: '20%',
|
|
condition: (_, siblingData) =>
|
|
['year', 'monthYear', 'fullDate'].includes(siblingData?.dateType),
|
|
},
|
|
min: 1900,
|
|
max: 2100,
|
|
},
|
|
{
|
|
name: 'month',
|
|
type: 'select',
|
|
label: 'Monat',
|
|
admin: {
|
|
width: '25%',
|
|
condition: (_, siblingData) =>
|
|
['monthYear', 'fullDate'].includes(siblingData?.dateType),
|
|
},
|
|
options: [
|
|
{ label: 'Januar', value: '1' },
|
|
{ label: 'Februar', value: '2' },
|
|
{ label: 'März', value: '3' },
|
|
{ label: 'April', value: '4' },
|
|
{ label: 'Mai', value: '5' },
|
|
{ label: 'Juni', value: '6' },
|
|
{ label: 'Juli', value: '7' },
|
|
{ label: 'August', value: '8' },
|
|
{ label: 'September', value: '9' },
|
|
{ label: 'Oktober', value: '10' },
|
|
{ label: 'November', value: '11' },
|
|
{ label: 'Dezember', value: '12' },
|
|
],
|
|
},
|
|
{
|
|
name: 'day',
|
|
type: 'number',
|
|
label: 'Tag',
|
|
admin: {
|
|
width: '15%',
|
|
condition: (_, siblingData) => siblingData?.dateType === 'fullDate',
|
|
},
|
|
min: 1,
|
|
max: 31,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{
|
|
name: 'endYear',
|
|
type: 'number',
|
|
label: 'Ende Jahr',
|
|
admin: {
|
|
width: '25%',
|
|
condition: (_, siblingData) => siblingData?.dateType === 'range',
|
|
},
|
|
min: 1900,
|
|
max: 2100,
|
|
},
|
|
{
|
|
name: 'endMonth',
|
|
type: 'select',
|
|
label: 'Ende Monat',
|
|
admin: {
|
|
width: '25%',
|
|
condition: (_, siblingData) => siblingData?.dateType === 'range',
|
|
},
|
|
options: [
|
|
{ label: 'Januar', value: '1' },
|
|
{ label: 'Februar', value: '2' },
|
|
{ label: 'März', value: '3' },
|
|
{ label: 'April', value: '4' },
|
|
{ label: 'Mai', value: '5' },
|
|
{ label: 'Juni', value: '6' },
|
|
{ label: 'Juli', value: '7' },
|
|
{ label: 'August', value: '8' },
|
|
{ label: 'September', value: '9' },
|
|
{ label: 'Oktober', value: '10' },
|
|
{ label: 'November', value: '11' },
|
|
{ label: 'Dezember', value: '12' },
|
|
],
|
|
},
|
|
{
|
|
name: 'ongoing',
|
|
type: 'checkbox',
|
|
label: 'Laufend (bis heute)',
|
|
admin: {
|
|
width: '25%',
|
|
condition: (_, siblingData) => siblingData?.dateType === 'range',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'customDate',
|
|
type: 'text',
|
|
label: 'Datum (Freitext)',
|
|
admin: {
|
|
description: 'z.B. "Frühjahr 2024", "Q1 2023", "1990er Jahre"',
|
|
condition: (_, siblingData) => siblingData?.dateType === 'custom',
|
|
},
|
|
},
|
|
|
|
// Inhalt
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
required: true,
|
|
label: 'Titel',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'subtitle',
|
|
type: 'text',
|
|
label: 'Untertitel',
|
|
localized: true,
|
|
admin: {
|
|
description: 'Optional: z.B. Rolle, Position, Ort',
|
|
},
|
|
},
|
|
{
|
|
name: 'description',
|
|
type: 'richText',
|
|
label: 'Beschreibung',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'shortDescription',
|
|
type: 'textarea',
|
|
label: 'Kurzbeschreibung',
|
|
localized: true,
|
|
admin: {
|
|
description: 'Für kompakte Ansichten (max. 200 Zeichen empfohlen)',
|
|
},
|
|
},
|
|
|
|
// Medien
|
|
{
|
|
name: 'image',
|
|
type: 'upload',
|
|
relationTo: 'media',
|
|
label: 'Bild',
|
|
},
|
|
{
|
|
name: 'gallery',
|
|
type: 'array',
|
|
label: 'Galerie',
|
|
admin: {
|
|
description: 'Zusätzliche Bilder für dieses Ereignis',
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'image',
|
|
type: 'upload',
|
|
relationTo: 'media',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'caption',
|
|
type: 'text',
|
|
label: 'Bildunterschrift',
|
|
localized: true,
|
|
},
|
|
],
|
|
},
|
|
|
|
// Kategorisierung
|
|
{
|
|
name: 'category',
|
|
type: 'select',
|
|
label: 'Kategorie',
|
|
admin: {
|
|
description: 'Zur Filterung und farblichen Unterscheidung',
|
|
},
|
|
options: [
|
|
{ label: 'Meilenstein', value: 'milestone' },
|
|
{ label: 'Gründung/Start', value: 'founding' },
|
|
{ label: 'Produkt', value: 'product' },
|
|
{ label: 'Team/Personal', value: 'team' },
|
|
{ label: 'Auszeichnung', value: 'award' },
|
|
{ label: 'Partnerschaft', value: 'partnership' },
|
|
{ label: 'Expansion', value: 'expansion' },
|
|
{ label: 'Technologie', value: 'technology' },
|
|
{ label: 'Sonstiges', value: 'other' },
|
|
],
|
|
},
|
|
{
|
|
name: 'importance',
|
|
type: 'select',
|
|
defaultValue: 'normal',
|
|
label: 'Wichtigkeit',
|
|
options: [
|
|
{ label: 'Highlight', value: 'highlight' },
|
|
{ label: 'Normal', value: 'normal' },
|
|
{ label: 'Minor', value: 'minor' },
|
|
],
|
|
admin: {
|
|
description: 'Highlights werden visuell hervorgehoben',
|
|
},
|
|
},
|
|
|
|
// Prozess-spezifische Felder (für einfache Prozesse wie Onboarding, Bewerbung)
|
|
{
|
|
name: 'stepNumber',
|
|
type: 'number',
|
|
label: 'Schritt-Nummer',
|
|
admin: {
|
|
description: 'Explizite Nummerierung (optional, sonst wird Reihenfolge verwendet)',
|
|
condition: (data) => data?.type === 'process',
|
|
},
|
|
},
|
|
{
|
|
name: 'duration',
|
|
type: 'text',
|
|
label: 'Dauer',
|
|
localized: true,
|
|
admin: {
|
|
description: 'z.B. "2-3 Tage", "1 Woche", "30 Minuten"',
|
|
condition: (data) => data?.type === 'process',
|
|
},
|
|
},
|
|
{
|
|
name: 'responsible',
|
|
type: 'text',
|
|
label: 'Verantwortlich',
|
|
localized: true,
|
|
admin: {
|
|
description: 'Person oder Rolle (z.B. "HR-Team", "Projektleiter")',
|
|
condition: (data) => data?.type === 'process',
|
|
},
|
|
},
|
|
{
|
|
name: 'actionRequired',
|
|
type: 'select',
|
|
label: 'Aktion erforderlich von',
|
|
admin: {
|
|
description: 'Wer muss in diesem Schritt aktiv werden?',
|
|
condition: (data) => data?.type === 'process',
|
|
},
|
|
options: [
|
|
{ label: 'Kunde/Bewerber', value: 'customer' },
|
|
{ label: 'Internes Team', value: 'internal' },
|
|
{ label: 'Beide Seiten', value: 'both' },
|
|
{ label: 'Automatisch', value: 'automatic' },
|
|
],
|
|
},
|
|
{
|
|
name: 'deliverables',
|
|
type: 'array',
|
|
label: 'Ergebnisse/Dokumente',
|
|
admin: {
|
|
description: 'Was wird in diesem Schritt erstellt oder benötigt?',
|
|
condition: (data) => data?.type === 'process',
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'name',
|
|
type: 'text',
|
|
required: true,
|
|
label: 'Name',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'type',
|
|
type: 'select',
|
|
defaultValue: 'output',
|
|
label: 'Typ',
|
|
options: [
|
|
{ label: 'Ergebnis (Output)', value: 'output' },
|
|
{ label: 'Benötigt (Input)', value: 'input' },
|
|
{ label: 'Dokument', value: 'document' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
|
|
// Icon & Styling
|
|
{
|
|
name: 'icon',
|
|
type: 'text',
|
|
label: 'Icon',
|
|
admin: {
|
|
description: 'Emoji oder Lucide Icon-Name (z.B. "rocket", "award", "users")',
|
|
},
|
|
},
|
|
{
|
|
name: 'color',
|
|
type: 'text',
|
|
label: 'Farbe (optional)',
|
|
admin: {
|
|
description: 'Überschreibt die Kategorie-Farbe (z.B. "#FF5733" oder "blue")',
|
|
},
|
|
},
|
|
|
|
// Links
|
|
{
|
|
name: 'links',
|
|
type: 'array',
|
|
label: 'Links',
|
|
fields: [
|
|
{
|
|
name: 'label',
|
|
type: 'text',
|
|
required: true,
|
|
label: 'Link-Text',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'url',
|
|
type: 'text',
|
|
required: true,
|
|
label: 'URL',
|
|
},
|
|
{
|
|
name: 'type',
|
|
type: 'select',
|
|
defaultValue: 'internal',
|
|
label: 'Link-Typ',
|
|
options: [
|
|
{ label: 'Intern', value: 'internal' },
|
|
{ label: 'Extern', value: 'external' },
|
|
{ label: 'Download', value: 'download' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
|
|
// Zusätzliche Daten
|
|
{
|
|
name: 'metadata',
|
|
type: 'json',
|
|
label: 'Zusätzliche Daten (JSON)',
|
|
admin: {
|
|
description: 'Für spezielle Anwendungsfälle (z.B. Statistiken, Kennzahlen)',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
|
|
// SEO
|
|
{
|
|
name: 'seo',
|
|
type: 'group',
|
|
label: 'SEO',
|
|
admin: {
|
|
position: 'sidebar',
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'metaTitle',
|
|
type: 'text',
|
|
label: 'Meta-Titel',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'metaDescription',
|
|
type: 'textarea',
|
|
label: 'Meta-Beschreibung',
|
|
localized: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
hooks: {
|
|
beforeChange: [
|
|
({ data }) => {
|
|
// Auto-generate slug from name if not provided
|
|
if (data && !data.slug && data.name) {
|
|
data.slug = data.name
|
|
.toLowerCase()
|
|
.replace(/[äöüß]/g, (match: string) => {
|
|
const map: Record<string, string> = { ä: 'ae', ö: 'oe', ü: 'ue', ß: 'ss' }
|
|
return map[match] || match
|
|
})
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-|-$/g, '')
|
|
}
|
|
return data
|
|
},
|
|
],
|
|
},
|
|
}
|