A simple CRUD REST API for managing changelog posts built with Go, Chi router, and PostgreSQL.
- Create, Read, Update, Delete changelog posts
- HTML description support
- Multiple images per changelog (stored as JSONB)
- Track which users have seen each changelog
- Pagination support
- RESTful API design
- PostgreSQL database with proper indexing
- Docker support for easy development
- Language: Go 1.21+
- Router: Chi v5
- Database: PostgreSQL 16
- Container: Docker & Docker Compose
.
├── cmd/
│ └── api/
│ └── main.go # Application entry point
├── internal/
│ ├── handlers/
│ │ └── handlers.go # HTTP request handlers
│ ├── models/
│ │ └── changelog.go # Data models
│ └── repository/
│ └── repository.go # Database operations
├── migrations/
│ ├── 001_initial_schema.sql # Database schema
│ └── down.sql # Rollback migrations
├── docker-compose.yml # Docker setup
├── Makefile # Build commands
└── README.md
- Go 1.21 or higher
- Docker and Docker Compose
- Make (optional, for convenience commands)
- Clone the repository:
git clone https://github.com/FlowieAI/changelog.git
cd changelog- Copy environment variables:
cp .env.example .env- Install dependencies:
go mod downloadStart the database:
make docker-upRun migrations:
make migrate-upRun the application:
make runOr start everything at once:
make devStart PostgreSQL:
docker-compose up -dWait for database to be ready, then run migrations:
docker exec -i changelog_db psql -U changelog -d changelog < migrations/001_initial_schema.sqlRun the application:
go run cmd/api/main.goThe API will be available at http://localhost:8080
GET /health
POST /api/v1/changelogs
Content-Type: application/json
{
"title": "Version 1.0.0 Released",
"description": "<h1>New Features</h1><p>Exciting updates!</p>",
"images": ["https://example.com/image1.jpg", "https://example.com/image2.jpg"]
}
GET /api/v1/changelogs?limit=10&offset=0
Response:
{
"data": [...],
"total": 100,
"limit": 10,
"offset": 0,
"total_pages": 10
}GET /api/v1/changelogs/{id}
PUT /api/v1/changelogs/{id}
Content-Type: application/json
{
"title": "Updated Title",
"description": "<p>Updated description</p>",
"images": ["https://example.com/new-image.jpg"]
}
Note: All fields are optional in the update request.
DELETE /api/v1/changelogs/{id}
POST /api/v1/changelogs/{id}/seen
Content-Type: application/json
{
"user_uuid": "123e4567-e89b-12d3-a456-426614174000"
}
GET /api/v1/changelogs/{id}/seen
Response:
[
{
"changelog_id": "123e4567-e89b-12d3-a456-426614174000",
"user_uuid": "456e7890-e89b-12d3-a456-426614174111",
"seen_at": "2024-01-15T10:30:00Z"
}
]id(UUID, primary key)title(VARCHAR 255)description(TEXT) - HTML contentimages(JSONB) - Array of image URLscreated_at(TIMESTAMP)updated_at(TIMESTAMP)
changelog_id(UUID, foreign key)user_uuid(UUID)seen_at(TIMESTAMP)- Primary key:
(changelog_id, user_uuid)
make buildmake testmake docker-logsmake docker-downmake migrate-down
make migrate-upDATABASE_URL- PostgreSQL connection string (default:postgres://changelog:changelog@localhost:5432/changelog?sslmode=disable)PORT- Server port (default:8080)
This service is designed to be deployed on Kubernetes using the manifests in the k8s/ directory.
- Kubernetes cluster (configured via https://github.com/FlowieAI/k8s-deployments)
- PostgreSQL database (running in the cluster or external)
- kubectl configured to access your cluster
- Update the secret with your database connection string:
Edit k8s/secret.yaml and replace the database-url with your PostgreSQL connection string:
database-url: "postgres://username:password@postgres-host:5432/changelog?sslmode=require"- Update the ingress with your domain:
Edit k8s/ingress.yaml and replace changelog.yourdomain.com with your actual domain.
- Apply the Kubernetes manifests:
# Apply secret (do this first)
kubectl apply -f k8s/secret.yaml
# Run database migration
kubectl apply -f k8s/migration-job.yaml
# Wait for migration to complete
kubectl wait --for=condition=complete job/changelog-migration --timeout=300s
# Deploy the application
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml- Verify deployment:
# Check if pods are running
kubectl get pods -l app=changelog-api
# Check service
kubectl get svc changelog-api
# Check ingress
kubectl get ingress changelog-api
# View logs
kubectl logs -l app=changelog-api --tail=50 -fThe repository includes a GitHub Actions workflow (.github/workflows/docker-build.yml) that automatically:
- Builds the Docker image on every push to
main - Pushes the image to GitHub Container Registry (ghcr.io)
- Tags images with branch name, commit SHA, and
latest
The image will be available at: ghcr.io/flowieai/changelog:latest
To integrate this service into your k8s-deployments repository:
- Copy the
k8s/directory contents to your k8s-deployments repo:
cp -r k8s/ ../k8s-deployments/services/changelog/-
Update your ArgoCD or Flux configuration to include the changelog service.
-
Ensure your PostgreSQL database is accessible from the cluster.
The application uses the following environment variables in Kubernetes:
DATABASE_URL- Set via Secret (changelog-secrets)PORT- Set to8080in the deployment
To scale the number of replicas:
kubectl scale deployment changelog-api --replicas=3Or update the replicas field in k8s/deployment.yaml.
The migration job (k8s/migration-job.yaml) should be run:
- Before the first deployment
- After any database schema changes
To manually run migrations:
kubectl delete job changelog-migration # Delete old job if exists
kubectl apply -f k8s/migration-job.yaml
kubectl logs -f job/changelog-migrationThe deployment includes:
- Liveness probe: Checks
/healthendpoint every 10s - Readiness probe: Checks
/healthendpoint every 5s - Resource limits: 256Mi memory, 500m CPU
Check pod logs:
kubectl logs -l app=changelog-api --tail=100Describe pod for events:
kubectl describe pod -l app=changelog-apiTest database connectivity:
kubectl run psql-test --rm -it --image=postgres:16-alpine -- psql $DATABASE_URL- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
MIT License