openapi: 3.0.3
info:
  title: WalkGuide API
  version: 1.0.0
  description: Design contract for WalkGuide Flutter and Spring Boot integration.
servers:
  - url: http://localhost:8080/api/v1
security:
  - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    ApiResponse:
      type: object
      properties:
        success: { type: boolean }
        data: { nullable: true }
        message: { type: string }
        timestamp: { type: string, format: date-time }
    LoginRequest:
      type: object
      required: [email, password]
      properties:
        email: { type: string, format: email }
        password: { type: string }
    RegisterRequest:
      type: object
      required: [email, password, displayName, role]
      properties:
        email: { type: string, format: email }
        password: { type: string, minLength: 6 }
        displayName: { type: string }
        role: { type: string, enum: [USER, GUARDIAN] }
    PairingInviteRequest:
      type: object
      required: [uniqueUserId]
      properties:
        uniqueUserId: { type: string, minLength: 12, maxLength: 12 }
    PairingRespondRequest:
      type: object
      required: [pairingId, accept]
      properties:
        pairingId: { type: integer, format: int64 }
        accept: { type: boolean }
    LocationUpdateRequest:
      type: object
      properties:
        lat: { type: number, format: double }
        lng: { type: number, format: double }
        accuracy: { type: number, format: double }
        speed: { type: number, format: double }
        heading: { type: number, format: double }
    CallTokenRequest:
      type: object
      required: [receiverId]
      properties:
        receiverId: { type: integer, format: int64 }
paths:
  /auth/ping:
    get:
      security: []
      responses:
        "200": { description: Server health, content: { application/json: { schema: { $ref: "#/components/schemas/ApiResponse" } } } }
  /auth/register:
    post:
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/RegisterRequest" }
      responses:
        "200": { description: Registered }
  /auth/login:
    post:
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LoginRequest" }
      responses:
        "200": { description: Logged in }
  /auth/refresh:
    post:
      security: []
      responses:
        "200": { description: Token refreshed }
  /auth/logout:
    post:
      responses:
        "200": { description: Logged out }
  /auth/fcm-token:
    put:
      responses:
        "200": { description: FCM token updated }
  /shared/pairing/invite:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/PairingInviteRequest" }
      responses:
        "200": { description: Invite sent }
  /shared/pairing/respond:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/PairingRespondRequest" }
      responses:
        "200": { description: Invite responded }
  /shared/pairing/unpair:
    delete:
      responses:
        "200": { description: Pairing removed }
  /shared/pairing/status:
    get:
      responses:
        "200": { description: Pairing status }
  /shared/call/token:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CallTokenRequest" }
      responses:
        "200": { description: Agora token generated }
  /shared/call/notify:
    post:
      responses:
        "200": { description: Incoming call notification sent }
  /shared/call/end:
    post:
      responses:
        "200": { description: Call end notification sent }
  /user/profile:
    get:
      responses:
        "200": { description: Current user profile }
  /user/settings:
    get:
      responses:
        "200": { description: User settings }
    put:
      responses:
        "200": { description: User settings updated }
  /user/voice-commands:
    get:
      responses:
        "200": { description: Voice commands }
  /user/shortcuts:
    get:
      responses:
        "200": { description: Hardware shortcuts }
    put:
      responses:
        "200": { description: Hardware shortcut updated }
  /user/ai-config:
    get:
      responses:
        "200": { description: AI config }
  /user/location:
    post:
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LocationUpdateRequest" }
      responses:
        "200": { description: Location stored }
  /user/obstacle:
    post:
      responses:
        "200": { description: Obstacle stored }
  /user/sos:
    post:
      responses:
        "200": { description: SOS triggered }
  /user/sos-events:
    get:
      responses:
        "200": { description: User SOS history }
  /user/activity-logs:
    get:
      responses:
        "200": { description: User activity logs }
  /user/notifications:
    get:
      responses:
        "200": { description: User notifications }
  /user/notifications/unread-count:
    get:
      responses:
        "200": { description: Unread notification count }
  /user/notifications/mark-all-read:
    put:
      responses:
        "200": { description: All notifications marked read }
  /user/notifications/{id}/read:
    put:
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer, format: int64 }
      responses:
        "200": { description: One notification marked read }
  /user/walkguide/start:
    post:
      responses:
        "200": { description: WalkGuide start logged }
  /user/walkguide/stop:
    post:
      responses:
        "200": { description: WalkGuide stop logged }
  /guardian/dashboard:
    get:
      responses:
        "200": { description: Guardian dashboard }
  /guardian/user-location:
    get:
      responses:
        "200": { description: Paired user latest location }
  /guardian/location-history:
    get:
      responses:
        "200": { description: Paired user location history }
  /guardian/activity-logs:
    get:
      responses:
        "200": { description: Paired user activity logs }
  /guardian/obstacle-logs:
    get:
      responses:
        "200": { description: Paired user obstacle logs }
  /guardian/notifications/send:
    post:
      responses:
        "200": { description: Notification sent to paired user }
  /guardian/sos-events:
    get:
      responses:
        "200": { description: Paired user SOS events }
  /guardian/sos/{id}/acknowledge:
    put:
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer, format: int64 }
      responses:
        "200": { description: SOS acknowledged }
  /guardian/ai-config:
    get:
      responses:
        "200": { description: Paired user AI config }
    put:
      responses:
        "200": { description: Paired user AI config updated }
  /guardian/voice-commands:
    get:
      responses:
        "200": { description: Paired user voice commands }
    put:
      responses:
        "200": { description: Paired user voice command updated }
  /guardian/shortcuts:
    get:
      responses:
        "200": { description: Paired user shortcuts }
  /guardian/geofence:
    get:
      responses:
        "200": { description: Geofence config }
    put:
      responses:
        "200": { description: Geofence config updated }
  /guardian/user-settings:
    get:
      responses:
        "200": { description: Paired user settings }
    put:
      responses:
        "200": { description: Paired user settings updated }
