now up and running using docker

This commit is contained in:
2025-04-17 15:22:55 +02:00
parent 5337da219e
commit 22b6f3bd2a
10 changed files with 80 additions and 117 deletions

6
.env
View File

@@ -1,7 +1,7 @@
# .env # .env
DB_HOST=mariadb DB_HOST=db
DB_ROOT_PASSWORD=iWO8ME9hlOCTml
DB_USER=api-user DB_USER=api-user
DB_PASSWORD=Pu38tkYv3W9k6S DB_PASSWORD=Pu38tkYv3W9k6S
DB_DATABASE=wagfarm DB_DATABASE=wagfarm
DB_PORT=3306 DB_PORT=5432
GIN_MODE=debug

View File

@@ -1,32 +1,34 @@
services: services:
db: db:
image: mariadb image: postgres:16
container_name: wagfarm-db container_name: wagfarm-db
restart: always
environment: environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} POSTGRES_USER: ${DB_USER}
MYSQL_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_DATABASE}
MYSQL_DATABASE: ${DB_DATABASE}
volumes: volumes:
- ./data/mysql:/var/lib/mysql - pgdata:/var/lib/postgresql/data
# - ./postgres-init:/docker-entrypoint-initdb.d # SQL scripts
networks: networks:
- wagfarm-net - wagfarm-net
healthcheck: healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] test: ["CMD-SHELL", "pg_isready", "-U", "${DB_USER}"]
interval: 5s interval: 10s
timeout: 5s timeout: 5s
retries: 5 retries: 5
start_period: 5s
api: api:
build: ./wagfarm-api build: ./wagfarm-api
container_name: wagfarm-api container_name: wagfarm-api
restart: always
environment: environment:
- DB_HOST=${DB_HOST} - DB_HOST=${DB_HOST}
- DB_PORT=${DB_PORT} - DB_PORT=${DB_PORT}
- DB_USER=${DB_USER} - DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD} - DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_DATABASE} - DB_NAME=${DB_DATABASE}
- GIN_MODE=${GIN_MODE}
ports: ports:
- "8089:8080" - "8089:8080"
depends_on: depends_on:
@@ -34,6 +36,15 @@ services:
condition: service_healthy condition: service_healthy
networks: networks:
- wagfarm-net - wagfarm-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"] # or use the health endpoint of your API
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
networks: networks:
wagfarm-net: wagfarm-net:
volumes:
pgdata:

View File

@@ -1,42 +0,0 @@
CREATE TABLE asset_type (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE asset (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
asset_type_id INT NOT NULL,
FOREIGN KEY (asset_type_id) REFERENCES asset_type(id)
);
CREATE TABLE log_type (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE log (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
log_type_id INT NOT NULL,
date DATE DEFAULT CURRENT_DATE,
FOREIGN KEY (log_type_id) REFERENCES log_type(id)
);
-- Junction table for equipment assets
CREATE TABLE log_equipment_asset (
log_id INT NOT NULL,
asset_id INT NOT NULL,
PRIMARY KEY (log_id, asset_id),
FOREIGN KEY (log_id) REFERENCES log(id) ON DELETE CASCADE,
FOREIGN KEY (asset_id) REFERENCES asset(id) ON DELETE CASCADE
);
-- Junction table for substance assets
CREATE TABLE log_substance_asset (
log_id INT NOT NULL,
asset_id INT NOT NULL,
PRIMARY KEY (log_id, asset_id),
FOREIGN KEY (log_id) REFERENCES log(id) ON DELETE CASCADE,
FOREIGN KEY (asset_id) REFERENCES asset(id) ON DELETE CASCADE
);

View File

@@ -1,32 +1,26 @@
# Use official Golang image # Stage 1: Build the Go binary
FROM golang:1.20-alpine as builder FROM golang:1.21-alpine AS builder
# Set the Current Working Directory inside the container
WORKDIR /app WORKDIR /app
# Copy go mod and sum files # Copy go.mod and go.sum first
COPY go.mod go.sum ./ COPY go.mod go.sum ./
# Download all dependencies. Dependencies will be cached if the go.mod and go.sum are not changed
RUN go mod download RUN go mod download
# Copy the source code into the container # Copy the rest of the code
COPY src src COPY . .
# Build the Go app # Build the Go binary
RUN go build -o main src RUN go build -o wagfarm-api main.go
# Start a new stage from a smaller image # Stage 2: Minimal runtime image
FROM alpine:latest FROM alpine:latest
# Install required libraries WORKDIR /root/
RUN apk --no-cache add ca-certificates
# Copy the pre-built binary file from the builder stage # Copy the binary from the builder
COPY --from=builder /app/main . COPY --from=builder /app/wagfarm-api .
# Expose the API port # Run the binary
EXPOSE 8089 CMD ["./wagfarm-api"]
#CMD ["tail", "-f", "/dev/null"]
# Run the Go app
CMD ["./main"]

View File

@@ -12,16 +12,13 @@ type Fertilizer struct {
FertilizerTypeID uint `gorm:"not null"` FertilizerTypeID uint `gorm:"not null"`
FertilizerType fertilizertype.FertilizerType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` FertilizerType fertilizertype.FertilizerType `gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
// Association to the ingredients. This represents the composition. // Association to the ingredients. This represents the composition.
Ingredients []FertilizerIngredient `gorm:"not null; many2many:fertilizer_ingredient"` Ingredients []ingredient.Ingredient `gorm:"not null; many2many:fertilizer_ingredient"`
} }
type FertilizerIngredient struct { type FertilizerIngredient struct {
FertilizerAssetID uint `gorm:"primaryKey"` // foreign key to the fertilizer assets FertilizerID uint `gorm:"primaryKey"` // foreign key to the fertilizer assets
IngredientID uint `gorm:"primaryKey"` // foreign key to the ingredient IngredientID uint `gorm:"primaryKey"` // foreign key to the ingredient
Amount float64 `gorm:"not null"` // amount of the ingredient Amount float64 `gorm:"not null"` // amount of the ingredient
// Preload the ingredient details if needed.
Ingredient ingredient.Ingredient `gorm:"not null"`
} }
func RegisterModels() { func RegisterModels() {

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"gorm.io/driver/mysql" "gorm.io/driver/postgres"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
) )
@@ -21,11 +21,11 @@ func Connect() error {
dbName := os.Getenv("DB_NAME") dbName := os.Getenv("DB_NAME")
dsn := fmt.Sprintf( dsn := fmt.Sprintf(
"%s:%s@tcp(%s:%s)/%s?parseTime=true", "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
dbUser, dbPassword, dbHost, dbPort, dbName, dbHost, dbPort, dbUser, dbPassword, dbName,
) )
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil { if err != nil {
return fmt.Errorf("failed to connect to database: %w", err) return fmt.Errorf("failed to connect to database: %w", err)
} }

View File

@@ -4,9 +4,9 @@ go 1.20
require ( require (
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
gorm.io/driver/mysql v1.5.7
gorm.io/gorm v1.25.12
github.com/shopspring/decimal v1.4.0 github.com/shopspring/decimal v1.4.0
gorm.io/driver/postgres v1.5.11
gorm.io/gorm v1.25.12
) )
require ( require (
@@ -21,6 +21,10 @@ require (
github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
@@ -35,6 +39,7 @@ require (
golang.org/x/arch v0.8.0 // indirect golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.20.0 // indirect golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.34.1 // indirect

View File

@@ -25,6 +25,14 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -71,6 +79,8 @@ golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
@@ -86,6 +96,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.0/go.mod h1:FFla/fJuCvyTi7rJQd27qlNX2v3L6deTR1GgTjSOLPo= gorm.io/driver/mysql v1.5.0/go.mod h1:FFla/fJuCvyTi7rJQd27qlNX2v3L6deTR1GgTjSOLPo=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=

View File

@@ -17,7 +17,7 @@ type BaseLog struct {
LogType string `gorm:"not null"` LogType string `gorm:"not null"`
Date time.Time `gorm:"not null"` Date time.Time `gorm:"not null"`
Duration float64 `gorm:"not null"` // in hours Duration float64 `gorm:"not null"` // in hours
VisibiltyID uint `gorm:"not null"` VisibilityID uint `gorm:"not null"`
Visibility visibility.Visibility `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"` Visibility visibility.Visibility `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;not null"`
Cost decimal.Decimal `gorm:"not null;type:decimal(10,2);"` // in euro Cost decimal.Decimal `gorm:"not null;type:decimal(10,2);"` // in euro
} }

View File

@@ -11,23 +11,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func initLogging() {
// Ensure the logs directory exists
if err := os.MkdirAll("logs", 0755); err != nil {
log.Fatalf("Failed to create log directory: %v", err)
}
// Open the log file
f, err := os.OpenFile("logs/api.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Failed to open log file: %v", err)
}
// Set log output
log.SetOutput(f)
gin.DefaultWriter = f // capture Gin logs too
}
func RegisterModels() { func RegisterModels() {
assets.RegisterModels() assets.RegisterModels()
logs.RegisterModels() logs.RegisterModels()
@@ -39,11 +22,14 @@ func RegisterRoutes(r *gin.Engine) {
assets.RegisterRoutes(group) assets.RegisterRoutes(group)
logs.RegisterRoutes(group) logs.RegisterRoutes(group)
taxonomy.RegisterRoutes(group) taxonomy.RegisterRoutes(group)
r.GET("/health", func(c *gin.Context) {
c.Status(200)
})
} }
func main() { func main() {
initLogging() log.SetOutput(os.Stdout)
log.Println("Starting API server...") log.Println("Starting API server...")
// connect to database // connect to database