Server Guidelinesο
0. Generalο
Project Context:
This project follows a microservices architecture using Go (Golang) as the primary backend language. Please adhere to Go best practices, the projectβs architectural patterns, and the conventions described in the Architecture Documentation.
Shared Code:
Utilities shared between microservices should be implemented in the Prompt SDK.
1. Naming Conventionsο
PascalCase should be used for:
Exported types, structs, and interfaces (e.g.,
CourseService
)Exported functions and methods (e.g.,
CreateCourse
)Package-level constants (e.g.,
MaxRetryAttempts
)
camelCase should be used for:
Unexported (private) functions and methods (e.g.,
setupRouter
)Local variables and function parameters (e.g.,
courseID
)Struct fields that are not exported
Unexported constants (e.g.,
maxRetryAttempts
)
snake_case should be used for:
Database column names and table names
Use descriptive names that clearly indicate the purpose. For example:
Service files should be suffixed with
Service
(e.g.,CourseService
)DTO files should be clearly named for their purpose (e.g.,
CreateCourseRequest
)
2. Folder Structureο
Each microservice follows a consistent modular structure. For each module/component, use the following folder organization:
servers/
βββ assessment/ -- Core server (main application)
β βββ module/ -- Course management module
β β βββ moduleDTO/ -- Contains Data Transfer Objects for API requests/responses
β β βββ submodule/ -- Sub-module (in this case for course participation)
β β βββ main.go -- Setup module and middleware, initialize service as singletons
β β βββ router.go -- HTTP endpoint definitions and middleware setup
β β βββ router_test.go -- Router tests
β β βββ service.go -- Core business logic using standalone functions with singleton dependencies
β β βββ service_test.go -- Service tests for standalone functions
β β βββ validation.go -- Input validation logic
β β βββ validation_test.go -- Validation tests
β βββ db/ -- Database layer
β β βββ migration/ -- SQL migration files
β β βββ query/ -- SQL query files (for SQLC)
β β βββ sqlc/ -- SQLC auto-generated database code
β βββ utils/ -- Shared utilities
β βββ testutils/ -- Test utilities
β βββ docs/ -- Swagger documentation
β βββ main.go -- Server entry point
β βββ go.mod -- Go module dependencies
β βββ sqlc.yaml -- SQLC configuration
βββ [other microservices]
Architectural Pattern Note:
Services in this project use standalone functions rather than methods on service structs. Dependencies (database connections, queries, etc.) are initialized as singletons in main.go
and passed to functions as needed. This pattern promotes simplicity, testability, and consistency across the codebase.
3. Dependency Managementο
3.1 Common Dependenciesο
The project uses several standard dependencies across services:
Gin (github.com/gin-gonic/gin) - HTTP web framework
pgx (github.com/jackc/pgx/v5) - PostgreSQL driver
UUID (github.com/google/uuid) - UUID generation
Logrus (github.com/sirupsen/logrus) - Structured logging
Testify (github.com/stretchr/testify) - Testing framework
SQLC (github.com/sqlc-dev/sqlc) - SQL code generation
3.2 Prompt SDKο
Use the internal
Prompt-SDK
(github.com/ls1intum/Prompt-SDK) for:Authentication middleware (Keycloak integration)
Authorization roles and permissions (RBAC)
CORS configuration
Common utilities
Authentication & Authorization:
Use Keycloak for authentication via the
Prompt-SDK
Define role-based access control (RBAC) for all endpoints β more details: Authorization
Use permission validation middleware
Example from assessment server:
// In assessment main.go
func main() {
// ... database setup ...
router := gin.Default()
router.Use(promptSDK.CORSMiddleware(coreHost))
api := router.Group("assessment/api/course_phase/:coursePhaseID")
// Use SDK authentication middleware in router setup
assessments.InitAssessmentModule(api, *query, conn)
}
// In assessment router.go
func setupAssessmentRouter(routerGroup *gin.RouterGroup, authMiddleware func(allowedRoles ...string) gin.HandlerFunc) {
assessmentRouter := routerGroup.Group("/student-assessment")
// Use Prompt-SDK roles for authorization
assessmentRouter.GET("", authMiddleware(promptSDK.PromptAdmin, promptSDK.CourseLecturer, promptSDK.CourseEditor), listAssessmentsByCoursePhase)
}
4. Database Managementο
4.1 Migration Systemο
Use
golang-migrate
for database schema changesPlace migration files in
db/migration/
directoryFollow naming convention:
####_description.up.sql
and####_description.down.sql
Run migrations on service startup
4.2 Query Management with SQLCο
Write SQL queries in
db/query/
directoryUse SQLC to generate type-safe Go code
Generated code goes in
db/sqlc/
directory
Example SQLC configuration:
version: "2"
sql:
- engine: "postgresql"
queries: "db/query/"
schema: "db/migration/"
gen:
go:
package: "db"
sql_package: "pgx/v5"
out: "db/sqlc"
emit_json_tags: true
overrides:
- db_type: "uuid"
go_type:
import: "github.com/google/uuid"
type: "UUID"
5. API Design and Documentationο
5.1 RESTful Conventionsο
Follow REST principles for endpoint design:
Use plural nouns for collections:
/courses
,/assessments
Use specific resource IDs for individual items:
/courses/{courseId}
Use HTTP methods semantically: GET (read), POST (create), PUT (update), DELETE (remove)
All servers must expose routes under
<server>/api/course_phase/:coursePhaseID
to use the Prompt-SDK authentication middleware (e.g.,assessment/api/course_phase/:coursePhaseID
).
5.2 Swagger Documentationο
Use
swaggo/swag
for API documentationAdd Swagger comments to all public endpoints
Include examples and proper status codes in documentation
Generate and serve documentation automatically
5.3 Data Transfer Objects (DTOs)ο
Use DTOs for request and response payloads
Create separate DTOs for different operations if they differ from the main entity (Create, Update, Get)
Use JSON tags for proper serialization
Convert between DTOs and database models explicitly
Example DTO structure:
type CreateCourse struct {
Name string `json:"name" binding:"required"`
StartDate pgtype.Date `json:"startDate" swaggertype:"string"`
EndDate pgtype.Date `json:"endDate" swaggertype:"string"`
RestrictedData meta.MetaData `json:"restrictedData"`
StudentReadableData meta.MetaData `json:"studentReadableData"`
}
// Convert dto to database model
func (c CreateCourse) GetDBModel() (db.CreateCourseParams, error) {/*...*/}
6. Error Handling and Loggingο
6.1 Error Handling Policyο
Use consistent error response format across all services
Log errors with appropriate context using logrus
Return structured
utils.ErrorResponse
for client-facing errorsNever expose internal error details to clients; use generic user-friendly messages
6.2 Logging Levelsο
log.Info("Assessment service started on port 8085")
log.WithField("coursePhaseID", coursePhaseID).Warn("No assessments found for course phase")
log.WithError(err).Error("Database connection failed")