Backend API for the mindful-minutes meditation tracking application. Built with Go, PostgreSQL, and Docker.
- User authentication via Clerk webhooks
- Session management for meditation tracking
- Analytics and streak calculations
- Dashboard data aggregation
- RESTful API with comprehensive validation
- Language: Go 1.21+
- Framework: Gin HTTP router
- Database: PostgreSQL 15
- Authentication: Clerk webhook integration
- Containerization: Docker & Docker Compose
- Testing: Go testing with testify
- Go 1.21 or higher
- Docker and Docker Compose
- Clerk account for authentication
Create a .env file in the root directory:
# Database Configuration
DATABASE_URL=postgres://mindful_user:mindful_pass@localhost:5432/mindful_minutes?sslmode=disable
# Clerk Configuration
CLERK_SECRET_KEY=your_clerk_secret_key_here
# Server Configuration
GIN_MODE=debug
PORT=8080-
Clone the repository
git clone https://github.com/nitinstp23/mindful-minutes-api.git cd mindful-minutes-api -
Install dependencies
go mod download
-
Start the database
docker-compose up postgres -d
-
Run database migrations
# Migrations are automatically applied when the database starts # Check docker-compose.yml for migration setup
-
Run the application
go run cmd/server/main.go
The API will be available at
http://localhost:8080
# Set your Clerk secret key
export CLERK_SECRET_KEY=your_clerk_secret_key_here
# Start all services
docker-compose up --buildAll API endpoints (except health check) require authentication via Clerk. Include the authorization header:
Authorization: Bearer <clerk_session_token>http://localhost:8080
GET /healthResponse:
{
"status": "healthy",
"timestamp": "2025-07-08T10:00:00Z"
}POST /webhooks/clerkRequest Body:
{
"type": "user.created",
"data": {
"id": "user_clerk_id",
"email_addresses": [
{
"email_address": "[email protected]"
}
],
"first_name": "John",
"last_name": "Doe"
}
}POST /api/sessionsRequest Body:
{
"duration_seconds": 600,
"session_type": "mindfulness",
"notes": "Morning meditation session"
}Response:
{
"id": "session_id",
"user_id": "user_ulid",
"duration_seconds": 600,
"session_type": "mindfulness",
"notes": "Morning meditation session",
"created_at": "2025-07-08T10:00:00Z"
}GET /api/sessions?limit=10&cursor=cursor_valueResponse:
{
"sessions": [
{
"id": "session_id",
"user_id": "user_ulid",
"duration_seconds": 600,
"session_type": "mindfulness",
"notes": "Morning meditation session",
"created_at": "2025-07-08T10:00:00Z"
}
],
"pagination": {
"next_cursor": "next_cursor_value",
"has_more": true
}
}DELETE /api/sessions/{session_id}Response:
{
"message": "Session deleted successfully"
}GET /api/dashboard?year=2025&sessions=5Response:
{
"current_streak": 5,
"longest_streak": 12,
"total_sessions": 45,
"total_minutes": 2700,
"weekly_progress": [
{
"date": "2025-07-01",
"sessions": 2,
"total_minutes": 30
}
],
"yearly_progress": [
{
"month": "January",
"sessions": 15,
"total_minutes": 450
}
],
"recent_sessions": [
{
"id": "session_id",
"duration_seconds": 600,
"session_type": "mindfulness",
"notes": "Evening session",
"created_at": "2025-07-08T20:00:00Z"
}
]
}Valid session types:
mindfulnessbreathingmettabody_scanwalkingother
All endpoints return consistent error responses:
{
"error": "Error message",
"details": "Additional error details (in development mode)"
}Common HTTP status codes:
400- Bad Request (validation errors)401- Unauthorized (authentication required)404- Not Found500- Internal Server Error
# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run tests for specific package
go test -v ./internal/handlers
# Run specific test
go test -v ./internal/handlers -run TestCreateSession# Generate coverage report
go test -cover ./...
# Generate HTML coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.htmlTests use an in-memory SQLite database for fast, isolated testing. The test utilities automatically:
- Set up a fresh database for each test
- Clean up data after each test
- Migrate database schema
Tests follow the pattern:
func TestFunctionName(t *testing.T) {
t.Run("return expected result when condition", func(t *testing.T) {
// Test implementation
})
}# Run linter (requires golangci-lint)
golangci-lint run
# Format code
go fmt ./...
# Build project
go build ./...cmd/server/- Application entry pointinternal/handlers/- HTTP request handlersinternal/services/- Business logicinternal/models/- Database modelsinternal/auth/- Authentication middlewareinternal/database/- Database connection and utilitiesinternal/config/- Configuration managementinternal/testutils/- Test utilities
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run tests and linting
- Submit a pull request
This project is licensed under the MIT License.