Commit Graph

65 Commits

Author SHA1 Message Date
david 67fc508384 Fix import order v1.7.2 2026-03-27 00:04:15 +01:00
david 92fe617f73 Fix typed nil panic when SMTP is not configured v1.7.1 2026-03-27 00:00:02 +01:00
david 94c5c30d09 feat: allow editing frequency and target_value on habits
- Add frequency to UpdateHabitRequest (was immutable, now editable)
- Validate frequency + specific_days/dates coherence on update
- Keep type and is_negative immutable (they change entry semantics)
- Remove completion_rate references from swagger and README
v1.7.0
2026-03-08 00:14:25 +01:00
david 2b059ec334 refactor: extract streak calculation to domain service
Move streak logic from application query to a dedicated domain service,
making it reusable and properly tested for all habit configurations.

- Support streaks for all habit types (boolean, counter, value) combined
  with positive/negative and optional target values
- Handle weekly habits with specific days (streak counts scheduled days)
- Today completed counts toward streak; not yet completed doesn't break it
- Calculate current and longest streak in a single forward pass
- Remove completion_rate from stats (not a useful metric for habits)
- Add comprehensive unit tests covering all 10 type combinations
v1.6.0
2026-03-07 22:49:31 +01:00
david 77cfb709d8 feat: add graceful shutdown on SIGINT/SIGTERM v1.5.0 2026-03-07 14:33:30 +01:00
david aae68ba20e fix: format code with gofmt v1.4.0 2026-03-07 04:36:52 +01:00
david 8883cdcb86 chore: add /api to gitignore 2026-03-07 03:50:47 +01:00
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
david 1aedc2b69a Add integration tests for auth refresh flow, rate limiting, and statistics
- Add refresh token flow tests including token rotation and invalidation
- Add rate limiting integration tests
- Add statistics endpoint integration tests
v1.3.0
2025-12-05 01:24:22 +01:00
david e9e7e9dbac Add automated backup system with SQLite VACUUM
- Implement backup package with SQLite VACUUM INTO for safe backups
- Add scheduler with configurable interval (default: 24h)
- Add retention policy with automatic cleanup (default: 7 days)
- Add optional gzip compression (~10x size reduction)
- Add comprehensive tests for backup creation and cleanup
- Integrate backup scheduler in main.go with graceful shutdown
- Add backup configuration variables (BACKUP_ENABLED, BACKUP_INTERVAL, BACKUP_RETENTION_DAYS, BACKUP_PATH, BACKUP_COMPRESS)
- Backups run automatically in background goroutine
- Coverage: backup package 52.7%
2025-12-05 00:17:37 +01:00
david 88b5d11113 Fix code formatting with gofmt v1.2.0 2025-12-04 23:26:51 +01:00
david 29f0f9b468 Add structured logging with zerolog
- Implement zerolog logger package with configurable levels
- Add contextual logging middleware (request_id, user_id, method, path, status, duration)
- Support both JSON (production) and human-readable (development) formats
- Add LOG_LEVEL and ENVIRONMENT configuration variables
- Replace standard log calls with structured logger throughout application
- Integrate logger in HTTP router and auth middleware
2025-12-04 23:22:05 +01:00
david 7575853355 Add rate limiting for password reset and improve SMTP tests
- Add RateLimitByEmail middleware (3 attempts/hour per email)
- Apply rate limiting to /api/v1/auth/forgot-password endpoint
- Expand SMTP tests with config validation, message types, and error detection
- Improve test coverage from 44.6% to 53.3%
2025-12-04 22:54:24 +01:00
david 788b6cf430 Add data export functionality with gzip compression
- Add FindByUserID method to HabitEntryRepository (JOIN with habits)
- Implement ExportUserDataHandler to export all user data
- Add GET /api/v1/export endpoint with gzip compression
- Apply strict rate limiting (1 export per hour per user)
- Export includes all habits (active + archived) and entries
- Add i18n translations for export errors (en/es)
- Update all test mocks to implement new repository method
- Export format: JSON with gzip (~10x compression ratio)
2025-12-03 22:32:22 +01:00
david 568ba3b016 Add email logging and SMTP health check
- Add structured logging for email sending (success/failure)
- Add HealthCheck method to EmailService interface
- Extend /health endpoint to include SMTP status
- Update all email service mocks to implement HealthCheck
- SMTP status shows: ok, error, or disabled
2025-12-03 20:41:40 +01:00
david 935f742ac9 Add filtering support to GET /api/v1/habits endpoint
Implemented comprehensive filtering capabilities for the habits list endpoint:
- Filter by type (BOOLEAN, COUNTER, VALUE)
- Filter by frequency (DAILY, WEEKLY, MONTHLY)
- Filter by archived status
- Text search in habit name and description
- All filters can be combined
- Filters work with pagination

Technical changes:
- Added FilterParams to GetUserHabitsQuery
- Created HabitFilter struct in repository interface
- Implemented dynamic SQL query building in SQLite repository
- Updated HTTP handler to parse filter query parameters
- Added comprehensive tests for repository and handler filtering
- Updated all test mocks with new filter methods
2025-12-02 01:02:39 +01:00
david 38e640c617 Add pagination support to GET /api/v1/habits endpoint
- Create pagination package with Params and Response structs
- Add FindActiveByUserIDWithPagination and CountActiveByUserID methods to HabitRepository interface
- Implement pagination in SQLite repository using LIMIT and OFFSET
- Update GetUserHabitsHandler to support optional pagination parameters
- Modify HTTP endpoint to parse 'page' and 'page_size' query params (default: page=1, page_size=50, max=100)
- Add GetUserHabitsResponse DTO with pagination metadata
- Maintain backward compatibility - endpoint works with and without pagination params
- Add comprehensive tests for pagination logic in repository, handler, and pagination package
- Update all mock repositories to implement new pagination methods
2025-12-01 23:53:00 +01:00
david f780c69806 Add tests for RequestPasswordResetHandler and fix test compilation errors
- Add comprehensive tests for RequestPasswordResetHandler covering success and error cases
- Fix timezone-related test failures after removal of User.Timezone field:
  - Remove Timezone assertions from login_user_test.go
  - Remove Timezone field from RegisterRequest in integration tests
  - Update ValidateRegistration test cases (no longer validates timezone)
  - Update migrations_test to check current user table schema
- Fix syntax errors in user_repository_test.go (duplicate closing braces on lines 114 and 210)
2025-12-01 23:04:40 +01:00
david 5d92820591 Remove timezone from User model and pass as request parameter
Timezone is now sent from the client on each request that needs it,
instead of storing it in the database. This simplifies the model and
allows timezone to be dynamic (useful for traveling users).

Changes:
- Remove timezone field from User entity
- Remove timezone from user registration
- GET /habits/today now requires ?timezone= query param
- Add migration to drop timezone column from database
- Update related tests
2025-11-29 16:18:04 +01:00
david a2aa8b2a76 Add i18n support with English and Spanish translations
- Created i18n package with translator and middleware
- Added translation files for English (en.json) and Spanish (es.json)
- Updated all HTTP handlers to use i18n for error/success messages
- Added comprehensive test coverage for i18n (87%)
- Updated CI workflow to use Go 1.24
- All tests passing with 50.8% total coverage
v1.1.0
2025-11-29 12:27:26 +01:00
david 90d5628a42 Fix today's habits timezone calculation and include entry data
- Calculate today based on user's timezone instead of always using UTC
- Include habit entry in response if it exists for the current day
- Update GetTodaysHabitsHandler to fetch and return entry information
- Add entry field to TodaysHabitDTO and TodaysHabitResponse
- Update tests to reflect new behavior of including completed habits
- Add test for habits with value entries
2025-11-29 02:09:30 +01:00
david 9a0637aa4c Remove broken Docker badge 2025-11-28 19:01:25 +01:00
david d3111ad52c Revise README content 2025-11-28 18:56:35 +01:00
david 6fb4823183 Fix error response documentation for field attribute
Separated ErrorResponse and ValidationErrorResponse types:
- ErrorResponse: general errors (401, 403, 404, 500) - no field attribute
- ValidationErrorResponse: form validation errors (400) - includes field attribute

Updated respondValidationError to return appropriate type based on error format.
Updated Swagger documentation to use ValidationErrorResponse only for validation endpoints.

This ensures the field attribute only appears in API responses for actual form field validation errors, not in general error responses.
2025-11-28 18:05:25 +01:00
david 8d631f8fab Improve README SEO and increase test coverage to 50%
Optimized README for better discoverability with keywords: api, habits, self-hosted. Consolidated content to reduce redundancy while maintaining clarity.

Added comprehensive test coverage across multiple layers:
- Infrastructure: bcrypt hashing, JWT tokens, configuration validation
- Application commands: user deletion, password reset, token revocation, email verification
- Application queries: login, token refresh
- Domain entities: refresh tokens, password reset tokens

Coverage increased from 42.5% to 50.8% with meaningful business logic tests.

Fixed integration test handler initialization with correct parameters.
2025-11-28 17:59:39 +01:00
david 06f95afc92 Update README with email verification and new configuration
- Add email verification and welcome email features to feature list
- Update docker-compose example with all environment variables
- Document all configuration options with proper categorization
- Add note about SMTP password escaping with $$
- Remove deprecated CORS_ORIGINS variable
- Add note about auto-verification when SMTP is not configured
2025-11-28 11:57:07 +01:00
david f37c1ac19b Improve email verification flow and error handling
- Send verification email before creating user to prevent orphaned accounts
- Detect SMTP authentication errors and fail fast without retries
- Add field-level validation errors for better frontend UX
- Configure docker-compose with explicit environment variables
- Document dollar sign escaping in .env.example (use $$)
- Implement welcome email on successful verification
- Clean up unnecessary comments
2025-11-28 11:32:51 +01:00
david 00f6b51228 Add optional email verification and registration control
Implemented email service infrastructure with SMTP support and optional email verification for self-hosted deployments. Registration flow now supports open/closed modes and hardcoded Apocapoc branding.

Key features:
- Email service with SMTP and template rendering
- Optional email verification (auto-verified without SMTP config)
- Registration modes: open/closed for access control
- Hardcoded Apocapoc branding (AppName, AppURL, DefaultFrom)
- Separate registration and login flows (registration no longer returns tokens)
2025-11-28 08:21:51 +01:00
david a95a703905 Remove coverage files from repository and add to gitignore 2025-11-28 01:42:26 +01:00
david 4290ee3455 Switch to pure-Go SQLite driver for cross-compilation
- Replace mattn/go-sqlite3 with modernc.org/sqlite (pure-Go, no CGO required)
- Update GoReleaser config to disable CGO for ARM64 builds
- Change driver name from 'sqlite3' to 'sqlite' in all sql.Open calls
- Enables successful cross-compilation for ARM64 without cross-compiler toolchain
- All tests passing with new driver
v1.0.0
2025-11-28 01:36:18 +01:00
david 0e909182c2 Add contact email to documentation
- Add Support section to README with contact email and issues link
- Add contact email to Swagger API documentation
- Regenerate Swagger docs
2025-11-28 01:26:33 +01:00
david 540a95cbec Fix GoReleaser version to v2 for config compatibility 2025-11-28 00:21:07 +01:00
david dda99a63b1 Add automated releases with binaries and simplify CI workflow
- Add GoReleaser configuration for Linux binaries (amd64, arm64)
- Add release job to GitHub Actions for tagged versions
- Remove github.server_url validations (Gitea CI disabled)
- Update README with binary download instructions
- Releases will include compiled binaries and changelogs
2025-11-28 00:14:10 +01:00
david ac521c38a8 Improve Docker image tagging strategy and remove Swagger version
- Replace 'stable' tag with semver-based tags (1.2.3, 1.2, 1)
- Use 'edge' tag for main branch instead of 'latest'
- Reserve 'latest' tag only for tagged releases
- Remove version from Swagger docs (tracked via git tags instead)
- Document available image tags in README
2025-11-27 23:59:27 +01:00
david 1b69bec12f Fix integration tests to comply with password requirements
CI/CD Pipeline / Test (push) Has been cancelled
CI/CD Pipeline / Lint (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Image (push) Has been cancelled
Update test passwords from 'password123' to 'Password123!' to meet security requirements (uppercase, lowercase, digit, special char).

Fix migrations test to match actual habit_entries schema (removed non-existent deleted_at column).
2025-11-27 23:38:36 +01:00
david cb467c688a Configure CI workflow to run only on GitHub and improve Docker tagging strategy
CI/CD Pipeline / Test (push) Has been cancelled
CI/CD Pipeline / Lint (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Image (push) Has been cancelled
- Add github.server_url check to prevent workflow execution on Gitea
- Implement clear separation between development (latest) and production (stable) tags
- Use stable tag only for versioned releases (v*)
- Add sha- prefix to commit-based tags for better clarity
- Remove redundant branch name tags
2025-11-27 22:49:25 +01:00
david 7cb2756b67 Implement Sprint 2 security enhancements
CI/CD Pipeline / Test (push) Has been cancelled
CI/CD Pipeline / Lint (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Image (push) Has been cancelled
Add user-based rate limiting middleware (100 req/min) for authenticated endpoints using httprate library. Implement common password validation blocking 50+ weak passwords. Improve test coverage from 38.3% to 44.6% with comprehensive refresh token tests.

Security improvements:
- Rate limiting by user ID for /habits and /stats endpoints
- X-RateLimit-Limit header in responses
- Common password blacklist in password validation
- Refresh token test suite with 5 scenarios (valid, invalid, expired, revoked, empty)
2025-11-27 10:33:01 +01:00
david bbe0757ab6 Add refresh token authentication system
CI/CD Pipeline / Test (push) Has been cancelled
CI/CD Pipeline / Lint (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Image (push) Has been cancelled
Implement complete refresh token flow for improved security:
- Short-lived access tokens (configurable, default 1h)
- Long-lived refresh tokens (configurable, default 7d)
- Automatic token rotation on refresh
- Token revocation for proper logout

Domain layer:
- Add RefreshToken entity with validation and revocation
- Add RefreshTokenRepository interface

Application layer:
- Add RefreshTokenHandler for token refresh operations
- Add RevokeTokenHandler for single token revocation
- Add RevokeAllTokensHandler for user-wide revocation

Infrastructure layer:
- Implement SQLite RefreshTokenRepository
- Add refresh_tokens table migration with indexes
- Add parseDuration helper for flexible time configuration

HTTP layer:
- Add POST /api/v1/auth/refresh endpoint
- Add POST /api/v1/auth/logout endpoint
- Update login/register to return refresh tokens
- Improve Swagger documentation with clear descriptions

Configuration:
- Update .env.example with secure token expiry defaults
- Add support for minute/hour/day duration formats

Tests:
- Fix test suite to work with new signatures
- All existing tests passing
2025-11-27 09:57:54 +01:00
david 10d45fc34e Add COUNTER type with auto-increment and IsNegative field
COUNTER type:
- Only accepts integer values (rejects decimals)
- Auto-increment behavior: each mark adds to existing value
- Supports decrement via negative values (e.g., -2)
- Enforces minimum value of 0 (never negative)
- Default increment is 1 if no value provided

VALUE type:
- Accepts decimal values
- Replaces value (no auto-increment)

IsNegative field:
- New boolean field on Habit entity
- Persisted in database (is_negative column)
- Available in all DTOs and HTTP responses
- Marks habits as "negative" (e.g., candy consumption)

Examples:
- COUNTER: 5 + (-2) = 3, 2 + (-3) = 0, 0 + (-1) = 0
- VALUE: 5000 → 12000 = 12000 (replacement)
2025-11-27 08:58:39 +01:00
david 358f844073 Remove unnecessary comments from codebase
Clean up obvious and redundant comments that don't add value:
- Remove step-by-step comments in command handlers
- Remove obvious test setup comments
- Keep only meaningful comments that explain why, not what
2025-11-27 00:48:50 +01:00
david ca2533d4df Improve type safety with proper value objects for HabitType and Frequency
Replace generic string types with strongly-typed value objects throughout
the application layer. This change ensures compile-time type checking and
automatic validation during JSON deserialization.

Changes:
- Add JSON marshaling/unmarshaling to HabitType and Frequency value objects
- Update all DTOs to use typed fields instead of strings
- Update commands and queries to use proper types
- Remove unnecessary string conversions
- Add comprehensive JSON serialization tests
- Fix existing tests to work with typed fields

Benefits:
- Type safety: compiler catches invalid usage
- Automatic validation: invalid values rejected during JSON parsing
- Better code documentation and self-explanatory APIs
- Reduced runtime errors
2025-11-27 00:39:45 +01:00
david 7768037724 Add robust input validation system and fix test suite
- Add comprehensive validation package with email (RFC 5322), password strength, and IANA timezone validation
- Implement strict password requirements: min 8 chars, uppercase, lowercase, digit, special character
- Integrate validation into RegisterUserHandler with complete test coverage (59 validation tests + 25 handler tests)
- Fix pre-existing test failures:
  - Remove tests for non-existent HabitEntry.DeletedAt and Delete() methods
  - Replace deprecated HabitTypeQuantity with HabitTypeValue
  - Add missing FindByHabitIDAndDateRange mock implementation
- Remove hardcoded localhost:8080 from Swagger config for self-hosted flexibility
2025-11-27 00:17:18 +01:00
david 95088a8162 Add explicit container name to docker-compose example
CI/CD Pipeline / Test (push) Has been cancelled
CI/CD Pipeline / Lint (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Image (push) Has been cancelled
Sets container_name to 'apocapoc-api-dev' for easier container identification and management during development.
2025-11-26 22:06:20 +01:00
david 4c8f3022f0 Refactor password hashing to follow DIP and improve CI/CD
CI/CD Pipeline / Test (push) Has been cancelled
CI/CD Pipeline / Lint (push) Has been cancelled
CI/CD Pipeline / Build and Push Docker Image (push) Has been cancelled
- Create PasswordHasher interface in domain layer
- Implement BcryptHasher in infrastructure layer
- Update RegisterUserHandler and LoginUserHandler to use interface
- Remove bcrypt dependency from application layer
- Update main.go and integration tests with dependency injection
- Enhance CI/CD workflow with test and lint jobs
- Add code coverage check (minimum 50%)
- Add go vet and gofmt validation
- Configure build job to depend on test and lint passing
- Update GitHub Actions to latest versions (v4→v5)

This achieves 100% SOLID compliance (DIP) and ensures Clean Architecture
by removing external library dependencies from application/domain layers.
2025-11-26 21:39:52 +01:00
david daa7154b12 Add enhanced health check endpoint
- Implement comprehensive health check with database ping
- Track and report server uptime
- Return proper HTTP status codes (503 if database is down)
- Add Swagger documentation for health endpoint
2025-11-26 20:40:03 +01:00
david 353a6c1f4b Add rate limiting for security
- Add httprate dependency for rate limiting
- Apply 10 requests per minute limit on auth endpoints
- Prevent brute force attacks on login/register
- Update README with security features
2025-11-26 20:37:52 +01:00
david b859c3da0c Remove docker-compose.dev.yml duplicate 2025-11-26 19:10:51 +01:00
david 4790ad6c62 Simplify docker-compose naming (use docker-compose.yml for local dev) 2025-11-26 19:10:15 +01:00
david f0643645b8 Add docker-compose.dev for local development 2025-11-26 18:57:24 +01:00
david a0141019b4 Add habit statistics feature
- Implement GetHabitStatsHandler with streak calculations
- Calculate current streak, longest streak, and completion rate
- Track completions this week and this month
- Add stats HTTP handler and route at /api/v1/stats/habits/{id}
- Add Swagger documentation for stats endpoint
2025-11-26 18:45:27 +01:00