Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/danielsl4/TFG_DAM_2526/llms.txt

Use this file to discover all available pages before exploring further.

Matches are the core unit of competition in FutsalManager. Admins create matches before the season starts, assign teams and fields, and can update team assignments for knockout brackets as results come in. Every admin action on a match is written to the audit log automatically.

Create a match

POST /matches
New matches are always created with status = 'pendiente'. Request body:
{
  "date": "2025-10-15T19:00:00",
  "homeTeamId": 4,
  "awayTeamId": 7,
  "fieldId": 2,
  "groupId": 1,
  "seasonId": 5,
  "phase": "fase_de_grupos",
  "homePlaceholder": null,
  "awayPlaceholder": null
}
FieldRequiredDescription
dateYesISO datetime string for kick-off.
homeTeamIdNoID of the home team. Can be null for knockout matches where the team is not yet determined.
awayTeamIdNoID of the away team. Can be null for the same reason.
fieldIdYesID of the field where the match is played.
groupIdYesID of the group this match belongs to.
seasonIdYesID of the season.
phaseNoDefaults to "fase_de_grupos". Use other values (e.g. "cuartos", "semifinal", "final") for knockout rounds.
homePlaceholderNoDisplay label when the home team is not yet known (e.g. "Winner Group A").
awayPlaceholderNoDisplay label when the away team is not yet known.
For knockout matches, leave homeTeamId and awayTeamId as null and fill in homePlaceholder / awayPlaceholder with descriptive labels. Update the real team IDs later with PUT /matches/:id/teams once the bracket is set.
Successful response:
{
  "message": "Partido creado correctamente",
  "id": 42
}
Creating a match automatically invalidates the relevant Redis caches for the season.

Update teams on a knockout match

PUT /matches/:id/teams
Use this endpoint to fill in the actual teams once a knockout bracket is determined, without having to delete and recreate the match. Request body:
{
  "homeTeamId": 9,
  "awayTeamId": 11,
  "homePlaceholder": null,
  "awayPlaceholder": null
}
All four fields are optional. Pass null to clear a value. The response confirms success and the match cache is invalidated.

Delete a match

DELETE /matches/:id
Deleting a match removes all associated records in a specific order to avoid foreign-key errors:
  1. All match_events for the match are deleted first.
  2. All match_votes for the match are deleted.
  3. The match row itself is deleted.
Match deletion is permanent and cannot be undone. Player statistics that were accumulated from events in this match are not automatically recalculated. Delete matches only before they have been refereed, or re-enter the data in a new match.

Upload an image

POST /admin/upload
Upload a team logo, player photo, or any other image asset. The file is processed with Sharp and stored in Cloudinary. Request format: multipart/form-data with a field named image. Query parameters:
ParameterRequiredDescription
folderNoCloudinary folder to store the image in. Defaults to "general".
filenameNoCustom filename. Cloudinary generates one if omitted.
Example:
curl -X POST /admin/upload \
  -H "Authorization: Bearer <token>" \
  -F "[email protected]" \
  "?folder=teams&filename=equipo-norte"
Successful response:
{
  "url": "https://res.cloudinary.com/..."
}
Store the returned URL in the logo_url field of a team or the photo_url field of a player.

Audit log

Every admin write action — creating a season, scheduling a match, updating teams — is recorded via logAction() with:
  • The user ID who performed the action.
  • A human-readable action label (e.g. "Creación de partido").
  • The entity type and entity ID affected.
  • A JSON details object with relevant IDs and names.
You can read the five most recent entries from GET /admin/summary (see the admin overview). For a full audit history, query the audit_logs table directly.

Build docs developers (and LLMs) love