Skip to content
This repository was archived by the owner on Jun 23, 2026. It is now read-only.

Streamlines API Architecture and Enhances Authentication - #45

Merged
FinnTheHero merged 18 commits into
masterfrom
development
Aug 22, 2025
Merged

Streamlines API Architecture and Enhances Authentication#45
FinnTheHero merged 18 commits into
masterfrom
development

Conversation

@FinnTheHero

Copy link
Copy Markdown
Owner

This refactor overhauls the backend project structure and significantly upgrades the authentication system.

  • Architectural Overhaul: Reorganizes packages into more distinct common, database, service, and server layers for improved modularity and clarity.
  • Enhanced JWT Authentication: Implements a robust authentication flow featuring separate access and refresh tokens, alongside an automatic token refresh mechanism to improve security and user experience.
  • Optimized Performance: Integrates in-memory caching for user lookups during token validation, reducing database load and speeding up authentication checks.
  • Improved EPUB Processing: Refines the logic for parsing and organizing chapters from EPUB files, ensuring more accurate content handling.
  • Development Experience & Configuration: Updates development server settings (air.toml) and adds dynamic CORS configuration capabilities for increased flexibility.

Restructures core API directories and packages for improved organization and clarity.

Upgrades the JWT authentication system to use access and refresh token pairs.
Introduces a flexible JWT middleware with support for user loading, caching, and distinct authentication levels.
Modifies user login to issue and set secure HTTP-only token cookies.
Updates JWT claims to include user ID for more robust session management.
Renames `handlers` to `handler` and `services` to `service` directories and packages for improved consistency.
Removes `firestore_` prefixes from internal package names, simplifying the codebase.
Introduces an in-memory cache for JWT token validation to optimize user lookup performance in authentication middleware.
Decouples the `UserService` dependency from the JWT middleware configuration, relying directly on the `service` layer.
Centralizes JWT claims definition and adds user type field.
Simplifies authentication middleware by removing direct user database lookup, focusing on claims validation.
Introduces a global in-memory token cache for efficient management and blacklisting.
Standardizes access token cookie and header names to `access_token`.
Updates token validation endpoint to return claims data directly.
Increases token cache cleanup interval for improved performance.
@FinnTheHero FinnTheHero self-assigned this Aug 22, 2025
@FinnTheHero FinnTheHero added the enhancement New feature or request label Aug 22, 2025
@FinnTheHero
FinnTheHero requested a review from Copilot August 22, 2025 19:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This refactor modernizes the API architecture by reorganizing the codebase into cleaner layers and implementing a comprehensive JWT authentication system with access and refresh tokens. The changes improve security, maintainability, and development experience.

  • Restructures packages from internal/usecases and internal/infrastructure to distinct service, database, and server layers
  • Implements enhanced JWT authentication with separate access/refresh tokens and automatic token refresh middleware
  • Adds in-memory caching for user lookups during authentication to reduce database load

Reviewed Changes

Copilot reviewed 31 out of 35 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
api/internal/service/*.go Moved service logic from usecases package with updated import paths
api/internal/server/middleware/token/*.go New comprehensive JWT token management system with caching and refresh capabilities
api/internal/server/handler/*.go Updated handlers to use new service layer and token system
api/internal/server/routes.go New centralized route configuration with improved middleware setup
api/internal/domain/token.go New domain models for token configuration and caching interfaces
api/common/*.go Moved common utilities from internal package with new domain parsing function

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

if err != nil {
return err
// Split chapters by priority
// Chpaters with chpater in title take priority

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

Typo in comment: 'Chpaters' should be 'Chapters' and 'chpater' should be 'chapter'

Suggested change
// Chpaters with chpater in title take priority
// Chapters with chapter in title take priority

Copilot uses AI. Check for mistakes.
return err
// Split chapters by priority
// Chpaters with chpater in title take priority
// Notes, Synopsys and everything else will be processes last

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

Typo in comment: 'Synopsys' should be 'Synopsis' and 'processes' should be 'processed'

Suggested change
// Notes, Synopsys and everything else will be processes last
// Notes, Synopsis and everything else will be processed last

Copilot uses AI. Check for mistakes.
}

// Cache user if cache is available
cacheKey := fmt.Sprintf("user:%s", claims.ID)

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

Using claims.ID instead of claims.Subject. The refresh token only contains Subject (user ID) in RegisteredClaims, not an ID field

Suggested change
cacheKey := fmt.Sprintf("user:%s", claims.ID)
user, err := service.GetUserByID(claims.Subject, ctx)
if err != nil {
return "", err
}
// Cache user if cache is available
cacheKey := fmt.Sprintf("user:%s", claims.Subject)

Copilot uses AI. Check for mistakes.
Comment thread api/common/env.go
func GetDomains(v string) []string {
env_variable := os.Getenv(v)
if env_variable == "" {
log.Fatal(&Error{Err: errors.New("Environmental Variable " + v + " Not Found"), Status: http.StatusNotFound})

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

log.Fatal will terminate the program immediately, but the Error struct with Status field suggests this should return an error instead of calling log.Fatal

Copilot uses AI. Check for mistakes.
Comment thread api/common/env.go

result := strings.Split(env_variable, ",")

return result

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

The function will never reach this return statement if the environment variable is empty due to log.Fatal being called above

Copilot uses AI. Check for mistakes.
Comment thread api/internal/server/routes.go Outdated
func RegisteredRoutes(r *gin.Engine) {
domains := cmn.GetDomains("DOMAIN")
if gin.Mode() == gin.DebugMode && len(domains) == 0 {
domains[0] = "*"

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

Attempting to assign to index 0 of an empty slice will cause a panic. Should use domains = []string{"*"} instead

Suggested change
domains[0] = "*"
domains = []string{"*"}

Copilot uses AI. Check for mistakes.
}

// Cache user if cache is available
cacheKey := fmt.Sprintf("user:%s", claims.ID)

Copilot AI Aug 22, 2025

Copy link

Choose a reason for hiding this comment

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

Using claims.ID which doesn't exist in RegisteredClaims. Should use claims.Subject instead

Suggested change
cacheKey := fmt.Sprintf("user:%s", claims.ID)
user, err := service.GetUserByID(claims.Subject, ctx)
if err != nil {
return "", err
}
// Cache user if cache is available
cacheKey := fmt.Sprintf("user:%s", claims.Subject)

Copilot uses AI. Check for mistakes.
@FinnTheHero
FinnTheHero merged commit ab0977f into master Aug 22, 2025
2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants