refactor: adopt portigo infrastructure patterns

Add config package with build-tag-switched dev/prod environments,
structured logging via zerolog, Taskfile for dev workflow, golangci-lint
config, testutil package, and improved DB setup with proper SQLite
pragmas and cleanup. Rename sqlc output package from gen to repository.

Switch to allowlist .gitignore, Alpine+UPX+scratch Dockerfile, and
CI pipeline with test/lint gates before deploy.
This commit is contained in:
Ryan Hamamura
2026-03-02 11:48:47 -10:00
parent 6d4f3eb821
commit 2df20c2840
27 changed files with 694 additions and 143 deletions

52
main.go
View File

@@ -8,20 +8,20 @@ import (
"encoding/hex"
"encoding/json"
"io/fs"
"log"
"os"
"sync"
"time"
"github.com/google/uuid"
"github.com/joho/godotenv"
"github.com/ryanhamamura/c4/auth"
"github.com/ryanhamamura/c4/config"
"github.com/ryanhamamura/c4/db"
"github.com/ryanhamamura/c4/db/gen"
"github.com/ryanhamamura/c4/db/repository"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/c4/logging"
"github.com/ryanhamamura/c4/snake"
"github.com/ryanhamamura/c4/ui"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
"github.com/ryanhamamura/via"
"github.com/ryanhamamura/via/h"
)
@@ -29,7 +29,7 @@ import (
var (
store = game.NewGameStore()
snakeStore = snake.NewSnakeStore()
queries *gen.Queries
queries *repository.Queries
chatPersister *db.ChatPersister
)
@@ -43,39 +43,35 @@ func DaisyUIPlugin(v *via.V) {
v.AppendToHead(h.Link(h.Rel("stylesheet"), h.Href("/assets/css/output.css?v="+version)))
}
func port() string {
if p := os.Getenv("PORT"); p != "" {
return p
}
return "7331"
}
func main() {
_ = godotenv.Load()
cfg := config.Global
logger := logging.SetupLogger(cfg.Environment, cfg.LogLevel)
if err := os.MkdirAll("data", 0o755); err != nil {
log.Fatal(err)
cleanupDB, err := db.Init(cfg.DBPath)
if err != nil {
log.Fatal().Err(err).Msg("initializing database")
}
if err := db.Init("data/c4.db"); err != nil {
log.Fatal(err)
}
queries = gen.New(db.DB)
defer cleanupDB()
queries = repository.New(db.DB)
store.SetPersister(db.NewGamePersister(queries))
snakeStore.SetPersister(db.NewSnakePersister(queries))
chatPersister = db.NewChatPersister(queries)
sessionManager, err := via.NewSQLiteSessionManager(db.DB)
if err != nil {
log.Fatal(err)
log.Fatal().Err(err).Msg("creating session manager")
}
_ = logger
v := via.New()
v.Config(via.Options{
LogLevel: via.LogLevelDebug,
DocumentTitle: "Game Lobby",
ServerAddress: ":" + port(),
SessionManager: sessionManager,
Plugins: []via.Plugin{DaisyUIPlugin},
LogLevel: via.LogLevelDebug,
DocumentTitle: "Game Lobby",
ServerAddress: ":" + cfg.Port,
SessionManager: sessionManager,
Plugins: []via.Plugin{DaisyUIPlugin},
})
subFS, _ := fs.Sub(assets, "assets")
@@ -315,7 +311,7 @@ func main() {
ctx := context.Background()
id := uuid.New().String()
user, err := queries.CreateUser(ctx, gen.CreateUserParams{
user, err := queries.CreateUser(ctx, repository.CreateUserParams{
ID: id,
Username: username.String(),
PasswordHash: hash,