feat: add tournament suggestions job and notification system
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 56s

- Implemented a scheduled job for fetching tournament suggestions in the scheduler service.
- Added a new service for handling tournament suggestions, including fetching and updating suggestions.
- Created notification system with models, controllers, and services for managing user notifications.
- Introduced a notification bell component in the frontend to display unread notifications.
- Added a notifications view for users to see all notifications and mark them as read.
- Updated API client and socket service to handle notifications and authentication.
- Created database migrations for notifications and tournament suggestions.
This commit is contained in:
Torsten Schulz (local)
2026-08-14 11:14:07 +02:00
parent 351fe588c1
commit bc9e7cfe3c
26 changed files with 643 additions and 13 deletions

View File

@@ -16,7 +16,7 @@ import {
TournamentMember, Accident, UserToken, OfficialTournament, OfficialCompetition, OfficialCompetitionMember, MyTischtennis, ClickTtAccount, MyTischtennisUpdateHistory, MyTischtennisFetchLog, ApiLog, MemberTransferConfig, MemberContact, MemberTtrHistory, MemberPlayInterest,
MemberOrder, MemberOrderHistory, MemberGroupPhoto, BillingTemplate, BillingTemplateField, BillingRun, BillingDocument, BillingDocumentValue, BillingUserSetting, FriendlyMatch, TrainingCancellation
, FriendlyMatchShared, FriendlyMatchInvitation
, CalendarEvent, ClubVenue, ClubRequest, ClubRequestNote, ClubSepaMandate, ClubPaymentClaim, ClubAccount, ClubAccountTransaction, ClubInvoiceParty, ClubInvoice, ClubInvoiceItem, ClubRole, ClubUserRole, ClubCommunicationThread, ClubCommunicationMessage, ClubCommunicationRecipient, ClubCommunicationDeliveryLog, ClubCommunicationTemplate, ClubDistributionGroup, ClubDistributionGroupMember, MemberProfileChangeRequest, MemberEventResponse
, CalendarEvent, ClubVenue, ClubRequest, ClubRequestNote, ClubSepaMandate, ClubPaymentClaim, ClubAccount, ClubAccountTransaction, ClubInvoiceParty, ClubInvoice, ClubInvoiceItem, ClubRole, ClubUserRole, ClubCommunicationThread, ClubCommunicationMessage, ClubCommunicationRecipient, ClubCommunicationDeliveryLog, ClubCommunicationTemplate, ClubDistributionGroup, ClubDistributionGroupMember, MemberProfileChangeRequest, MemberEventResponse, NotificationEvent, NotificationRecipient, TournamentSuggestion
} from './models/index.js';
import authRoutes from './routes/authRoutes.js';
import clubRoutes from './routes/clubRoutes.js';
@@ -78,6 +78,7 @@ import clubInvoiceRoutes from './routes/clubInvoiceRoutes.js';
import clubPaymentClaimRoutes from './routes/clubPaymentClaimRoutes.js';
import clubCommunicationRoutes from './routes/clubCommunicationRoutes.js';
import clubDocumentRoutes from './routes/clubDocumentRoutes.js';
import notificationRoutes from './routes/notificationRoutes.js';
import schedulerService from './services/schedulerService.js';
import { requestLoggingMiddleware } from './middleware/requestLoggingMiddleware.js';
import HttpError from './exceptions/HttpError.js';
@@ -263,13 +264,17 @@ function stripJsonLdByType(html, schemaType) {
app.set('trust proxy', true);
// CORS-Konfiguration - Socket.IO hat seine eigene CORS-Konfiguration
app.use(cors({
// CORS-Konfiguration. Der explizite OPTIONS-Handler ist für lokale Vite-Hosts
// wichtig: POST/PUT/PATCH mit authcode lösen einen Browser-Preflight aus.
const corsOptions = {
origin: true,
credentials: true,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'authcode', 'userid']
}));
allowedHeaders: ['Content-Type', 'Authorization', 'authcode', 'userid'],
optionsSuccessStatus: 204,
};
app.options('*', cors(corsOptions));
app.use(cors(corsOptions));
app.use('/api/clicktt/proxy', express.raw({
type: ['multipart/form-data', 'application/octet-stream'],
@@ -379,6 +384,7 @@ app.use('/api/calendar', calendarRoutes);
app.use('/api/calendar-events', calendarEventRoutes);
app.use('/api/mobile-feedback', mobileFeedbackRoutes);
app.use('/api/club-requests', clubRequestRoutes);
app.use('/api/notifications', notificationRoutes);
app.use('/api/club-dashboard', clubDashboardRoutes);
app.use('/api/club-tasks', clubTaskRoutes);
app.use('/api/club-statistics', clubStatisticsRoutes);
@@ -664,6 +670,9 @@ app.use((err, req, res, next) => {
await safeSync(CalendarEvent);
await safeSync(MemberProfileChangeRequest);
await safeSync(MemberEventResponse);
await safeSync(NotificationEvent);
await safeSync(NotificationRecipient);
await safeSync(TournamentSuggestion);
await safeSync(TeamDocument);
// Foreign Keys wieder aktivieren