Major changes: - Docker Compose: full Supabase stack (11 services) equivalent to supabase CLI - Fischerei module: 16 DB tables, waters/species/stocking/catch books/competitions - Sitzungsprotokolle module: meeting protocols, agenda items, task tracking - Verbandsverwaltung module: federation management, member clubs, contacts, fees - Per-account module activation via Modules page toggle - Site Builder: live CMS data in Puck blocks (courses, events, membership registration) - Public registration APIs: course signup, event registration, membership application - Document generation: PDF member cards, Excel reports, HTML labels - Landing page: real Com.BISS content (no filler text) - UX audit fixes: AccountNotFound component, shared status badges, confirm dialog, pagination, duplicate heading removal, emoji→badge replacement, a11y fixes - QA: healthcheck fix, API auth fix, enum mismatch fix, password required attribute
197 lines
6.3 KiB
TypeScript
197 lines
6.3 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
// =====================================================
|
|
// Enum Schemas
|
|
// =====================================================
|
|
|
|
export const associationTypeSchema = z.enum([
|
|
'sportverein',
|
|
'fischereiverein',
|
|
'schuetzenverein',
|
|
'musikverein',
|
|
'kulturverein',
|
|
'foerderverein',
|
|
'jugendverein',
|
|
'sonstige',
|
|
]);
|
|
|
|
export const paymentMethodSchema = z.enum([
|
|
'bar',
|
|
'lastschrift',
|
|
'ueberweisung',
|
|
'paypal',
|
|
]);
|
|
|
|
export const billingStatusSchema = z.enum([
|
|
'offen',
|
|
'bezahlt',
|
|
'ueberfaellig',
|
|
'storniert',
|
|
]);
|
|
|
|
export const noteTypeSchema = z.enum([
|
|
'notiz',
|
|
'aufgabe',
|
|
'erinnerung',
|
|
]);
|
|
|
|
export const contactRoleSchema = z.enum([
|
|
'vorsitzender',
|
|
'stellvertreter',
|
|
'kassier',
|
|
'schriftfuehrer',
|
|
'jugendwart',
|
|
'sportwart',
|
|
'beisitzer',
|
|
'sonstige',
|
|
]);
|
|
|
|
// =====================================================
|
|
// Type Exports
|
|
// =====================================================
|
|
|
|
export type AssociationType = z.infer<typeof associationTypeSchema>;
|
|
export type PaymentMethod = z.infer<typeof paymentMethodSchema>;
|
|
export type BillingStatus = z.infer<typeof billingStatusSchema>;
|
|
export type NoteType = z.infer<typeof noteTypeSchema>;
|
|
export type ContactRole = z.infer<typeof contactRoleSchema>;
|
|
|
|
// =====================================================
|
|
// Member Clubs (Vereine)
|
|
// =====================================================
|
|
|
|
export const CreateMemberClubSchema = z.object({
|
|
accountId: z.string().uuid(),
|
|
name: z.string().min(1, 'Name ist erforderlich').max(256),
|
|
shortName: z.string().max(32).optional(),
|
|
associationTypeId: z.string().uuid().optional(),
|
|
memberCount: z.number().int().min(0).optional(),
|
|
foundedYear: z.number().int().min(1800).max(2100).optional(),
|
|
street: z.string().max(256).optional(),
|
|
zip: z.string().max(10).optional(),
|
|
city: z.string().max(128).optional(),
|
|
phone: z.string().max(64).optional(),
|
|
email: z.string().email().optional().or(z.literal('')),
|
|
website: z.string().url().optional().or(z.literal('')),
|
|
iban: z.string().max(34).optional(),
|
|
bic: z.string().max(11).optional(),
|
|
accountHolder: z.string().max(256).optional(),
|
|
isArchived: z.boolean().default(false),
|
|
});
|
|
|
|
export type CreateMemberClubInput = z.infer<typeof CreateMemberClubSchema>;
|
|
|
|
export const UpdateMemberClubSchema = CreateMemberClubSchema.partial().extend({
|
|
clubId: z.string().uuid(),
|
|
});
|
|
|
|
export type UpdateMemberClubInput = z.infer<typeof UpdateMemberClubSchema>;
|
|
|
|
// =====================================================
|
|
// Club Contacts (Ansprechpartner)
|
|
// =====================================================
|
|
|
|
export const CreateClubContactSchema = z.object({
|
|
clubId: z.string().uuid(),
|
|
firstName: z.string().min(1, 'Vorname ist erforderlich').max(128),
|
|
lastName: z.string().min(1, 'Nachname ist erforderlich').max(128),
|
|
role: contactRoleSchema.default('sonstige'),
|
|
phone: z.string().max(64).optional(),
|
|
email: z.string().email().optional().or(z.literal('')),
|
|
isPrimary: z.boolean().default(false),
|
|
});
|
|
|
|
export type CreateClubContactInput = z.infer<typeof CreateClubContactSchema>;
|
|
|
|
export const UpdateClubContactSchema = CreateClubContactSchema.partial().extend({
|
|
contactId: z.string().uuid(),
|
|
});
|
|
|
|
export type UpdateClubContactInput = z.infer<typeof UpdateClubContactSchema>;
|
|
|
|
// =====================================================
|
|
// Club Roles (Funktionen im Verband)
|
|
// =====================================================
|
|
|
|
export const CreateClubRoleSchema = z.object({
|
|
accountId: z.string().uuid(),
|
|
name: z.string().min(1, 'Name ist erforderlich').max(128),
|
|
description: z.string().max(512).optional(),
|
|
sortOrder: z.number().int().default(0),
|
|
});
|
|
|
|
export type CreateClubRoleInput = z.infer<typeof CreateClubRoleSchema>;
|
|
|
|
// =====================================================
|
|
// Association Types (Vereinstypen)
|
|
// =====================================================
|
|
|
|
export const CreateAssociationTypeSchema = z.object({
|
|
accountId: z.string().uuid(),
|
|
name: z.string().min(1, 'Name ist erforderlich').max(128),
|
|
description: z.string().max(512).optional(),
|
|
sortOrder: z.number().int().default(0),
|
|
});
|
|
|
|
export type CreateAssociationTypeInput = z.infer<typeof CreateAssociationTypeSchema>;
|
|
|
|
// =====================================================
|
|
// Club Fee Types (Beitragsarten)
|
|
// =====================================================
|
|
|
|
export const CreateClubFeeTypeSchema = z.object({
|
|
accountId: z.string().uuid(),
|
|
name: z.string().min(1, 'Name ist erforderlich').max(128),
|
|
description: z.string().max(512).optional(),
|
|
defaultAmount: z.number().min(0).optional(),
|
|
isActive: z.boolean().default(true),
|
|
});
|
|
|
|
export type CreateClubFeeTypeInput = z.infer<typeof CreateClubFeeTypeSchema>;
|
|
|
|
// =====================================================
|
|
// Club Fee Billings (Beitragsabrechnungen)
|
|
// =====================================================
|
|
|
|
export const CreateClubFeeBillingSchema = z.object({
|
|
clubId: z.string().uuid(),
|
|
feeTypeId: z.string().uuid(),
|
|
year: z.number().int().min(2000).max(2100),
|
|
amount: z.number().min(0),
|
|
dueDate: z.string().optional(),
|
|
paidDate: z.string().optional(),
|
|
paymentMethod: paymentMethodSchema.optional(),
|
|
status: billingStatusSchema.default('offen'),
|
|
notes: z.string().max(1024).optional(),
|
|
});
|
|
|
|
export type CreateClubFeeBillingInput = z.infer<typeof CreateClubFeeBillingSchema>;
|
|
|
|
// =====================================================
|
|
// Club Notes (Notizen / Aufgaben)
|
|
// =====================================================
|
|
|
|
export const CreateClubNoteSchema = z.object({
|
|
clubId: z.string().uuid(),
|
|
title: z.string().min(1, 'Titel ist erforderlich').max(256),
|
|
content: z.string().optional(),
|
|
noteType: noteTypeSchema.default('notiz'),
|
|
dueDate: z.string().optional(),
|
|
isCompleted: z.boolean().default(false),
|
|
});
|
|
|
|
export type CreateClubNoteInput = z.infer<typeof CreateClubNoteSchema>;
|
|
|
|
// =====================================================
|
|
// Association History (Verbandshistorie)
|
|
// =====================================================
|
|
|
|
export const CreateAssociationHistorySchema = z.object({
|
|
clubId: z.string().uuid(),
|
|
year: z.number().int().min(1800).max(2100),
|
|
memberCount: z.number().int().min(0).optional(),
|
|
notes: z.string().max(2048).optional(),
|
|
});
|
|
|
|
export type CreateAssociationHistoryInput = z.infer<typeof CreateAssociationHistorySchema>;
|