Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Docker ignore patterns
.git
.gitignore
README.md
MEJORAS_RECOMENDADAS.md
Dockerfile
docker-compose.yml
.dockerignore

# Development files
.air.toml
tmp/
logs/
*.log

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db

# Test files
*_test.go
testdata/

# Build artifacts
main
bin/
build/

# Documentation
api/docs/
39 changes: 39 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Database Configuration
DATABASE_URL=postgres://postgres:postgres@localhost:5432/go_api?sslmode=disable

# Redis Configuration
REDIS_URL=redis://localhost:6379

# Server Configuration
API_URL=localhost
PORT=8000

# Rate Limiting Configuration
RATE_LIMIT_MAX_REQUESTS=100
RATE_LIMIT_TIMEFRAME=60

# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-change-in-production
JWT_ISSUER=go-api
JWT_AUDIENCE=go-api-users
JWT_TOKEN_EXPIRATION=86400
JWT_REFRESH_EXPIRATION=604800

# API Key (for internal endpoints)
API_KEY=your-api-key-change-in-production

# Cloudflare R2 Storage Configuration
STORAGE_BUCKET_NAME=your-bucket-name
STORAGE_ACCOUNT_ID=your-account-id
STORAGE_ACCESS_KEY_ID=your-access-key-id
STORAGE_SECRET_ACCESS_KEY=your-secret-access-key
STORAGE_PUBLIC_DOMAIN=your-custom-domain.com
STORAGE_USE_PUBLIC_URL=false

# Web Push Notifications
VAPID_PUBLIC_KEY=your-vapid-public-key
VAPID_PRIVATE_KEY=your-vapid-private-key

# Development Environment
ENVIRONMENT=development
LOG_LEVEL=debug
160 changes: 160 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
name: CI/CD Pipeline

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

env:
GO_VERSION: '1.24.4'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: go_api_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}

- name: Cache Go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-

- name: Download dependencies
run: go mod download

- name: Verify dependencies
run: go mod verify

- name: Install golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest

- name: Run tests
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/go_api_test?sslmode=disable
REDIS_URL: redis://localhost:6379
run: |
go test -race -coverprofile=coverage.out -covermode=atomic ./...

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.out
fail_ci_if_error: true

- name: Build
run: go build -v ./cmd/api/main.go

security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}

- name: Run Gosec Security Scanner
uses: securecodewarrior/github-action-gosec@master
with:
args: './...'

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'

docker:
needs: [test, security]
runs-on: ubuntu-latest
if: github.event_name == 'push'

permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

deploy:
needs: [docker]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'

steps:
- name: Deploy to production
run: |
echo "Deployment step - replace with your deployment logic"
echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
101 changes: 101 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
run:
timeout: 5m
issues-exit-code: 1
tests: true

output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true

linters-settings:
gofmt:
simplify: true
goimports:
local-prefixes: github.com/imlargo/go-api
golint:
min-confidence: 0.8
govet:
check-shadowing: true
misspell:
locale: US
unused:
check-exported: false
unparam:
check-exported: false
gocritic:
enabled-tags:
- performance
- style
- experimental
disabled-checks:
- wrapperFunc
cyclop:
max-complexity: 15
funlen:
lines: 100
statements: 60
gocognit:
min-complexity: 15
nestif:
min-complexity: 4
lll:
line-length: 120

linters:
disable-all: true
enable:
- bodyclose
- cyclop
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- funlen
- gochecknoinits
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- golint
- gomnd
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- lll
- misspell
- nakedret
- nestif
- prealloc
- rowserrcheck
- scopelint
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace

issues:
exclude-rules:
- path: _test\.go
linters:
- gomnd
- funlen
- goconst
- path: cmd/
linters:
- gochecknoinits
- text: "weak cryptographic primitive"
linters:
- gosec
max-issues-per-linter: 0
max-same-issues: 0
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Multi-stage build for Go API
FROM golang:1.24.4-alpine AS builder

# Install ca-certificates and git for dependencies
RUN apk add --no-cache ca-certificates git

# Set working directory
WORKDIR /app

# Copy go mod files first for better caching
COPY go.mod go.sum ./
RUN go mod download

# Copy source code
COPY . .

# Build the application
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/api/main.go

# Final stage - minimal image
FROM alpine:latest

# Install ca-certificates for HTTPS requests
RUN apk --no-cache add ca-certificates

WORKDIR /root/

# Copy the binary from builder stage
COPY --from=builder /app/main .

# Expose port
EXPOSE 8000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1

# Run the binary
CMD ["./main"]
Loading