Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Jun 24, 2025

Summary by CodeRabbit

  • New Features

    • Introduced new Caddy server configurations for local and production environments, including enhanced security headers and compression for production.
    • Added multi-stage Docker build for the API, improving security and deployment efficiency.
    • Modularized Docker Compose setup with distinct services for API, database, and Caddy, supporting both local and production profiles.
  • Improvements

    • Simplified and clarified environment variable examples and documentation.
    • Streamlined Makefile and build process to use Docker Compose profiles for local and production builds.
    • Updated database and network environment validation rules for greater flexibility.
    • Standardized service and container naming conventions across configuration files.
    • Enhanced environment loading and validation by decoupling validator initialization and improving environment variable retrieval.
  • Cleanup

    • Removed unused or redundant build targets, variables, and configuration sections from Makefiles and ignore files.
    • Eliminated deprecated fields and logic from environment and database configuration.

@coderabbitai
Copy link

coderabbitai bot commented Jun 24, 2025

Walkthrough

This change restructures the build and deployment process to use Docker Compose profiles and Caddy as a reverse proxy. It updates environment and configuration files, simplifies Makefile targets, and removes legacy bin directory handling. The environment loading and validation logic is refactored to use system environment variables and explicit validator injection.

Changes

Files/Paths Change Summary
.air.toml, .gitignore, .dockerignore Removed or updated bin directory exclusions; adjusted ignore patterns.
.env.example Cleaned up, reorganized, and updated environment variable examples and comments; removed unused variables.
Makefile, config/makefile/app.mk, config/makefile/build.mk, config/makefile/db.mk, config/makefile/logs.mk Simplified and modularized Makefile system; removed legacy build targets; switched to Docker Compose-based builds; updated variable and container names.
boost/factory.go, boost/ignite.go Refactored environment loading to use system environment variables and explicit validator parameter; updated function signatures.
env/db.go, env/network.go Removed unused fields; relaxed validation constraints for DB and network environment structs.
database/model.go, database/connection.go Added DriverName constant; removed unused URL field from connection struct.
cli/main.go, main.go, database/seeder/main.go Updated initialization to use new environment and validator loading logic.
go.mod Added local replace directive for boost module.
caddy/Caddyfile.local, caddy/Caddyfile.prod, caddy/Dockerfile Added new Caddy configuration files and Dockerfile for local and production reverse proxy setups.
docker/dockerfile-api Added multi-stage Dockerfile for Go application build and deployment.
docker-compose.yml Major restructure: added Caddy and API services, split networks, introduced volumes, and updated service definitions.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Make as Makefile
    participant Docker as Docker Compose
    participant Caddy as Caddy Service
    participant API as API Service
    participant DB as Postgres DB

    Dev->>Make: make build:local / build:prod
    Make->>Docker: docker compose --profile [local|prod] up --build -d
    Docker->>Caddy: Start Caddy (local/prod profile)
    Docker->>API: Start API container
    Docker->>DB: Start Postgres container
    Caddy->>API: Reverse proxy HTTP requests (via caddy_net)
    API->>DB: Connect to database (via oullin_net)
Loading

Possibly related PRs

  • Blog post parser #32: Modifies environment loading and validator initialization in the boost package, closely related to this PR's changes in environment and validator management.

Poem

A rabbit hops through Docker fields,
With Caddy’s proxy now revealed.
The bin is gone, the scripts are lean,
Compose and Make in sync and clean.
Environment fresh, the networks new—
Oullin’s stack, a dream come true!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4796c95 and 07b702a.

📒 Files selected for processing (1)
  • caddy/Dockerfile (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • caddy/Dockerfile

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gocanto gocanto changed the title Add [api] reverse proxy Caddy: API Reverse Proxy Jun 25, 2025
@gocanto gocanto marked this pull request as ready for review June 25, 2025 05:52
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (6)
caddy/Dockerfile (2)

3-3: Consider pinning the Caddy version for reproducible builds.

Using caddy:latest can lead to unpredictable builds. Consider pinning to a specific version like caddy:2.7-alpine for consistency across environments.

-FROM caddy:latest
+FROM caddy:2.7-alpine

7-7: Hard-coded configuration file limits flexibility.

The Dockerfile currently only copies Caddyfile.local, but the AI summary mentions both Caddyfile.local and Caddyfile.prod. Consider using a build argument to make this configurable for different environments.

+ARG CADDY_CONFIG=Caddyfile.local
-COPY Caddyfile.local /etc/caddy/Caddyfile
+COPY ${CADDY_CONFIG} /etc/caddy/Caddyfile
docker/dockerfile-api (1)

70-70: Consider pinning the Alpine version for reproducible builds.

Using alpine:${ALPINE_VERSION} with ALPINE_VERSION=latest can lead to unpredictable builds. Consider using a specific version like 3.19.

-ARG ALPINE_VERSION=latest
+ARG ALPINE_VERSION=3.19
caddy/Caddyfile.prod (1)

4-21: LGTM! Well-configured production setup with good security practices.

The production Caddyfile includes essential security measures:

  • Automatic HTTPS via Let's Encrypt
  • Appropriate compression for performance
  • Essential security headers (HSTS, X-Frame-Options, X-Content-Type-Options)
  • Consistent reverse proxy configuration

Consider adding additional security headers for enhanced protection:

    header {
        # Enable HSTS to ensure browsers only connect via HTTPS.
        Strict-Transport-Security "max-age=31536000;"
        # Prevent clickjacking attacks.
        X-Frame-Options "SAMEORIGIN"
        # Prevent content type sniffing.
        X-Content-Type-Options "nosniff"
+       # Additional security headers
+       X-XSS-Protection "1; mode=block"
+       Referrer-Policy "strict-origin-when-cross-origin"
    }
boost/factory.go (1)

60-85: Good refactoring, but consider testability implications.

The refactoring from map-based to direct os.Getenv() calls simplifies the code and eliminates parameter passing. The use of database.DriverName constant is also an improvement over hardcoding.

However, consider the testability implications:

Suggestion: Consider adding a helper function for testability:

+func getEnvVar(key string) string {
+    return strings.TrimSpace(os.Getenv(key))
+}
+
func MakeEnv(validate *pkg.Validator) *env.Environment {
    errorSufix := "Environment: "

-   port, _ := strconv.Atoi(os.Getenv("ENV_DB_PORT"))
+   port, _ := strconv.Atoi(getEnvVar("ENV_DB_PORT"))

    token := auth.Token{
-       Public:  strings.TrimSpace(os.Getenv("ENV_APP_TOKEN_PUBLIC")),
-       Private: strings.TrimSpace(os.Getenv("ENV_APP_TOKEN_PRIVATE")),
+       Public:  getEnvVar("ENV_APP_TOKEN_PUBLIC"),
+       Private: getEnvVar("ENV_APP_TOKEN_PRIVATE"),
    }

This would make the code more testable by allowing the helper function to be mocked in tests.

boost/ignite.go (1)

10-12: Consider implications of loading env vars into global process environment.

Loading environment variables directly into the process environment using godotenv.Load() affects global state, which could impact other parts of the application or tests. Consider documenting this behavior or evaluating if a more isolated approach would be better for testing.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2c96c2 and 65a4050.

📒 Files selected for processing (24)
  • .air.toml (0 hunks)
  • .dockerignore (1 hunks)
  • .env.example (1 hunks)
  • .gitignore (0 hunks)
  • Makefile (2 hunks)
  • boost/factory.go (2 hunks)
  • boost/ignite.go (1 hunks)
  • caddy/Caddyfile.local (1 hunks)
  • caddy/Caddyfile.prod (1 hunks)
  • caddy/Dockerfile (1 hunks)
  • cli/main.go (1 hunks)
  • config/makefile/app.mk (1 hunks)
  • config/makefile/build.mk (1 hunks)
  • config/makefile/db.mk (1 hunks)
  • config/makefile/logs.mk (0 hunks)
  • database/connection.go (0 hunks)
  • database/model.go (1 hunks)
  • database/seeder/main.go (2 hunks)
  • docker-compose.yml (1 hunks)
  • docker/dockerfile-api (1 hunks)
  • env/db.go (1 hunks)
  • env/network.go (1 hunks)
  • go.mod (1 hunks)
  • main.go (1 hunks)
💤 Files with no reviewable changes (4)
  • config/makefile/logs.mk
  • .air.toml
  • .gitignore
  • database/connection.go
🔇 Additional comments (33)
.dockerignore (1)

16-16: Question: Should the caddy/ directory be ignored?

Since there's a new caddy/Dockerfile that needs to be built, ignoring the entire caddy/ directory might prevent the Docker build context from accessing necessary files like Caddyfile.local and Caddyfile.prod mentioned in the AI summary.

#!/bin/bash
# Check if caddy directory contains files that need to be included in Docker builds
fd . caddy/ --type f
go.mod (1)

36-36: Verify the local replace directive is intentional for containerized builds.

The replace directive points to a local ./boost directory, which is appropriate for development but ensure this works correctly in the containerized build process defined in docker/dockerfile-api. The Dockerfile copies the entire source code, so the local boost package should be available during the build.

config/makefile/app.mk (1)

23-23: LGTM! Documentation formatting improved.

The comment formatting changes improve readability and maintain consistency in the documentation style.

Also applies to: 27-28

docker/dockerfile-api (4)

107-110: Review security implications of copying .env file into the image.

While copying the .env file enables configuration loading, it permanently embeds potentially sensitive environment variables into the Docker image. Consider whether this is the intended behavior or if environment variables should be passed at runtime instead.

For production deployments, it's generally safer to:

  1. Use environment variables passed at runtime via docker run -e or Docker Compose
  2. Use Docker secrets for sensitive data
  3. Mount configuration files as volumes

Do you want to keep the .env file in the image, or would you prefer runtime environment variable injection?


65-65: Excellent build optimization with static linking and version injection.

The build command uses great practices:

  • CGO_ENABLED=0 for static linking
  • -ldflags="-s -w" for binary size reduction
  • Version injection via -X main.Version=${APP_VERSION}
  • Build tags for conditional compilation

83-85: Strong security practices with non-root user.

Creating and using a dedicated non-root user (adduser -S) is an excellent security practice that follows the principle of least privilege.


46-51: Excellent Docker layer caching optimization.

Copying go.mod and go.sum first, then running go mod download before copying the source code is a best practice that maximizes Docker layer caching efficiency.

database/model.go (1)

9-9: LGTM! Good refactoring to eliminate magic strings.

Extracting the database driver name into a named constant improves maintainability and reduces the risk of typos when referencing the driver across the codebase.

env/network.go (1)

4-4: Verify the rationale for reducing minimum host length validation.

The minimum length validation was reduced from 8 to 7 characters. While this accommodates shorter hostnames and IP addresses (e.g., "1.1.1.1" or "app.com"), please ensure this change aligns with your expected host formats and doesn't compromise validation robustness.

config/makefile/db.mk (1)

8-8: LGTM! Consistent container renaming.

The database container name change from "gocanto-db" to "oullin_db" is consistently applied and aligns with the project restructuring mentioned in the AI summary.

database/seeder/main.go (1)

8-8: LGTM! Good addition for explicit validation.

Adding the pkg import to support the validator injection pattern is a positive change that makes validation dependencies explicit.

cli/main.go (1)

19-19: ```shell
#!/bin/bash

Description: Locate the definition of Ignite in the boost package to verify its return signature

echo "Searching for Ignite function definitions in the codebase:"
rg -n "func Ignite" -C 3


</details>
<details>
<summary>caddy/Caddyfile.local (1)</summary>

`1-25`: **LGTM! Well-configured local development setup.**

The Caddyfile configuration is appropriate for local development:
- Correctly disables HTTPS for local environment
- Proper reverse proxy setup to the API service
- Good logging configuration for debugging
- Clear and helpful comments

</details>
<details>
<summary>main.go (2)</summary>

`6-6`: **LGTM! Proper dependency addition.**

The new import for the `pkg` package is correctly added to support the explicit validator retrieval.

---

`14-18`: **LGTM! Good refactoring towards explicit dependency injection.**

The changes improve the initialization logic by:
- Explicitly obtaining the validator via `pkg.GetDefaultValidator()`
- Passing the validator to `boost.Ignite` as a parameter
- Clear separation of concerns between validator creation and environment initialization

This follows better dependency injection patterns and makes the code more testable.

</details>
<details>
<summary>env/db.go (1)</summary>

`8-8`: **Verify the relaxed validation is intentional.**

The minimum length validation for `DatabaseName` was reduced from 10 to 5 characters. Ensure this change aligns with your database naming requirements and doesn't compromise validation standards.



```shell
#!/bin/bash
# Description: Check for database name usage patterns in the codebase
# Expected: Verify current database names meet the new 5-character minimum

# Search for database name configurations and usage
rg -i "database.*name|db.*name" --type go -A 2 -B 2
echo "---"
# Check environment files for database names
fd -e env -e example | xargs cat | grep -i "db.*name"
boost/factory.go (1)

12-12: LGTM! Necessary import for direct environment variable access.

The os import is correctly added to support the refactored environment variable loading.

boost/ignite.go (2)

9-9: Good refactoring - validator injection improves testability.

The change to accept a validator parameter instead of creating a default one internally improves dependency injection and makes the function more testable.


10-12: Verify all callers updated for new function signature.

The function signature change from Ignite(envPath string) to Ignite(envPath string, validate *pkg.Validator) requires updates to all calling code. Ensure consistency across the codebase.

#!/bin/bash
# Description: Find all calls to Ignite function to verify they've been updated with the new signature

# Search for calls to boost.Ignite or Ignite function
rg -A 3 -B 1 'Ignite\(' --type go
Makefile (3)

46-46: Improved help text clarity.

The change from "Makefile Commands" to "Applications Options" better describes the available operations for users.


50-58: Consistent formatting improvements.

The added spacing in help descriptions improves alignment and readability of the command documentation.


56-58: Verify new build targets match Docker Compose profiles.

The simplified build targets (build:local, build:prod, build:release) should correspond to the profiles defined in docker-compose.yml. Ensure the profile names are consistent.

#!/bin/bash
# Description: Verify Docker Compose profiles match Makefile build targets

# Check for profile definitions in docker-compose.yml
rg 'profiles:' docker-compose.yml

# Check build targets in build.mk
rg 'build\\:' config/makefile/build.mk
.env.example (3)

1-1: Improved section organization.

The simplified section headers (App, Auth, DB) make the environment file more readable and easier to navigate.

Also applies to: 9-9, 13-13


22-31: Excellent documentation for debugging and Docker variables.

The expanded comments clearly explain when EN_DB_BIN_DIR and ENV_DB_URL are needed, which helps developers understand their purpose.


14-16: Verify database credential consistency across environment files.

The database credentials have been updated to use "gus", "password", and "oullin_db". Ensure these changes are consistent across all environment-related files and Docker configurations.

#!/bin/bash
# Description: Check for consistency of database credentials across configuration files

# Search for database name references
rg -i 'oullin_db|gocanto' --type yaml --type go

# Check Docker Compose for database service name
rg 'container_name.*db|POSTGRES_DB' docker-compose.yml
config/makefile/build.mk (2)

1-1: Clean simplification of build targets.

The updated .PHONY declaration correctly reflects the three remaining build targets, removing obsolete ones.


3-7: Verify Docker Compose profiles and service dependencies.

The new build targets use Docker Compose profiles (local and prod). Ensure that:

  1. The profiles are properly defined in docker-compose.yml
  2. All required services have appropriate dependencies
  3. The --build -d flags work correctly with the new setup
#!/bin/bash
# Description: Verify Docker Compose profiles and service configuration

# Check if profiles are defined in docker-compose.yml
echo "=== Checking Docker Compose profiles ==="
rg 'profiles:.*\[(local|prod)\]' docker-compose.yml

# Check service dependencies
echo "=== Checking service dependencies ==="
rg -A 5 'depends_on:' docker-compose.yml

# Validate Docker Compose file syntax
echo "=== Validating Docker Compose syntax ==="
docker compose -f docker-compose.yml config --quiet && echo "Docker Compose file is valid" || echo "Docker Compose file has syntax errors"
docker-compose.yml (6)

1-4: Good addition of persistent volumes for Caddy.

The caddy_data and caddy_config volumes ensure Caddy's SSL certificates and configuration persist across container restarts.


5-11: Excellent network segmentation architecture.

The separation of caddy_net (for reverse proxy) and oullin_net (for backend services) provides good security isolation between the public-facing proxy and internal services.


55-82: API service configuration looks comprehensive.

The API service configuration includes:

  • Proper environment variable injection
  • Multi-network connectivity (caddy_net + oullin_net)
  • Health-based dependency on postgres
  • Build arguments for versioning

This setup enables the API to communicate with both the database and receive requests from Caddy.


60-63: Good container networking configuration.

Setting ENV_DB_HOST: postgres and ENV_HTTP_HOST: 0.0.0.0 correctly configures the API to:

  1. Connect to the postgres service by its service name
  2. Listen on all interfaces for incoming connections from Caddy

83-129: Verify postgres service health check configuration.

The postgres service includes a comprehensive health check, but verify that:

  1. The pg_isready command works with the specified parameters
  2. The health check intervals are appropriate for your use case
  3. The SSL certificate paths exist and are properly configured
#!/bin/bash
# Description: Verify database configuration files and SSL certificates

# Check if database SSL certificates exist
echo "=== Checking database SSL certificates ==="
ls -la database/infra/ssl/server.crt database/infra/ssl/server.key 2>/dev/null || echo "Database SSL certificates not found"

# Check if postgresql.conf exists
echo "=== Checking PostgreSQL configuration ==="
ls -la database/infra/config/postgresql.conf 2>/dev/null || echo "PostgreSQL configuration not found"

# Check docker-entrypoint-initdb.d directory
echo "=== Checking database initialization scripts ==="
ls -la database/infra/docker-entrypoint-initdb.d/ 2>/dev/null || echo "Database init directory not found"

14-34: ```shell
#!/bin/bash

Fetch the caddy_local service definition and its port mappings from docker-compose.yml

echo "=== caddy_local service ports in docker-compose.yml ==="
grep -R "caddy_local" -n docker-compose.yml -A 10


</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
caddy/Dockerfile (1)

13-13: Consider making the Caddyfile source configurable.

The hardcoded Caddyfile.local filename limits flexibility. Consider using a build argument to specify which Caddyfile to copy.

You could add a build argument for the Caddyfile:

ARG CADDY_VERSION=2.10.0
+ARG CADDYFILE=Caddyfile.local

# Copy your custom Caddyfile into the container.
# This overwrites the default Caddyfile.
-COPY Caddyfile.local /etc/caddy/Caddyfile
+COPY ${CADDYFILE} /etc/caddy/Caddyfile
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65a4050 and 4796c95.

📒 Files selected for processing (5)
  • boost/factory.go (1 hunks)
  • caddy/Caddyfile.prod (1 hunks)
  • caddy/Dockerfile (1 hunks)
  • docker-compose.yml (1 hunks)
  • env/env.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • boost/factory.go
  • caddy/Caddyfile.prod
🔇 Additional comments (6)
env/env.go (2)

3-6: LGTM: Clean import structure.

The import additions for os and strings are appropriate for the new GetEnvVar function.


16-18: LGTM: Simple and effective environment variable retrieval.

The GetEnvVar function is well-implemented with proper whitespace trimming. This approach is cleaner than the previous map-based method mentioned in the summary.

docker-compose.yml (4)

1-3: LGTM: Named volumes for Caddy data persistence.

The named volumes caddy_data and caddy_config provide proper persistence for Caddy's data and configuration.


6-11: LGTM: Network separation improves security.

The separate networks caddy_net and oullin_net provide good isolation between the reverse proxy layer and the backend services.


87-90: Verify service name consistency for database connections.

The service is named postgres but has container name oullin_db. Ensure this doesn't cause confusion in database connections.

The service name postgres should be accessible from other services in the same network, but verify this matches the ENV_DB_HOST configuration in the API service.


120-132: LGTM: Comprehensive health check configuration.

The health check configuration for PostgreSQL is well-structured with appropriate intervals, timeouts, and retry logic.

@gocanto gocanto merged commit 738ac44 into main Jun 25, 2025
2 checks passed
@gocanto gocanto deleted the feature/caddy branch June 25, 2025 06:47
@coderabbitai coderabbitai bot mentioned this pull request Nov 7, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants