тестовый го бэкэнд

This commit is contained in:
Artem Tsyrulnikov
2026-03-27 00:18:42 +03:00
parent 9edb9d6aca
commit 730d453371
7 changed files with 1314 additions and 0 deletions

121
backend/main.go Normal file
View File

@@ -0,0 +1,121 @@
package main
import (
"embed"
"flag"
"fmt"
"io/fs"
"log"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
//go:embed dist/*
var distFS embed.FS
func main() {
port := flag.Int("port", 1111, "port to listen on")
flag.Parse()
dsn := "host=localhost user=user password=pass dbname=app port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}
db.AutoMigrate(
&Template{}, &File{}, &Sheet{}, &Attribute{}, &TemplateAttribute{},
&Standard{}, &Group{}, &Laboratory{}, &ConditionType{}, &DailyCondition{},
)
r := gin.Default()
// API routes under /api/
api := r.Group("/api")
registerRoutesOnGroup(api, db)
// SPA: embedded frontend
distSub, err := fs.Sub(distFS, "dist")
if err != nil {
log.Fatalf("failed to open embedded dist: %v", err)
}
fileServer := http.FileServer(http.FS(distSub))
r.NoRoute(func(c *gin.Context) {
c.Header("Cache-Control", "no-store")
path := strings.TrimPrefix(c.Request.URL.Path, "/")
if path == "" {
path = "index.html"
}
// Serve static file if exists
if f, err := distSub.Open(path); err == nil {
f.Close()
fileServer.ServeHTTP(c.Writer, c.Request)
return
}
// SPA fallback
indexFile, err := fs.ReadFile(distSub, "index.html")
if err != nil {
c.String(500, "index.html not found")
return
}
c.Data(200, "text/html; charset=utf-8", indexFile)
})
addr := fmt.Sprintf(":%d", *port)
log.Printf("Serving on http://localhost%s", addr)
r.Run(addr)
}
func registerRoutesOnGroup(api *gin.RouterGroup, db *gorm.DB) {
api.GET("/templates/", func(c *gin.Context) { getTemplates(c, db) })
api.GET("/templates/:id", func(c *gin.Context) { getTemplate(c, db) })
api.POST("/templates/", func(c *gin.Context) { createTemplate(c, db) })
api.PATCH("/templates/:id", func(c *gin.Context) { patchTemplate(c, db) })
api.DELETE("/templates/:id", func(c *gin.Context) { deleteTemplate(c, db) })
api.POST("/templates/copy", func(c *gin.Context) { copyTemplate(c, db) })
api.GET("/files/", func(c *gin.Context) { getFiles(c, db) })
api.GET("/files/:id", func(c *gin.Context) { getFile(c, db) })
api.POST("/files/upload", func(c *gin.Context) { uploadFile(c, db) })
api.GET("/sheets/", func(c *gin.Context) { getSheets(c, db) })
api.GET("/sheets/:id", func(c *gin.Context) { getSheet(c, db) })
api.POST("/sheets/", func(c *gin.Context) { createSheet(c, db) })
api.PATCH("/sheets/:id", func(c *gin.Context) { patchSheet(c, db) })
api.GET("/attributes/", func(c *gin.Context) { getAttributes(c, db) })
api.POST("/attributes/", func(c *gin.Context) { createAttribute(c, db) })
api.GET("/attributes/:id/values", func(c *gin.Context) { getAttributeValues(c, db) })
api.GET("/standards/", func(c *gin.Context) { getStandards(c, db) })
api.GET("/standards/:id", func(c *gin.Context) { getStandard(c, db) })
api.POST("/standards/", func(c *gin.Context) { createStandard(c, db) })
api.PATCH("/standards/:id", func(c *gin.Context) { patchStandard(c, db) })
api.DELETE("/standards/:id", func(c *gin.Context) { deleteStandard(c, db) })
api.GET("/laboratories/", func(c *gin.Context) { getLaboratories(c, db) })
api.GET("/laboratories/:id", func(c *gin.Context) { getLaboratory(c, db) })
api.GET("/daily-conditions/", func(c *gin.Context) { getDailyConditions(c, db) })
api.GET("/daily-conditions/:id", func(c *gin.Context) { getDailyCondition(c, db) })
api.POST("/daily-conditions/", func(c *gin.Context) { createDailyCondition(c, db) })
api.PATCH("/daily-conditions/:id", func(c *gin.Context) { updateDailyCondition(c, db) })
api.DELETE("/daily-conditions/:id", func(c *gin.Context) { deleteDailyCondition(c, db) })
api.GET("/groups/", func(c *gin.Context) { getGroups(c, db) })
api.GET("/groups/:id", func(c *gin.Context) { getGroup(c, db) })
api.POST("/groups/", func(c *gin.Context) { createGroup(c, db) })
api.PATCH("/groups/:id", func(c *gin.Context) { patchGroup(c, db) })
api.DELETE("/groups/:id", func(c *gin.Context) { deleteGroup(c, db) })
api.POST("/protocols/", func(c *gin.Context) { createProtocol(c, db) })
}