Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Jun 20, 2025

Summary by CodeRabbit

  • New Features

    • Introduced public API endpoints for profile, experience, projects, social links, and talks, serving static JSON data.
    • Added new JSON fixture files for profile, experience, projects, social, and talks data.
  • Refactor

    • Centralized and simplified application setup and routing, improving maintainability.
    • Replaced manual middleware and handler management with a modular router and middleware pipeline.
    • Streamlined environment variable handling and removed unused or redundant fields.
    • Enhanced middleware with username and token validation for API requests.
  • Bug Fixes

    • Improved error handling and consistent JSON error responses for API endpoints.
  • Chores

    • Cleaned up and removed legacy user management code and related middleware.
    • Updated environment example file to remove obsolete variables.

@coderabbitai
Copy link

coderabbitai bot commented Jun 20, 2025

Walkthrough

This update introduces a major refactor of the application's initialization, routing, and handler architecture. It removes legacy user management code, introduces modular route handlers serving JSON fixture data, and establishes a new middleware pipeline for authentication and authorization. The application setup is streamlined via a new App abstraction, centralizing environment, logging, and database management. Numerous supporting utilities, middleware, and schema types are added or restructured to support this modular, testable design.

Changes

File(s) Change Summary
.env.example, env/app.go, pkg/auth/token.go Removed ENV_APP_TOKEN_USERNAME and ApiKeyHeader; Token struct no longer has Username field.
boost/app.go, boost/factory.go, boost/helpers.go, boost/ignite.go, boost/router.go Refactored app struct and initialization; added helpers, new router, and renamed Spark to Ignite.
main.go, cli/main.go, database/seeder/main.go Updated app/environment initialization to use new App and Ignite flow; minor log/case tweaks.
handler/experience.go, handler/profile.go, handler/projects.go, handler/social.go, handler/talks.go, handler/response.go Added new modular handlers serving JSON fixture data and helper for JSON responses.
pkg/http/handler.go, pkg/http/message.go, pkg/http/schema.go Added API handler wrapper, internal error helper, and new error/middleware schemas.
pkg/http/middleware/pipeline.go, pkg/http/middleware/token.go, pkg/http/middleware/username.go Introduced pipeline struct and new middleware for token and username checks.
handler/user/admin.go, handler/user/create.go, handler/user/repository.go, handler/user/schema.go Removed legacy user management, creation, and repository code.
pkg/middleware/middlewares.go, pkg/middleware/schema.go Deleted old middleware stack and schema definitions.
storage/fixture/experience.json, storage/fixture/profile.json, storage/fixture/projects.json, storage/fixture/social.json, storage/fixture/talks.json Added new JSON fixture files for experience, profile, projects, social, and talks data.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Router
    participant Middleware
    participant Handler
    participant Storage

    Client->>Router: HTTP GET /api/{resource}
    Router->>Middleware: PipelineFor(handler)
    Middleware->>Middleware: UsernameCheck
    Middleware->>Middleware: TokenCheck
    Middleware->>Handler: Call Handle()
    Handler->>Storage: Read fixture JSON
    Storage-->>Handler: JSON content
    Handler-->>Client: JSON response
Loading

Poem

In fields of code, a rabbit hops,
Refactoring old, with gentle plops.
Middleware guards the garden gate,
JSON carrots on each plate.
The app now boots with nimble cheer—
Fresh fixtures, routes, and flow appear!
🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 force-pushed the feature/add-fixtures branch from fd4743f to 6a75064 Compare June 23, 2025 03:51
@gocanto gocanto force-pushed the feature/add-fixtures branch from 6a75064 to 34fdbc3 Compare June 23, 2025 03:53
@gocanto gocanto force-pushed the feature/add-fixtures branch from 02bfe20 to 3145f5d Compare June 23, 2025 07:06
@gocanto gocanto marked this pull request as ready for review June 23, 2025 07:07
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: 16

🧹 Nitpick comments (8)
handler/response.go (1)

8-17: Well-structured JSON response utility.

The function follows good practices by setting the correct Content-Type header, handling write errors appropriately, and providing meaningful error messages.

Consider adding a status code parameter for future flexibility:

-func writeJSON(content []byte, w baseHttp.ResponseWriter) error {
+func writeJSON(content []byte, w baseHttp.ResponseWriter, statusCode ...int) error {
 	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(baseHttp.StatusOK)
+	
+	status := baseHttp.StatusOK
+	if len(statusCode) > 0 {
+		status = statusCode[0]
+	}
+	w.WriteHeader(status)

This would maintain backward compatibility while allowing for error responses in the future.

pkg/http/middleware/username.go (1)

17-17: Consider making the username configurable.

The hardcoded username "gocanto" reduces flexibility and makes testing more difficult. Consider reading this from environment configuration.

-	if username != "gocanto" {
+	if username != m.Env.App.Username { // Assuming you add Username to env config
handler/talks.go (2)

14-18: Consider making the file path configurable.

The hardcoded file path "./storage/fixture/talks.json" reduces flexibility and makes testing harder. Consider accepting the path as a parameter or reading from configuration.

-func MakeTalks() Talks {
-	return Talks{
-		content: "./storage/fixture/talks.json",
-	}
+func MakeTalks(filePath string) Talks {
+	return Talks{
+		content: filePath,
+	}
 }

20-34: Consider validating file existence at startup.

The handler reads the file on every request. Consider validating file existence during initialization to fail fast if the fixture file is missing.

Additionally, you could add a startup validation method:

+func (h Talks) Validate() error {
+	if _, err := os.Stat(h.content); os.IsNotExist(err) {
+		return fmt.Errorf("talks fixture file not found: %s", h.content)
+	}
+	return nil
+}
storage/fixture/experience.json (1)

15-15: Consider standardizing skills field formatting.

The skills fields have inconsistent punctuation - some end with periods, others don't. Consider standardizing the format for consistency.

 "skills": "Executive Leadership, Strategic Planning, Engineering Management, Cross-functional Team Leadership, Technical Architecture."

Should be consistent across all entries (either all with periods or all without).

Also applies to: 28-28, 41-41, 54-54, 67-67, 80-80, 93-93

boost/helpers.go (1)

9-11: Consider passing Router by pointer

Taking Router by value and then taking its address could be inefficient for large structs. Consider accepting a pointer instead.

-func (a *App) SetRouter(router Router) {
-	a.router = &router
+func (a *App) SetRouter(router *Router) {
+	a.router = router
boost/router.go (1)

31-79: Consider abstracting route registration pattern

The route registration methods follow an identical pattern. Consider creating a helper method to reduce code duplication.

+func (r *Router) registerRoute(path string, handlerFactory func() interface{ Handle(baseHttp.ResponseWriter, *baseHttp.Request) *http.ApiError }) {
+	handler := handlerFactory()
+	resolver := r.PipelineFor(handler.Handle)
+	r.Mux.HandleFunc("GET "+path, resolver)
+}
+
 func (r *Router) Profile() {
-	abstract := handler.MakeProfileHandler()
-
-	resolver := r.PipelineFor(
-		abstract.Handle,
-	)
-
-	r.Mux.HandleFunc("GET /profile", resolver)
+	r.registerRoute("/profile", func() interface{ Handle(baseHttp.ResponseWriter, *baseHttp.Request) *http.ApiError } {
+		return handler.MakeProfileHandler()
+	})
 }
main.go (1)

10-10: Consider avoiding global variables for better testability.

Using a global app variable can make unit testing difficult and creates hidden dependencies.

Consider returning the app from a setup function instead:

-var app *boost.App
-
-func init() {
+func setupApp() *boost.App {
 	secrets, validate := boost.Ignite("./.env")
-	app = boost.MakeApp(secrets, validate)
+	return boost.MakeApp(secrets, validate)
 }

 func main() {
+	app := setupApp()
 	defer app.CloseDB()
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0c2d64d and baf3d5d.

📒 Files selected for processing (35)
  • .env.example (0 hunks)
  • boost/app.go (1 hunks)
  • boost/factory.go (3 hunks)
  • boost/helpers.go (1 hunks)
  • boost/ignite.go (1 hunks)
  • boost/router.go (1 hunks)
  • cli/main.go (1 hunks)
  • database/seeder/main.go (3 hunks)
  • database/seeder/seeds/factory.go (1 hunks)
  • env/app.go (0 hunks)
  • handler/experience.go (1 hunks)
  • handler/profile.go (1 hunks)
  • handler/projects.go (1 hunks)
  • handler/response.go (1 hunks)
  • handler/social.go (1 hunks)
  • handler/talks.go (1 hunks)
  • handler/user/admin.go (0 hunks)
  • handler/user/create.go (0 hunks)
  • handler/user/repository.go (0 hunks)
  • handler/user/schema.go (0 hunks)
  • main.go (1 hunks)
  • pkg/auth/token.go (1 hunks)
  • pkg/http/handler.go (1 hunks)
  • pkg/http/message.go (1 hunks)
  • pkg/http/middleware/pipeline.go (1 hunks)
  • pkg/http/middleware/token.go (1 hunks)
  • pkg/http/middleware/username.go (1 hunks)
  • pkg/http/schema.go (1 hunks)
  • pkg/middleware/middlewares.go (0 hunks)
  • pkg/middleware/schema.go (0 hunks)
  • storage/fixture/experience.json (1 hunks)
  • storage/fixture/profile.json (1 hunks)
  • storage/fixture/projects.json (1 hunks)
  • storage/fixture/social.json (1 hunks)
  • storage/fixture/talks.json (1 hunks)
💤 Files with no reviewable changes (8)
  • env/app.go
  • .env.example
  • pkg/middleware/schema.go
  • handler/user/schema.go
  • handler/user/admin.go
  • handler/user/create.go
  • pkg/middleware/middlewares.go
  • handler/user/repository.go
🧰 Additional context used
🪛 golangci-lint (1.64.8)
handler/experience.go

24-24: slog: slog.Error arg "err" should be a string or a slog.Attr (possible missing key or value)

(govet)

handler/projects.go

24-24: slog: slog.Error arg "err" should be a string or a slog.Attr (possible missing key or value)

(govet)

handler/profile.go

24-24: slog: slog.Error arg "err" should be a string or a slog.Attr (possible missing key or value)

(govet)

🔇 Additional comments (26)
storage/fixture/profile.json (1)

1-10: Well-structured fixture data with appropriate obfuscation.

The JSON structure is valid and the profile data is appropriately anonymized using an example domain. The reversed email format (otnacog@example.com) maintains consistency with the handle while using a safe example domain.

database/seeder/seeds/factory.go (1)

26-26: Good consistency improvement.

Lowercasing "db" in the error message follows Go error message conventions.

boost/ignite.go (1)

9-9: Function renaming improves clarity.

The rename from Spark to Ignite better describes the initialization purpose of this function.

Verify that all references to the old Spark function have been updated throughout the codebase:

#!/bin/bash
# Description: Check for any remaining references to the old Spark function name
# Expected: No remaining references to boost.Spark

echo "Searching for remaining references to boost.Spark..."
rg "boost\.Spark" --type go

echo "Searching for Spark function calls..."
rg "Spark\(" --type go
pkg/auth/token.go (1)

10-11: Token struct simplification aligns with authentication refactor.

Removing the Username field simplifies token-based authentication by eliminating username dependency, which aligns with the broader authentication refactoring described in the summary.

Verify that all code depending on the Username field has been updated:

#!/bin/bash
# Description: Check for any remaining references to Token.Username field
# Expected: No remaining references to the removed Username field

echo "Searching for Token struct field access..."
rg "\.Username" --type go -A 2 -B 2

echo "Searching for Token struct initialization with Username..."
rg "Username.*:" --type go -A 2 -B 2
cli/main.go (1)

19-19: Verify function rename consistency across codebase.

The function call change from boost.Spark to boost.Ignite looks correct, but ensure this rename is applied consistently throughout the entire codebase.

#!/bin/bash
# Description: Verify all occurrences of boost.Spark have been updated to boost.Ignite
# Expected: No occurrences of boost.Spark should remain

# Search for any remaining boost.Spark calls
rg "boost\.Spark" --type go
database/seeder/main.go (2)

16-16: LGTM on function rename.

The change from boost.Spark to boost.Ignite is consistent with the broader refactoring.


33-33: Good stylistic consistency improvements.

The standardization of "DB" to "db" in comments and log messages improves consistency across the codebase.

Also applies to: 37-37, 117-117

storage/fixture/talks.json (1)

1-36: Well-structured fixture data with minor validation suggestions.

The JSON structure is clean and consistent. Consider validating the following:

  1. UUID format - All UUIDs appear properly formatted but should be verified
  2. URL accessibility - The engineers.sg URLs should be validated for availability
  3. Date consistency - Dates follow YYYY-MM-DD format consistently
#!/bin/bash
# Description: Validate the fixture data format and accessibility
# Expected: Valid UUIDs, accessible URLs, proper JSON structure

# Validate JSON structure
echo "Validating JSON structure..."
cat storage/fixture/talks.json | jq . > /dev/null && echo "✓ Valid JSON" || echo "✗ Invalid JSON"

# Check UUID format (basic pattern check)
echo "Checking UUID formats..."
cat storage/fixture/talks.json | jq -r '.data[].uuid' | grep -E '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' | wc -l

# Test URL accessibility (first URL only to avoid heavy operations)
echo "Testing first URL accessibility..."
curl -s --head "$(cat storage/fixture/talks.json | jq -r '.data[0].url')" | head -1
storage/fixture/social.json (1)

1-41: ```shell
#!/bin/bash

Test all URLs for reachability

echo "Testing all URLs in social.json..."
cat storage/fixture/social.json | jq -r '.data[].url' | while read url; do
echo "Testing: $url"
curl -s --head --max-time 5 "$url" | head -1
done


</details>
<details>
<summary>pkg/http/message.go (1)</summary>

`8-13`: **Clean implementation of internal error helper function.**

The function correctly formats error messages and uses the appropriate HTTP status code. The import aliasing prevents naming conflicts with the local `http` package.




```shell
#!/bin/bash
# Description: Verify ApiError type definition and usage patterns
# Expected: ApiError struct should be defined, function should be used consistently

# Find ApiError struct definition
echo "Searching for ApiError type definition..."
ast-grep --pattern 'type ApiError struct {
  $$$
}'

# Check usage patterns of InternalError function
echo "Checking InternalError usage patterns..."
rg "InternalError" --type go -A 2 -B 1
pkg/http/middleware/pipeline.go (1)

12-21: LGTM! Clean middleware pipeline implementation.

The middleware chaining logic is correct, with clear documentation explaining the reverse order application. The implementation follows Go best practices.

pkg/http/handler.go (1)

9-27: Good error handling pattern.

The handler wrapper provides consistent JSON error responses and proper HTTP status codes. The JSON encoding error handling is well implemented.

boost/factory.go (2)

53-53: Good consistency improvement in error messages.

The capitalization changes improve consistency in error message formatting across the factory functions.

Also applies to: 117-117


64-67: LGTM! Token simplification aligns with refactor.

The removal of the Username field from the token initialization is consistent with the broader authentication refactor mentioned in the summary.

storage/fixture/experience.json (1)

10-11: Verify future end date.

The end date "April, 2025" appears to be in the future. Ensure this is intentional and not a typo.

handler/social.go (2)

14-18: LGTM: Clean constructor pattern

The constructor function follows a consistent pattern with other handlers in the system. The hardcoded path approach is appropriate for fixture-based data serving.


20-34: LGTM: Solid error handling pattern

The Handle method demonstrates good error handling practices:

  • Proper file reading with error checking
  • Structured API error responses
  • Consistent return pattern with nil indicating success
  • Integration with the writeJSON helper for response handling
handler/profile.go (2)

14-18: LGTM: Consistent handler pattern

The constructor follows the same clean pattern established across all fixture handlers, maintaining consistency in the codebase architecture.


20-34: LGTM: Consistent error handling implementation

The Handle method maintains the same robust error handling pattern established in other handlers, ensuring consistent API behavior across all endpoints.

pkg/http/schema.go (3)

5-13: LGTM: Well-designed error response types

The separation between ErrorResponse for JSON serialization and ApiError for internal error handling is well thought out. The struct field tags ensure proper JSON marshaling.


15-21: LGTM: Robust error interface implementation

The Error() method includes proper nil safety checks, preventing potential panics when dealing with nil ApiError pointers. The fallback to "Internal Server Error" is appropriate.


23-25: LGTM: Clean function type definitions

The ApiHandler and Middleware function types establish a clear contract for the HTTP layer, enabling clean middleware composition and error handling throughout the system.

boost/helpers.go (1)

23-29: LGTM: Clean getter methods

The getter methods provide appropriate access to private App fields while maintaining encapsulation.

boost/router.go (3)

11-15: LGTM: Well-structured Router design

The Router struct encapsulates the necessary dependencies (environment, mux, pipeline) for handling route registration and middleware composition.


17-29: LGTM: Solid middleware pipeline composition

The PipelineFor method properly composes the middleware chain with token authentication and username validation. The pipeline order (username check, then token check) is logical for authentication flow.


38-38: Verify API path consistency

The route paths don't include the /api prefix mentioned in the AI summary. Please confirm if these should be /api/profile, /api/experience, etc., or if the current paths are intentional.

#!/bin/bash
# Description: Check if other files reference these routes with /api prefix
# Expected: Find references to confirm the correct path pattern

rg -A 2 -B 2 "/api/(profile|experience|projects|social|talks)" --type go

Also applies to: 48-48, 58-58, 68-68, 78-78

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: 0

♻️ Duplicate comments (1)
boost/app.go (1)

21-41: Add error handling for component initialization.

The initialization functions MakeLogs, MakeSentry, and MakeDbConnection could potentially fail, but their errors are not being handled. This could lead to runtime panics.

🧹 Nitpick comments (1)
boost/app.go (1)

43-55: Consider calling router methods directly on the pointer.

While the nil check is good, you can avoid dereferencing the router pointer by calling methods directly:

 func (a *App) Boot() {
 	if a.router == nil {
 		panic("Router is not set")
 	}
-
-	router := *a.router
-
-	router.Profile()
-	router.Experience()
-	router.Projects()
-	router.Social()
-	router.Talks()
+	
+	a.router.Profile()
+	a.router.Experience()
+	a.router.Projects()
+	a.router.Social()
+	a.router.Talks()

This is more idiomatic Go and avoids unnecessary dereferencing.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between baf3d5d and d36cb4b.

📒 Files selected for processing (11)
  • boost/app.go (1 hunks)
  • boost/helpers.go (1 hunks)
  • handler/experience.go (1 hunks)
  • handler/profile.go (1 hunks)
  • handler/projects.go (1 hunks)
  • handler/social.go (1 hunks)
  • handler/talks.go (1 hunks)
  • pkg/http/handler.go (1 hunks)
  • pkg/http/middleware/token.go (1 hunks)
  • pkg/http/middleware/username.go (1 hunks)
  • storage/fixture/projects.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • storage/fixture/projects.json
  • pkg/http/handler.go
  • pkg/http/middleware/username.go
  • handler/social.go
  • handler/experience.go
  • handler/projects.go
  • handler/profile.go
  • handler/talks.go
  • pkg/http/middleware/token.go
  • boost/helpers.go
🔇 Additional comments (2)
boost/app.go (2)

7-7: LGTM! Imports are appropriate for the new functionality.

The added imports for middleware and net/http are necessary for the middleware pipeline and HTTP multiplexer setup.

Also applies to: 9-9


13-18: Excellent encapsulation with private fields.

Converting all struct fields to private provides better encapsulation and controlled access to the App's internal components.

@gocanto gocanto merged commit f2c96c2 into main Jun 23, 2025
2 checks passed
@gocanto gocanto deleted the feature/add-fixtures branch June 23, 2025 07:41
@coderabbitai coderabbitai bot mentioned this pull request Jul 22, 2025
@coderabbitai coderabbitai bot mentioned this pull request Sep 24, 2025
3 tasks
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