openapi: 3.0.3 info: title: Amici Scommesse API version: 1.1.0 description: | API per l'applicazione Amici Scommesse - Sistema di gestione scommesse tra amici. **Architettura**: L'API utilizza una architettura a layer con dependency injection, validazione automatica input, e formato risposte standardizzato. **Versioning**: - `/api/v1/*` - API corrente (formato standardizzato) - `/api/legacy/*` - API legacy (backward compatibility) **Autenticazione**: Mock authentication (Mario Rossi hardcoded). JWT da implementare. contact: name: API Support email: support@amiciscommesse.com license: name: ISC servers: - url: http://localhost:3000/api/v1 description: Development server (v1) - url: http://localhost:3000/api/legacy description: Legacy API (backward compatibility) tags: - name: Groups description: Gestione gruppi di utenti - name: Bets description: Gestione scommesse - name: Friend Requests description: Gestione richieste di amicizia - name: Users description: Gestione profilo utente - name: Initial Data description: Caricamento dati iniziali - name: Health description: Health check endpoint components: schemas: # ===== Success Response Wrapper ===== SuccessResponse: type: object required: - success - timestamp properties: success: type: boolean example: true message: type: string example: Operation successful data: type: object timestamp: type: string format: date-time example: '2024-01-01T00:00:00.000Z' # ===== Error Response Wrapper ===== ErrorResponse: type: object required: - success - message - timestamp properties: success: type: boolean example: false message: type: string example: Error message errors: type: array items: type: object properties: field: type: string example: name message: type: string example: Name is required timestamp: type: string format: date-time example: '2024-01-01T00:00:00.000Z' # ===== User ===== User: type: object properties: id: type: integer example: 1 name: type: string example: Mario Rossi email: type: string format: email example: mario.rossi@example.com avatarUrl: type: string nullable: true example: https://example.com/avatar.jpg score: type: integer example: 100 # ===== Group ===== Group: type: object properties: id: type: integer example: 1 name: type: string example: Gruppo Calcio members: type: array items: $ref: '#/components/schemas/User' # ===== Participant ===== Participant: type: object properties: user: oneOf: - type: integer - $ref: '#/components/schemas/User' role: type: string enum: [PARTICIPANT, OBSERVER] example: PARTICIPANT # ===== Bet ===== Bet: type: object properties: id: type: string example: 507f1f77bcf86cd799439011 title: type: string example: Chi vince il campionato? description: type: string nullable: true example: Scommessa sul vincitore del campionato 2024 stake: type: string example: 50 euro participants: type: array items: $ref: '#/components/schemas/Participant' status: type: string enum: [ACTIVE, AWAITING_VALIDATION, COMPLETED, EXPIRED] example: ACTIVE startDate: type: string format: date-time example: '2024-01-01T00:00:00.000Z' endDate: type: string format: date-time nullable: true example: '2024-12-31T23:59:59.000Z' isPublic: type: boolean example: false groupId: type: string nullable: true example: '1' winner: oneOf: - type: integer - $ref: '#/components/schemas/User' nullable: true # ===== Friend Request ===== FriendRequest: type: object properties: id: type: integer example: 1 fromUserId: type: integer example: 1 toUserId: type: integer example: 2 status: type: string enum: [PENDING, ACCEPTED, REJECTED] example: PENDING fromUser: $ref: '#/components/schemas/User' toUser: $ref: '#/components/schemas/User' createdAt: type: string format: date-time updatedAt: type: string format: date-time # ===== Create Group Request ===== CreateGroupRequest: type: object required: - name - members properties: name: type: string minLength: 1 maxLength: 100 example: Gruppo Calcio members: type: array minItems: 1 items: type: integer example: [1, 2, 3] # ===== Update Group Request ===== UpdateGroupRequest: type: object properties: name: type: string minLength: 1 maxLength: 100 example: Nuovo Nome Gruppo # ===== Add Members Request ===== AddMembersRequest: type: object required: - userIds properties: userIds: type: array minItems: 1 items: type: integer example: [4, 5] # ===== Create Bet Request ===== CreateBetRequest: type: object required: - title - stake - participants properties: title: type: string minLength: 1 maxLength: 200 example: Chi vince il campionato? description: type: string maxLength: 1000 example: Scommessa sul vincitore stake: type: string minLength: 1 example: 50 euro participants: type: array minItems: 1 items: type: object required: - user - role properties: user: type: integer role: type: string enum: [PARTICIPANT, OBSERVER] example: - user: 1 role: PARTICIPANT - user: 2 role: PARTICIPANT isPublic: type: boolean default: false example: false groupId: type: string nullable: true example: '1' # ===== Update Bet Request ===== UpdateBetRequest: type: object properties: title: type: string minLength: 1 maxLength: 200 description: type: string maxLength: 1000 stake: type: string minLength: 1 status: type: string enum: [ACTIVE, AWAITING_VALIDATION, COMPLETED, EXPIRED] endDate: type: string format: date-time winner: type: integer nullable: true # ===== Send Friend Request ===== SendFriendRequestRequest: type: object required: - identifier properties: identifier: oneOf: - type: integer - type: string example: 2 description: User ID, name, or email # ===== Update User Request ===== UpdateUserRequest: type: object properties: name: type: string minLength: 1 maxLength: 100 example: Mario Rossi email: type: string format: email example: mario.rossi@example.com avatarUrl: type: string format: uri nullable: true example: https://example.com/avatar.jpg # ===== Initial Data ===== InitialData: type: object properties: currentUser: $ref: '#/components/schemas/User' users: type: array items: $ref: '#/components/schemas/User' friends: type: array items: $ref: '#/components/schemas/User' friendRequests: type: array items: $ref: '#/components/schemas/FriendRequest' groups: type: array items: $ref: '#/components/schemas/Group' userBets: type: array items: $ref: '#/components/schemas/Bet' publicBets: type: array items: $ref: '#/components/schemas/Bet' # ===== Health Status ===== HealthStatus: type: object properties: status: type: string enum: [healthy, unhealthy] example: healthy timestamp: type: string format: date-time services: type: object properties: postgres: type: string example: connected mongodb: type: string example: connected responses: ValidationError: description: Validation error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: success: false message: Validation failed errors: - field: name message: Name is required timestamp: '2024-01-01T00:00:00.000Z' NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: success: false message: Resource not found timestamp: '2024-01-01T00:00:00.000Z' InternalError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: success: false message: Internal server error timestamp: '2024-01-01T00:00:00.000Z' paths: # ==================== GROUPS ==================== /groups: get: tags: - Groups summary: Lista tutti i gruppi description: Recupera la lista di tutti i gruppi con i loro membri responses: '200': description: Lista gruppi recuperata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/Group' '500': $ref: '#/components/responses/InternalError' post: tags: - Groups summary: Crea un nuovo gruppo description: Crea un nuovo gruppo con i membri specificati requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateGroupRequest' responses: '201': description: Gruppo creato con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Group' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /groups/{id}: get: tags: - Groups summary: Dettaglio gruppo description: Recupera i dettagli di un gruppo specifico con i membri parameters: - name: id in: path required: true schema: type: integer example: 1 responses: '200': description: Gruppo recuperato con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Group' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' put: tags: - Groups summary: Aggiorna gruppo description: Aggiorna le informazioni di un gruppo parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateGroupRequest' responses: '200': description: Gruppo aggiornato con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Group' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' delete: tags: - Groups summary: Elimina gruppo description: Elimina un gruppo esistente parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Gruppo eliminato con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: 'null' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /groups/{id}/members: put: tags: - Groups summary: Aggiungi membri al gruppo description: Aggiunge uno o più membri a un gruppo esistente parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddMembersRequest' responses: '200': description: Membri aggiunti con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Group' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /groups/{id}/members/{userId}: delete: tags: - Groups summary: Rimuovi membro dal gruppo description: Rimuove un membro da un gruppo parameters: - name: id in: path required: true schema: type: integer - name: userId in: path required: true schema: type: integer responses: '200': description: Membro rimosso con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Group' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' # ==================== BETS ==================== /bets: get: tags: - Bets summary: Lista tutte le scommesse description: Recupera la lista di tutte le scommesse con dati utente popolati responses: '200': description: Lista scommesse recuperata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/Bet' '500': $ref: '#/components/responses/InternalError' post: tags: - Bets summary: Crea una nuova scommessa description: Crea una nuova scommessa con partecipanti requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateBetRequest' responses: '201': description: Scommessa creata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Bet' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /bets/{id}: get: tags: - Bets summary: Dettaglio scommessa description: Recupera i dettagli di una scommessa specifica parameters: - name: id in: path required: true schema: type: string example: 507f1f77bcf86cd799439011 responses: '200': description: Scommessa recuperata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Bet' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' put: tags: - Bets summary: Aggiorna scommessa description: Aggiorna i dettagli di una scommessa parameters: - name: id in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateBetRequest' responses: '200': description: Scommessa aggiornata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/Bet' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' delete: tags: - Bets summary: Elimina scommessa description: Elimina una scommessa esistente parameters: - name: id in: path required: true schema: type: string responses: '200': description: Scommessa eliminata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: 'null' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' # ==================== FRIEND REQUESTS ==================== /friend-requests: get: tags: - Friend Requests summary: Lista amici description: Recupera la lista di amici dell'utente corrente responses: '200': description: Lista amici recuperata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/User' '500': $ref: '#/components/responses/InternalError' post: tags: - Friend Requests summary: Invia richiesta di amicizia description: Invia una richiesta di amicizia a un utente requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SendFriendRequestRequest' responses: '201': description: Richiesta inviata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/FriendRequest' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '409': description: Conflict - Already friends or request exists content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': $ref: '#/components/responses/InternalError' /friend-requests/pending: get: tags: - Friend Requests summary: Lista richieste pending description: Recupera le richieste di amicizia pending per l'utente corrente responses: '200': description: Lista richieste recuperata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: array items: $ref: '#/components/schemas/FriendRequest' '500': $ref: '#/components/responses/InternalError' /friend-requests/{id}/accept: post: tags: - Friend Requests summary: Accetta richiesta di amicizia description: Accetta una richiesta di amicizia pending parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Richiesta accettata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: object properties: message: type: string example: Friend request accepted successfully '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' /friend-requests/{id}: delete: tags: - Friend Requests summary: Rifiuta/cancella richiesta description: Rifiuta o cancella una richiesta di amicizia parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Richiesta rifiutata con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: type: object properties: message: type: string example: Friend request rejected successfully '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' # ==================== USERS ==================== /users/current: put: tags: - Users summary: Aggiorna profilo utente description: Aggiorna il profilo dell'utente corrente requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateUserRequest' responses: '200': description: Profilo aggiornato con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/User' '400': $ref: '#/components/responses/ValidationError' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalError' # ==================== INITIAL DATA ==================== /initial-data: get: tags: - Initial Data summary: Carica dati iniziali description: | Carica tutti i dati iniziali necessari per l'applicazione in una singola chiamata. Include: utente corrente, lista utenti, amici, richieste di amicizia, gruppi, scommesse. responses: '200': description: Dati iniziali caricati con successo content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessResponse' - type: object properties: data: $ref: '#/components/schemas/InitialData' '500': $ref: '#/components/responses/InternalError' # Health Check (non versioned) /health: get: tags: - Health summary: Health check description: Verifica lo stato dei database (PostgreSQL e MongoDB) servers: - url: http://localhost:3000 description: Health check endpoint (non versioned) responses: '200': description: Sistema healthy content: application/json: schema: $ref: '#/components/schemas/HealthStatus' '503': description: Sistema unhealthy content: application/json: schema: type: object properties: status: type: string example: unhealthy timestamp: type: string format: date-time error: type: string example: Database connection failed