Skip to content

Project Structure ​

Go backend directory organization.

Directory Layout ​

sis_backendgo/
├── cmd/
│   ├── api/
│   │   └── main.go              # Application entry point
│   ├── migrate-static/          # Static data migration tool
│   ├── migrate-daily/           # Daily data migration tool
│   ├── migrate-requirements/    # Requirements migration tool
│   ├── inspect-requirements/    # Requirements inspection tool
│   └── seed-data/               # Database seeding tool
├── internal/
│   ├── config/
│   │   └── config.go            # Environment configuration
│   ├── domain/                  # Business domains (20 modules)
│   │   ├── academic/
│   │   ├── audit/
│   │   ├── authentication/
│   │   ├── authorization/
│   │   ├── billing/
│   │   ├── communications/
│   │   ├── core/
│   │   ├── financialaid/
│   │   ├── formbuilder/
│   │   ├── grading/
│   │   ├── organization/
│   │   ├── people/
│   │   ├── proxy/
│   │   ├── registration/
│   │   ├── reporting/
│   │   ├── roles/
│   │   ├── sso/
│   │   ├── testscores/
│   │   ├── workflow/
│   │   └── workflowengine/
│   ├── lmsintegration/          # LMS connectors, engine, export (NOT under domain/)
│   ├── middleware/              # HTTP middleware
│   │   ├── auth.go              # Session-based authentication
│   │   ├── bodylimit.go         # Request body size limit
│   │   ├── chain.go             # Middleware chaining
│   │   ├── cors.go              # CORS handling
│   │   ├── csrf.go              # CSRF token validation
│   │   ├── impersonation_audit.go # Impersonation audit logging
│   │   ├── locale.go            # Accept-Language parsing
│   │   ├── logging.go           # Request logging
│   │   ├── ratelimit.go         # Rate limiting
│   │   ├── security_headers.go  # Security response headers
│   │   └── stdlib.go            # Standard middleware (RequestID, RealIP, Recoverer)
│   ├── router/
│   │   └── router.go            # Route registration
│   └── shared/                  # Shared utilities
│       ├── audit/               # Audit logging helpers
│       ├── auth/                # Session service, password hashing
│       ├── credits/             # Credit conversion utilities
│       ├── db/                  # Database utilities
│       ├── email/               # SMTP email service
│       ├── errors/              # Error types & constructors
│       ├── response/            # HTTP response helpers
│       └── validator/           # Input validation
├── migrations/                  # Go-specific migration scripts
├── go.mod                       # Go module definition
├── go.sum                       # Dependency checksums
└── .env                         # Environment variables

Domain Module Structure ​

Each domain follows a consistent 6-file structure:

internal/domain/{name}/
├── model.go       # Database entity structs with db tags
├── dto.go         # Request/Response DTOs with validation
├── repository.go  # Data access layer (SQL queries)
├── service.go     # Business logic layer
├── handler.go     # HTTP request handlers
└── routes.go      # Route registration function

Complex Domains ​

Some domains have additional files for subresources or complex logic:

internal/domain/academic/
├── model.go
├── dto.go
├── repository.go
├── service.go
├── service_junction.go           # Junction table logic (e.g. course-requisites)
├── handler.go
└── routes.go

internal/domain/billing/
├── model.go
├── dto.go
├── repository.go
├── service.go
├── service_subresources.go       # Complex subresource logic
├── handler.go
├── handler_subresources.go       # Subresource handlers
└── routes.go

Key Directories ​

cmd/api/ ​

Application entry point:

go
// main.go
func main() {
    // Load configuration
    cfg, _ := config.Load()

    // Initialize logger
    logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

    // Connect to database (lib/pq via database/sql)
    database, _ := sql.Open("postgres", cfg.DSN())

    // Connect to Valkey/Redis for sessions
    sessionService := auth.NewSessionService(redisClient, cfg)

    // Create router with all dependencies
    deps := &router.Deps{
        Config:         cfg,
        Logger:         logger,
        DB:             database,
        SessionService: sessionService,
        // ...
    }
    handler := router.New(deps)

    // Start server
    http.ListenAndServe(":8000", handler)
}

internal/config/ ​

Environment configuration:

go
type Config struct {
    // Server
    ServerPort  string
    ServerHost  string
    Environment string

    // Database (PostgreSQL via lib/pq)
    DBHost     string
    DBPort     string
    DBUser     string
    DBPassword string
    DBName     string
    DBSSLMode  string
    DBMaxConns int

    // Redis/Valkey (sessions)
    RedisURL      string
    RedisPassword string
    RedisDB       int

    // Sessions
    SessionTTL              time.Duration
    SessionSlidingExpiration bool

    // CORS
    CORSAllowedOrigins   []string
    CORSAllowCredentials bool

    // Cookies
    CookieDomain string
    CookiePath   string
    CookieSecure bool

    // Photo Storage
    PhotoStoragePath string
    PhotoMaxSizeMB   int

    // Email
    SMTPHost     string
    SMTPPort     int
    SMTPFrom     string
    SMTPUseTLS   bool
}

func Load() (*Config, error) {
    // Load from .env file and environment variables
}

internal/middleware/ ​

HTTP middleware chain:

FilePurpose
auth.goSession-based authentication (reads sis_session cookie, validates via Valkey)
bodylimit.goRequest body size limit (1 MB default)
chain.goMiddleware composition
cors.goCORS headers
csrf.goCSRF token validation for mutating requests
impersonation_audit.goAudit logging for impersonated actions
locale.goAccept-Language header parsing for i18n
logging.goRequest/response logging
ratelimit.goRate limiting for public endpoints
security_headers.goSecurity response headers
stdlib.goStandard middleware (RequestID, RealIP, Recoverer)

internal/shared/ ​

Shared utilities:

DirectoryPurpose
audit/Audit logging helpers
auth/Session service (Valkey), password hashing, cookie management
credits/Credit conversion utilities
db/Query builder, row scanner, pagination, transactions
email/SMTP email service
errors/Custom error types and constructors
response/HTTP JSON response helpers
validator/Input validation utilities

internal/router/ ​

Central route registration. All 20 domain packages register their routes here:

go
func New(deps *Deps) http.Handler {
    mux := http.NewServeMux()

    // Session-based auth middleware
    authMw := middleware.Auth(sessionValidator)
    csrfMw := middleware.CSRF()
    impersonationAuditMw := middleware.ImpersonationAudit(deps.DB)
    protect := func(handler http.HandlerFunc) http.HandlerFunc {
        return middleware.WithMiddleware(authMw,
            middleware.WithMiddleware(csrfMw,
                middleware.WithMiddleware(impersonationAuditMw, handler)))
    }

    // Register domain routes
    core.RegisterRoutes(mux, p, deps.DB, deps.Validator, protect)
    organization.RegisterRoutes(mux, p, deps.DB, deps.Validator, protect)
    people.RegisterRoutes(mux, p, deps.PeopleHandler, protect)
    academic.RegisterRoutes(mux, p, deps.AcademicHandler, protect)
    // ... all 20 domain packages, plus lmsintegration

    // Global middleware stack
    handler := middleware.Chain(normalizedMux,
        middleware.RequestID,
        middleware.RealIP,
        middleware.Locale,
        middleware.Logger(deps.Logger),
        middleware.Recoverer,
        corsMiddleware,
        middleware.SecurityHeaders,
        middleware.BodyLimit(1<<20),
    )

    return handler
}

Frontend Stats ​

The frontend (sis_frontend/) contains:

CategoryCount
Views147 across 18 directories
API services36 service files
Pinia stores10 stores
Reusable components67 components

File Naming Conventions ​

TypePatternExample
Entry pointmain.gocmd/api/main.go
Domain modelmodel.godomain/people/model.go
Domain DTOdto.godomain/people/dto.go
Repositoryrepository.godomain/people/repository.go
Serviceservice.godomain/people/service.go
Handlerhandler.godomain/people/handler.go
Routesroutes.godomain/people/routes.go
Tests*_test.goservice_test.go

Configuration ​

Environment Variables ​

Set via .env file in sis_backendgo/:

bash
# Server
SERVER_PORT=8000
SERVER_HOST=0.0.0.0
ENVIRONMENT=development

# Database (PostgreSQL via lib/pq)
DB_HOST=127.0.0.1
DB_PORT=5433
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=sis
DB_SSLMODE=disable
DB_MAX_CONNS=25

# Valkey/Redis (required for sessions)
REDIS_URL=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0

# Sessions
SESSION_TTL=4h
SESSION_SLIDING_EXPIRATION=true

# CORS
CORS_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
CORS_ALLOW_CREDENTIALS=true

# Cookies
COOKIE_DOMAIN=
COOKIE_PATH=/api
COOKIE_SECURE=false

# Photo Storage
PHOTO_STORAGE_PATH=./photos
PHOTO_MAX_SIZE_MB=2

# Email (Mailpit for development)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_FROM=no-reply@puc.edu
SMTP_USE_TLS=false

Environment Selection ​

Use the ENVIRONMENT variable:

ValueDescription
developmentLocal development (verbose logging, relaxed cookie settings)
productionProduction (minimal logging, secure cookies required)

Student Information System Documentation