22 Commits

Author SHA1 Message Date
Torsten Schulz (local)
3ac4039097 feat: implement user linking for members and update database schema for user associations
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 53s
2026-07-22 23:54:45 +02:00
Torsten Schulz (local)
46079fc16e feat: update navigation link for club payments in dashboard and enhance error handling in Home view
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-22 16:17:19 +02:00
Torsten Schulz (local)
e38f2c2e19 feat: add archived documents section and filtering options to club archive view
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s
2026-07-22 16:07:31 +02:00
Torsten Schulz (local)
d190c2cb70 feat: add optional reply address to communication threads and enhance email transport status handling
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s
2026-07-22 15:28:39 +02:00
Torsten Schulz (local)
fd0b3020bf feat: implement load request ID for improved data loading consistency across views
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s
2026-07-22 15:25:00 +02:00
Torsten Schulz (local)
8e4edfb719 style: improve button styling and layout for schedule actions and summary bar
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 1m4s
2026-07-22 15:09:23 +02:00
Torsten Schulz (local)
01f80ea094 style: enhance layout and styling of schedule summary items and summary bar
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s
2026-07-22 15:04:17 +02:00
Torsten Schulz (local)
8140283b7a feat: improve schedule view layout and controls for match overview
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s
2026-07-22 14:57:13 +02:00
Torsten Schulz (local)
48f0f9afb0 fix: update app version to 1.7.10 and SDK versions to 36
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 2m28s
2026-07-22 14:38:33 +02:00
Torsten Schulz (local)
ad778328e8 feat: add team name normalization for selected schedule in PDF generation
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 50s
2026-07-17 16:01:39 +02:00
Torsten Schulz (local)
91006bb0c5 fix: adjust table font size and improve cell content formatting in PDF generation
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s
2026-07-17 15:51:15 +02:00
Torsten Schulz (local)
110519c7b8 feat: add team name normalization for club matching in match service
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 15:35:57 +02:00
Torsten Schulz (local)
6afa5a5629 fix: improve existing match handling in CSV import to ensure correct league and location updates
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 50s
2026-07-17 15:19:23 +02:00
Torsten Schulz (local)
7bf7ae2bef fix: ensure leagueId is retained when editing a team to prevent accidental removal of MyTischtennis link
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 14:53:06 +02:00
Torsten Schulz (local)
51b620f496 feat: enhance table generation in PDF with optional cell pinning for teams
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 14:28:12 +02:00
Torsten Schulz (local)
f83e3986b7 feat: add age group code extraction and link youth club teams to imported leagues
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 50s
2026-07-17 14:10:52 +02:00
Torsten Schulz (local)
bb9a030e89 fix: update clubId handling in CSV upload to support query parameters and improve form data processing
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 53s
2026-07-17 14:02:54 +02:00
Torsten Schulz (local)
a767061bd3 fix: remove manual Content-Type setting for CSV import to ensure proper form data handling
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 13:58:10 +02:00
Torsten Schulz (local)
35031e3ae5 fix: improve error handling for CSV import in upload and ScheduleView
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 13:48:56 +02:00
Torsten Schulz (local)
370df07c2a feat: implement team name normalization and enhance CSV import match detection
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 12:25:58 +02:00
Torsten Schulz (local)
94385231d3 fix: update CSV import to correctly decode Windows-1252 encoding for venue names
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s
2026-07-17 12:00:17 +02:00
Torsten Schulz (local)
5357dac9e1 chore: update file permissions for multiple files and add migration for club fee rules
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 54s
- Changed file permissions from 644 to 755 for various files in the mobile-app and mobile-app_legacy_rn_expo directories, ensuring executable permissions where necessary.
- Added a new SQL migration script to the backend to introduce missing columns for club billing and invoice settings in the clubs table, maintaining synchronization with the current Sequelize model.
2026-07-17 11:51:24 +02:00
964 changed files with 1167 additions and 249 deletions

0
.codex Normal file → Executable file
View File

0
.cursor/commands/club-settings.md Normal file → Executable file
View File

0
.cursor/commands/oldfkchecks.md Normal file → Executable file
View File

0
.gitea/workflows/deploy.yml Normal file → Executable file
View File

0
.gitignore vendored Normal file → Executable file
View File

0
Advanced Normal file → Executable file
View File

0
Autofill Normal file → Executable file
View File

0
CHECK_SERVER.md Normal file → Executable file
View File

0
CODEx_MIGRATION_RULES.md Normal file → Executable file
View File

0
DEPLOYMENT_SOCKET_IO.md Normal file → Executable file
View File

0
DSGVO_CHECKLIST.md Normal file → Executable file
View File

0
Languages Normal file → Executable file
View File

0
PERMISSIONS_GUIDE.md Normal file → Executable file
View File

0
PERMISSIONS_MIGRATION.md Normal file → Executable file
View File

0
SERVER_NODE_UPGRADE.md Normal file → Executable file
View File

0
SITEMAP_ANLEITUNG.md Normal file → Executable file
View File

0
System Normal file → Executable file
View File

0
TrainingsTagebuch.code-workspace Normal file → Executable file
View File

0
apache-http.conf.example Normal file → Executable file
View File

0
apache-https.conf.example Normal file → Executable file
View File

0
apache.conf.example Normal file → Executable file
View File

0
backend/CLICKTT_HTTV_README.md Normal file → Executable file
View File

0
backend/MYTISCHTENNIS_AUTO_FETCH_README.md Normal file → Executable file
View File

0
backend/MYTISCHTENNIS_URL_PARSER_README.md Normal file → Executable file
View File

0
backend/README_CLEANUP.md Normal file → Executable file
View File

0
backend/SOCKET_IO_SSL_SETUP.md Normal file → Executable file
View File

0
backend/checkRealIndexes.sql Normal file → Executable file
View File

0
backend/checkTableNames.sql Normal file → Executable file
View File

0
backend/cleanupKeys.sql Normal file → Executable file
View File

0
backend/cleanupKeysAggressive.sql Normal file → Executable file
View File

0
backend/cleanupKeysCorrected.sql Normal file → Executable file
View File

0
backend/cleanupKeysFinal.sql Normal file → Executable file
View File

0
backend/cleanupKeysIntelligent.sql Normal file → Executable file
View File

0
backend/cleanupKeysMinimal.sql Normal file → Executable file
View File

0
backend/cleanupKeysNode.cjs Normal file → Executable file
View File

0
backend/cleanupKeysNode.js Normal file → Executable file
View File

0
backend/cleanupKeysReal.sql Normal file → Executable file
View File

0
backend/cleanupKeysSimple.sql Normal file → Executable file
View File

0
backend/cleanupKeysSmart.sql Normal file → Executable file
View File

0
backend/clients/myTischtennisClient.js Normal file → Executable file
View File

0
backend/config.js Normal file → Executable file
View File

0
backend/constants/ERROR_CODES_USAGE.md Normal file → Executable file
View File

0
backend/constants/errorCodes.js Normal file → Executable file
View File

0
backend/controllers/accidentController.js Normal file → Executable file
View File

0
backend/controllers/activityController.js Normal file → Executable file
View File

0
backend/controllers/apiLogController.js Normal file → Executable file
View File

0
backend/controllers/authController.js Normal file → Executable file
View File

0
backend/controllers/billingController.js Normal file → Executable file
View File

0
backend/controllers/calendarController.js Normal file → Executable file
View File

0
backend/controllers/calendarEventController.js Normal file → Executable file
View File

0
backend/controllers/clickTtAccountController.js Normal file → Executable file
View File

0
backend/controllers/clubAccountController.js Normal file → Executable file
View File

0
backend/controllers/clubArchiveController.js Normal file → Executable file
View File

0
backend/controllers/clubCommunicationController.js Normal file → Executable file
View File

2
backend/controllers/clubDashboardController.js Normal file → Executable file
View File

@@ -610,7 +610,7 @@ export const getClubDashboard = async (req, res) => {
title: 'Finanzen',
value: paidRatio === null ? 'Keine Daten' : `${paidRatio} % erledigt`,
meta: paymentClaims.length > 0 ? `${paymentClaims.length} offene oder teilweise offene Forderungen` : 'Noch keine Beitragsforderungen erfasst',
to: '/club-tasks',
to: '/club-payments',
},
],
},

0
backend/controllers/clubDocumentController.js Normal file → Executable file
View File

0
backend/controllers/clubInvoiceController.js Normal file → Executable file
View File

0
backend/controllers/clubPaymentClaimController.js Normal file → Executable file
View File

0
backend/controllers/clubRequestController.js Normal file → Executable file
View File

0
backend/controllers/clubStatisticsController.js Normal file → Executable file
View File

0
backend/controllers/clubTaskController.js Normal file → Executable file
View File

0
backend/controllers/clubTeamController.js Normal file → Executable file
View File

0
backend/controllers/clubVenueController.js Normal file → Executable file
View File

0
backend/controllers/clubsController.js Normal file → Executable file
View File

0
backend/controllers/diaryController.js Normal file → Executable file
View File

0
backend/controllers/diaryDateActivityController.js Normal file → Executable file
View File

0
backend/controllers/diaryDateTagController.js Normal file → Executable file
View File

0
backend/controllers/diaryMemberActivityController.js Normal file → Executable file
View File

0
backend/controllers/diaryMemberController.js Normal file → Executable file
View File

0
backend/controllers/diaryNoteController.js Normal file → Executable file
View File

0
backend/controllers/diaryTagController.js Normal file → Executable file
View File

0
backend/controllers/friendlyMatchController.js Normal file → Executable file
View File

View File

0
backend/controllers/friendlyMatchSharedController.js Normal file → Executable file
View File

0
backend/controllers/groupController.js Normal file → Executable file
View File

6
backend/controllers/matchController.js Normal file → Executable file
View File

@@ -4,7 +4,7 @@ import { emitScheduleMatchUpdated } from '../services/socketService.js';
import { devLog } from '../utils/logger.js';
export const uploadCSV = async (req, res) => {
try {
const { clubId } = req.body;
const clubId = req.body?.clubId ?? req.query?.clubId;
const { authcode: userToken} = req.headers;
const filePath = req.file.path;
const result = await MatchService.importCSV(userToken, clubId, filePath);
@@ -16,7 +16,9 @@ export const uploadCSV = async (req, res) => {
});
} catch (error) {
console.error('Error importing CSV:', error);
return res.status(500).json({ error: 'Failed to import CSV data' });
return res.status(500).json({
error: error.message || 'Failed to import CSV data'
});
}
};

0
backend/controllers/memberActivityController.js Normal file → Executable file
View File

27
backend/controllers/memberController.js Normal file → Executable file
View File

@@ -2,6 +2,8 @@ import MemberService from "../services/memberService.js";
import MemberTransferService from "../services/memberTransferService.js";
import clickTtPlayerRegistrationService from "../services/clickTtPlayerRegistrationService.js";
import { emitMemberChanged } from '../services/socketService.js';
import Member from '../models/Member.js';
import UserClub from '../models/UserClub.js';
import { devLog } from '../utils/logger.js';
const getClubMembers = async(req, res) => {
@@ -351,6 +353,28 @@ const transferMembers = async (req, res) => {
}
};
const linkMemberUser = async (req, res) => {
try {
const clubId = Number(req.params.clubId);
const memberId = Number(req.params.memberId);
const userId = Number(req.body?.userId);
if (!clubId || !memberId || !userId) return res.status(400).json({ error: 'Mitglied, Verein und Benutzer sind erforderlich.' });
const [member, clubUser, existing] = await Promise.all([
Member.findOne({ where: { id: memberId, clubId } }),
UserClub.findOne({ where: { clubId, userId, approved: true } }),
Member.findOne({ where: { userId } }),
]);
if (!member || !clubUser) return res.status(404).json({ error: 'Mitglied oder freigegebener Vereinsbenutzer wurde nicht gefunden.' });
if (existing && Number(existing.id) !== memberId) return res.status(409).json({ error: 'Dieses Benutzerkonto ist bereits einem Mitglied zugeordnet.' });
await member.update({ userId });
emitMemberChanged(clubId);
res.json({ memberId, userId });
} catch (error) {
console.error('[linkMemberUser] - Error:', error);
res.status(500).json({ error: 'Mitglied konnte nicht verknüpft werden.' });
}
};
export {
getClubMembers,
getWaitingApprovals,
@@ -372,5 +396,6 @@ export {
requestClickTtPlayerRegistration,
deleteMemberImage,
setPrimaryMemberImage,
generateMemberGallery
generateMemberGallery,
linkMemberUser
};

0
backend/controllers/memberGroupPhotoController.js Normal file → Executable file
View File

0
backend/controllers/memberNoteController.js Normal file → Executable file
View File

0
backend/controllers/memberOrderController.js Normal file → Executable file
View File

0
backend/controllers/memberTransferConfigController.js Normal file → Executable file
View File

0
backend/controllers/mobileFeedbackController.js Normal file → Executable file
View File

0
backend/controllers/myTischtennisController.js Normal file → Executable file
View File

46
backend/controllers/myTischtennisUrlController.js Normal file → Executable file
View File

@@ -250,39 +250,37 @@ class MyTischtennisUrlController {
throw new HttpError('Club team not found', 404);
}
let league;
// First, try to find existing league by name and season
const leagueName = completeData.leagueName || completeData.groupname;
league = await League.findOne({
where: {
name: leagueName,
seasonId: season.id,
clubId: team.clubId
let league;
// The league chosen for a club team is also used by the schedule filters.
// Keep that assignment and only enrich it with the MyTischtennis metadata.
if (team.leagueId) {
league = await League.findOne({
where: { id: team.leagueId, clubId: team.clubId }
});
if (league) {
devLog(`Keeping team's existing league: ${league.name} (ID: ${league.id})`);
}
});
}
if (!league) {
league = await League.findOne({
where: {
name: leagueName,
seasonId: season.id,
clubId: team.clubId
}
});
}
if (league) {
devLog(`Found existing league: ${league.name} (ID: ${league.id})`);
// Update myTischtennis fields
devLog(`Using existing league: ${league.name} (ID: ${league.id})`);
await league.update({
myTischtennisGroupId: completeData.groupId,
association: completeData.association,
groupname: completeData.groupname
});
} else if (team.leagueId) {
// Team has a league assigned, update it
league = await League.findByPk(team.leagueId);
if (league) {
devLog(`Updating team's existing league: ${league.name} (ID: ${league.id})`);
await league.update({
name: leagueName,
myTischtennisGroupId: completeData.groupId,
association: completeData.association,
groupname: completeData.groupname
});
}
} else if (createLeague) {
// Create new league
devLog(`Creating new league: ${leagueName}`);

0
backend/controllers/officialTournamentController.js Normal file → Executable file
View File

0
backend/controllers/participantController.js Normal file → Executable file
View File

0
backend/controllers/permissionController.js Normal file → Executable file
View File

0
backend/controllers/predefinedActivityController.js Normal file → Executable file
View File

View File

0
backend/controllers/seasonController.js Normal file → Executable file
View File

0
backend/controllers/sessionController.js Normal file → Executable file
View File

0
backend/controllers/teamController.js Normal file → Executable file
View File

0
backend/controllers/teamDocumentController.js Normal file → Executable file
View File

0
backend/controllers/tournamentController.js Normal file → Executable file
View File

0
backend/controllers/tournamentStagesController.js Normal file → Executable file
View File

0
backend/controllers/trainingCancellationController.js Normal file → Executable file
View File

0
backend/controllers/trainingGroupController.js Normal file → Executable file
View File

0
backend/controllers/trainingStatsController.js Normal file → Executable file
View File

0
backend/controllers/trainingTimeController.js Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More