Files
apocapoc-api/docs/swagger.yaml
T
david aa8f7af55d feat: implement offline sync endpoints with Last-Write-Wins strategy
Add comprehensive offline synchronization support for habits and entries:

## Infrastructure (Phase 1)
- Add UpdatedAt and DeletedAt timestamps to Habit and HabitEntry entities
- Implement soft delete with Delete(), Touch(), and IsDeleted() methods
- Create SQL migration with optimized composite indexes for sync queries
- Add GetChangesSince() and SoftDelete() to both repositories
- Update all Find* methods to exclude soft-deleted records
- 13 comprehensive TDD tests for sync repository methods

## HTTP Endpoints (Phase 2)
- GET /api/v1/sync/changes: retrieve all changes since timestamp
- POST /api/v1/sync/batch: apply client changes with conflict resolution
- Implement Last-Write-Wins strategy using UpdatedAt timestamps
- Add authentication and rate limiting (100 req/min)
- Validate user ownership for all sync operations
- 9 tests for sync handlers (3 queries + 6 commands)

## Technical Details
- Composite indexes: (user_id, updated_at) for optimal query performance
- No pagination: atomic sync operations for data consistency
- Upsert behavior: create resources if not found on server
- DTOs with full entity state including timestamps
- Swagger documentation updated for new endpoints

All 220+ tests passing ✓
2025-12-12 00:11:46 +01:00

1341 lines
34 KiB
YAML

basePath: /api/v1
definitions:
http.AuthResponse:
properties:
refresh_token:
type: string
token:
type: string
user_id:
type: string
type: object
http.CreateHabitRequest:
properties:
carry_over:
type: boolean
description:
type: string
frequency:
$ref: '#/definitions/value_objects.Frequency'
is_negative:
type: boolean
name:
type: string
specific_dates:
items:
type: integer
type: array
specific_days:
items:
type: integer
type: array
target_value:
type: number
type:
$ref: '#/definitions/value_objects.HabitType'
type: object
http.EntryChangesDTO:
properties:
created:
items:
$ref: '#/definitions/http.SyncHabitEntryDTO'
type: array
deleted:
items:
type: string
type: array
updated:
items:
$ref: '#/definitions/http.SyncHabitEntryDTO'
type: array
type: object
http.ErrorResponse:
properties:
error:
type: string
type: object
http.ForgotPasswordRequest:
properties:
email:
type: string
type: object
http.GetUserHabitsResponse:
properties:
data:
items:
$ref: '#/definitions/http.UserHabitResponse'
type: array
pagination:
$ref: '#/definitions/pagination.Response'
type: object
http.HabitChangesDTO:
properties:
created:
items:
$ref: '#/definitions/http.SyncHabitDTO'
type: array
deleted:
items:
type: string
type: array
updated:
items:
$ref: '#/definitions/http.SyncHabitDTO'
type: array
type: object
http.HabitEntriesResponse:
properties:
entries:
items:
$ref: '#/definitions/http.HabitEntryResponse'
type: array
limit:
type: integer
page:
type: integer
total:
type: integer
type: object
http.HabitEntryResponse:
properties:
completed_at:
type: string
habit_id:
type: string
id:
type: string
scheduled_date:
type: string
value:
type: number
type: object
http.HealthResponse:
properties:
database:
type: string
smtp:
type: string
status:
type: string
uptime:
type: string
type: object
http.LoginRequest:
properties:
email:
type: string
password:
type: string
type: object
http.LogoutRequest:
properties:
refresh_token:
type: string
type: object
http.MarkHabitRequest:
properties:
scheduled_date:
type: string
value:
type: number
type: object
http.RefreshRequest:
properties:
refresh_token:
type: string
type: object
http.RegisterRequest:
properties:
email:
type: string
password:
type: string
type: object
http.RegisterResponse:
properties:
message:
type: string
user_id:
type: string
type: object
http.ResendVerificationRequest:
properties:
email:
type: string
type: object
http.ResetPasswordRequest:
properties:
new_password:
type: string
token:
type: string
type: object
http.SyncBatchRequest:
properties:
entries:
$ref: '#/definitions/http.EntryChangesDTO'
habits:
$ref: '#/definitions/http.HabitChangesDTO'
type: object
http.SyncChangesResponse:
properties:
entries:
$ref: '#/definitions/http.EntryChangesDTO'
habits:
$ref: '#/definitions/http.HabitChangesDTO'
type: object
http.SyncHabitDTO:
properties:
archived_at:
type: string
carry_over:
type: boolean
created_at:
type: string
description:
type: string
frequency:
$ref: '#/definitions/value_objects.Frequency'
id:
type: string
is_negative:
type: boolean
name:
type: string
specific_dates:
items:
type: integer
type: array
specific_days:
items:
type: integer
type: array
target_value:
type: number
type:
$ref: '#/definitions/value_objects.HabitType'
updated_at:
type: string
user_id:
type: string
type: object
http.SyncHabitEntryDTO:
properties:
completed_at:
type: string
habit_id:
type: string
id:
type: string
scheduled_date:
type: string
updated_at:
type: string
value:
type: number
type: object
http.TodaysHabitEntryResponse:
properties:
completed_at:
type: string
id:
type: string
value:
type: number
type: object
http.TodaysHabitResponse:
properties:
entry:
$ref: '#/definitions/http.TodaysHabitEntryResponse'
id:
type: string
is_carried_over:
type: boolean
is_negative:
type: boolean
name:
type: string
scheduled_date:
type: string
target_value:
type: number
type:
$ref: '#/definitions/value_objects.HabitType'
type: object
http.UpdateHabitRequest:
properties:
carry_over:
type: boolean
description:
type: string
name:
type: string
specific_dates:
items:
type: integer
type: array
specific_days:
items:
type: integer
type: array
target_value:
type: number
type: object
http.UserHabitResponse:
properties:
carry_over:
type: boolean
frequency:
$ref: '#/definitions/value_objects.Frequency'
id:
type: string
is_negative:
type: boolean
name:
type: string
specific_days:
items:
type: integer
type: array
target_value:
type: number
type:
$ref: '#/definitions/value_objects.HabitType'
type: object
http.ValidationErrorResponse:
properties:
error:
type: string
field:
type: string
type: object
http.VerifyEmailRequest:
properties:
token:
type: string
type: object
pagination.Response:
properties:
page:
type: integer
page_size:
type: integer
total_items:
type: integer
total_pages:
type: integer
type: object
queries.ExportEntryDTO:
properties:
completed_at:
type: string
habit_id:
type: string
id:
type: string
scheduled_date:
type: string
value:
type: number
type: object
queries.ExportHabitDTO:
properties:
archived_at:
type: string
carry_over:
type: boolean
created_at:
type: string
description:
type: string
frequency:
$ref: '#/definitions/value_objects.Frequency'
id:
type: string
is_negative:
type: boolean
name:
type: string
specific_dates:
items:
type: integer
type: array
specific_days:
items:
type: integer
type: array
target_value:
type: number
type:
$ref: '#/definitions/value_objects.HabitType'
type: object
queries.ExportUserDataResult:
properties:
entries:
items:
$ref: '#/definitions/queries.ExportEntryDTO'
type: array
exported_at:
type: string
habits:
items:
$ref: '#/definitions/queries.ExportHabitDTO'
type: array
type: object
queries.HabitStatsDTO:
properties:
completion_rate:
type: number
completions_this_month:
type: integer
completions_this_week:
type: integer
current_streak:
type: integer
habit_id:
type: string
habit_name:
type: string
longest_streak:
type: integer
total_completions:
type: integer
type: object
value_objects.Frequency:
enum:
- DAILY
- WEEKLY
- MONTHLY
type: string
x-enum-varnames:
- FrequencyDaily
- FrequencyWeekly
- FrequencyMonthly
value_objects.HabitType:
enum:
- BOOLEAN
- COUNTER
- VALUE
type: string
x-enum-varnames:
- HabitTypeBoolean
- HabitTypeCounter
- HabitTypeValue
info:
contact:
email: contact@apocapoc.app
name: API Support
url: https://github.com/davidfolch/apocapoc-api
description: Self-hosted habit tracking service
license:
name: MIT
url: https://opensource.org/licenses/MIT
termsOfService: http://swagger.io/terms/
title: Apocapoc API
paths:
/auth/forgot-password:
post:
consumes:
- application/json
description: Request a password reset email with a reset token
parameters:
- description: User email
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.ForgotPasswordRequest'
produces:
- application/json
responses:
"200":
description: Reset email sent successfully
schema:
additionalProperties:
type: string
type: object
"400":
description: Invalid email
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Email not verified
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: User not found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Request password reset
tags:
- auth
/auth/login:
post:
consumes:
- application/json
description: Authenticate user with email and password. Returns both access
token and refresh token. The access token is used for API requests, the refresh
token is used to obtain new access tokens when they expire.
parameters:
- description: Login credentials
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.LoginRequest'
produces:
- application/json
responses:
"200":
description: Returns access token, refresh token, and user ID
schema:
$ref: '#/definitions/http.AuthResponse'
"400":
description: Invalid request body
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Invalid email or password
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Email not verified
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Login user
tags:
- auth
/auth/logout:
post:
consumes:
- application/json
description: Revoke the refresh token to invalidate the user session. After
logout, the refresh token cannot be used to obtain new access tokens. The
user will need to login again. Always call this endpoint before clearing tokens
from client storage to ensure proper session termination.
parameters:
- description: Refresh token to revoke
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.LogoutRequest'
produces:
- application/json
responses:
"200":
description: Successfully logged out - the refresh token is now invalid
schema:
additionalProperties:
type: string
type: object
"400":
description: Invalid request body or missing refresh token
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Refresh token not found (already revoked or never existed)
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Logout user
tags:
- auth
/auth/refresh:
post:
consumes:
- application/json
description: 'Exchange a valid refresh token for a new access token and refresh
token pair. IMPORTANT: The old refresh token is automatically revoked and
you receive a NEW refresh token - always update both tokens in storage. Use
this endpoint when the access token expires to maintain the user session without
requiring re-login.'
parameters:
- description: Current refresh token
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.RefreshRequest'
produces:
- application/json
responses:
"200":
description: Returns NEW access token and NEW refresh token - the old refresh
token is now invalid
schema:
$ref: '#/definitions/http.AuthResponse'
"400":
description: Invalid request body
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Invalid or expired refresh token
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Refresh access token
tags:
- auth
/auth/register:
post:
consumes:
- application/json
description: Create a new user account. If email verification is enabled, you
will receive a verification email. Otherwise, you can login immediately.
parameters:
- description: 'Registration data (password requires: min 8 chars, uppercase,
lowercase, digit, special char)'
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.RegisterRequest'
produces:
- application/json
responses:
"201":
description: Returns user ID and message about next steps
schema:
$ref: '#/definitions/http.RegisterResponse'
"400":
description: 'Invalid input: email format or password requirements'
schema:
$ref: '#/definitions/http.ValidationErrorResponse'
"403":
description: Registration is closed
schema:
$ref: '#/definitions/http.ErrorResponse'
"409":
description: Email already registered
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Register a new user
tags:
- auth
/auth/resend-verification:
post:
consumes:
- application/json
description: Resend the email verification link to the user's email address
parameters:
- description: User email
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.ResendVerificationRequest'
produces:
- application/json
responses:
"200":
description: Verification email sent
schema:
additionalProperties:
type: string
type: object
"400":
description: Invalid email
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: User not found
schema:
$ref: '#/definitions/http.ErrorResponse'
"409":
description: Email already verified
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Resend verification email
tags:
- auth
/auth/reset-password:
post:
consumes:
- application/json
description: Reset user password using the reset token from email
parameters:
- description: Reset token and new password
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.ResetPasswordRequest'
produces:
- application/json
responses:
"200":
description: Password reset successfully
schema:
additionalProperties:
type: string
type: object
"400":
description: Invalid token or password requirements not met
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: User not found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Reset password
tags:
- auth
/auth/verify-email:
post:
consumes:
- application/json
description: Verify user email address using the token sent via email
parameters:
- description: Verification token
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.VerifyEmailRequest'
produces:
- application/json
responses:
"200":
description: Email verified successfully
schema:
additionalProperties:
type: string
type: object
"400":
description: Invalid or expired token
schema:
$ref: '#/definitions/http.ErrorResponse'
"409":
description: Email already verified
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
summary: Verify email address
tags:
- auth
/export:
get:
description: Export all user habits and entries in JSON format with gzip compression.
Limited to 1 export per hour.
produces:
- application/json
responses:
"200":
description: Compressed JSON export
schema:
$ref: '#/definitions/queries.ExportUserDataResult'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"429":
description: Rate limit exceeded
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Export user data
tags:
- export
/habits:
get:
description: Get all active habits for the authenticated user with optional
pagination and filters
parameters:
- description: 'Page number (default: 1)'
in: query
name: page
type: integer
- description: 'Page size (default: 50, max: 100)'
in: query
name: page_size
type: integer
- description: Filter by type (BOOLEAN, COUNTER, VALUE)
in: query
name: type
type: string
- description: Filter by frequency (DAILY, WEEKLY, MONTHLY)
in: query
name: frequency
type: string
- description: 'Include archived habits (default: false)'
in: query
name: archived
type: boolean
- description: Search by name or description
in: query
name: search
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/http.GetUserHabitsResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Get all user habits
tags:
- habits
post:
consumes:
- application/json
description: Create a new habit for the authenticated user
parameters:
- description: Habit data
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.CreateHabitRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
additionalProperties:
type: string
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Create a new habit
tags:
- habits
/habits/{id}:
delete:
description: Archive (soft delete) a habit
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
type: string
type: object
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Archive habit
tags:
- habits
get:
description: Get a specific habit by ID
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/http.UserHabitResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Get habit by ID
tags:
- habits
put:
consumes:
- application/json
description: Update an existing habit
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
- description: Update data
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.UpdateHabitRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
type: string
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Update habit
tags:
- habits
/habits/{id}/entries:
get:
description: Get entries (completion history) for a habit with optional date
filtering and pagination
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
- description: Start date (YYYY-MM-DD)
in: query
name: from
type: string
- description: End date (YYYY-MM-DD)
in: query
name: to
type: string
- description: Page number
in: query
name: page
type: integer
- description: Page size (max 100)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/http.HabitEntriesResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Get habit entries
tags:
- habits
/habits/{id}/entries/{date}:
delete:
description: Delete a habit entry (unmark completion)
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
- description: Date (YYYY-MM-DD)
in: path
name: date
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
type: string
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Unmark habit
tags:
- habits
/habits/{id}/mark:
post:
consumes:
- application/json
description: Mark a habit as completed for a specific date
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
- description: Mark data
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.MarkHabitRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
type: string
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"409":
description: Conflict
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Mark habit as complete
tags:
- habits
/habits/today:
get:
description: Get all habits scheduled for today for the authenticated user.
Includes the entry for today if it exists. Requires timezone as query parameter
(e.g., ?timezone=America/New_York).
parameters:
- description: IANA timezone (e.g., 'America/New_York', 'Europe/Madrid', 'UTC')
in: query
name: timezone
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/http.TodaysHabitResponse'
type: array
"400":
description: Invalid or missing timezone
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Get today's habits
tags:
- habits
/health:
get:
description: Get API health status including database connectivity and uptime
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/http.HealthResponse'
"503":
description: Service Unavailable
schema:
$ref: '#/definitions/http.HealthResponse'
summary: Health check
tags:
- system
/stats/habits/{id}:
get:
description: Get statistics for a specific habit including streaks and completion
rates
parameters:
- description: Habit ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/queries.HabitStatsDTO'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Get habit statistics
tags:
- stats
/sync/batch:
post:
consumes:
- application/json
description: Apply a batch of changes from the client for offline sync (Last-Write-Wins)
parameters:
- description: Sync batch data
in: body
name: request
required: true
schema:
$ref: '#/definitions/http.SyncBatchRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
type: string
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Apply sync batch
tags:
- sync
/sync/changes:
get:
consumes:
- application/json
description: Get all changes (habits and entries) since a given timestamp for
offline sync
parameters:
- description: ISO 8601 timestamp (e.g., 2025-01-01T00:00:00Z)
in: query
name: since
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/http.SyncChangesResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/http.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Get sync changes
tags:
- sync
/users/me:
delete:
description: Permanently delete the authenticated user's account and all associated
data (habits, entries, tokens). This action cannot be undone.
produces:
- application/json
responses:
"200":
description: Account deleted successfully
schema:
additionalProperties:
type: string
type: object
"401":
description: Unauthorized - invalid or missing token
schema:
$ref: '#/definitions/http.ErrorResponse'
"404":
description: User not found
schema:
$ref: '#/definitions/http.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/http.ErrorResponse'
security:
- BearerAuth: []
summary: Delete user account
tags:
- users
securityDefinitions:
BearerAuth:
description: Type "Bearer" followed by a space and JWT token.
in: header
name: Authorization
type: apiKey
swagger: "2.0"