Skip to content

Commit 50f4ddd

Browse files
committed
Fixed init version main.go
1 parent 90e3d5f commit 50f4ddd

3 files changed

Lines changed: 229 additions & 32 deletions

File tree

backend/go.mod

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ require (
1616
github.com/go-playground/validator/v10 v10.26.0 // indirect
1717
github.com/go-sql-driver/mysql v1.8.1 // indirect
1818
github.com/goccy/go-json v0.10.2 // indirect
19+
github.com/golang-migrate/migrate/v4 v4.18.3 // indirect
20+
github.com/hashicorp/errwrap v1.1.0 // indirect
21+
github.com/hashicorp/go-multierror v1.1.1 // indirect
1922
github.com/jinzhu/inflection v1.0.0 // indirect
2023
github.com/jinzhu/now v1.1.5 // indirect
2124
github.com/json-iterator/go v1.1.12 // indirect
@@ -27,12 +30,13 @@ require (
2730
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
2831
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
2932
github.com/ugorji/go/codec v1.2.12 // indirect
33+
go.uber.org/atomic v1.7.0 // indirect
3034
golang.org/x/arch v0.8.0 // indirect
31-
golang.org/x/crypto v0.33.0 // indirect
32-
golang.org/x/net v0.34.0 // indirect
33-
golang.org/x/sys v0.30.0 // indirect
34-
golang.org/x/text v0.22.0 // indirect
35-
google.golang.org/protobuf v1.34.1 // indirect
35+
golang.org/x/crypto v0.36.0 // indirect
36+
golang.org/x/net v0.38.0 // indirect
37+
golang.org/x/sys v0.31.0 // indirect
38+
golang.org/x/text v0.23.0 // indirect
39+
google.golang.org/protobuf v1.34.2 // indirect
3640
gopkg.in/yaml.v3 v3.0.1 // indirect
3741
gorm.io/driver/mysql v1.6.0 // indirect
3842
gorm.io/gorm v1.30.0 // indirect

backend/go.sum

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv
3030
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
3131
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
3232
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
33+
github.com/golang-migrate/migrate/v4 v4.18.3 h1:EYGkoOsvgHHfm5U/naS1RP/6PL/Xv3S4B/swMiAmDLs=
34+
github.com/golang-migrate/migrate/v4 v4.18.3/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
3335
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
36+
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
37+
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
38+
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
39+
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
40+
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
3441
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
3542
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
3643
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -68,31 +75,43 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
6875
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
6976
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
7077
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
78+
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
79+
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
7180
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
7281
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
7382
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
7483
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
7584
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
7685
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
7786
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
87+
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
88+
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
7889
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
7990
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
8091
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
8192
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
93+
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
94+
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
8295
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
8396
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
8497
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
8598
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
8699
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
87100
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
101+
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
102+
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
88103
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
89104
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
90105
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
91106
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
92107
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
93108
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
109+
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
110+
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
94111
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
95112
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
113+
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
114+
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
96115
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
97116
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
98117
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

backend/main.go

Lines changed: 201 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,220 @@
11
package main
22

33
import (
4+
"fmt"
45
"log"
56
"net/http"
7+
"os"
8+
"time"
69

710
"github.com/gin-gonic/gin"
8-
// "gorm.io/driver/mysql" // DB接続時にコメント解除
9-
// "gorm.io/gorm" // DB接続時にコメント解除
11+
"github.com/go-playground/validator/v10"
12+
"github.com/golang-migrate/migrate/v4"
13+
_ "github.com/golang-migrate/migrate/v4/database/mysql" // MySQL driver for migrate
14+
_ "github.com/golang-migrate/migrate/v4/source/file" // File source for migrate
15+
"gorm.io/driver/mysql"
16+
"gorm.io/gorm"
17+
"gorm.io/gorm/logger"
1018
)
1119

12-
// CreateUserInput : ユーザー作成リクエストのバリデーション用構造体
13-
type CreateUserInput struct {
14-
Username string `json:"username" binding:"required,min=3,max=30"`
15-
Email string `json:"email" binding:"required,email"`
20+
// Global Variables
21+
var (
22+
db *gorm.DB
23+
validate *validator.Validate
24+
)
25+
26+
// Models (仮定義: 実際には models/ ディレクトリなどに分離推奨)
27+
// OpenAPIのスキーマに基づいてGORMモデルを定義します。
28+
// 例:
29+
// type Complex struct {
30+
// ID uint `gorm:"primarykey" json:"id"`
31+
// UserID string `json:"user_id" gorm:"type:varchar(36);not null;index"` // UUID
32+
// Content string `json:"content" gorm:"not null" validate:"required"`
33+
// Category string `json:"category" gorm:"not null" validate:"required"`
34+
// CreatedAt time.Time `json:"created_at"`
35+
// UpdatedAt time.Time `json:"updated_at"`
36+
// }
37+
// type Goal struct { ... }
38+
// type Action struct { ... }
39+
40+
// ErrorResponse Helper
41+
type ErrorResponse struct {
42+
Code int `json:"code"`
43+
Message string `json:"message"`
44+
}
45+
46+
// NewErrorResponse Helper
47+
func NewErrorResponse(code int, message string) ErrorResponse {
48+
return ErrorResponse{Code: code, Message: message}
49+
}
50+
51+
// AuthMiddleware provides a simple authentication mechanism for the MVP.
52+
// It checks for an 'X-User-ID' header. If the header is not present,
53+
// it sets a default test user ID. This is a temporary measure and should be
54+
// replaced with a proper token-based authentication system for production.
55+
func AuthMiddleware() gin.HandlerFunc {
56+
return func(c *gin.Context) {
57+
userID := c.GetHeader("X-User-ID")
58+
if userID == "" {
59+
// テスト用のダミーユーザーID (実際の認証基盤実装時に置き換える)
60+
userID = "test-user-uuid-12345"
61+
log.Printf("Warning: X-User-ID header not found, using default test user ID: %s", userID)
62+
}
63+
c.Set("userID", userID)
64+
c.Next()
65+
}
1666
}
1767

68+
// PingHandler handles the health check endpoint.
69+
func PingHandler(c *gin.Context) {
70+
c.JSON(http.StatusOK, gin.H{"message": "pong"})
71+
}
72+
73+
// Complex Handlers (スタブ)
74+
// func CreateComplexHandler(c *gin.Context) { /* ... */ }
75+
// func GetComplexesHandler(c *gin.Context) { /* ... */ }
76+
// func GetComplexHandler(c *gin.Context) { /* ... */ }
77+
// func UpdateComplexHandler(c *gin.Context) { /* ... */ }
78+
// func DeleteComplexHandler(c *gin.Context) { /* ... */ }
79+
80+
// Goal Handlers (スタブ)
81+
// func CreateGoalHandler(c *gin.Context) { /* ... */ }
82+
// func GetGoalsHandler(c *gin.Context) { /* ... */ }
83+
// func GetGoalHandler(c *gin.Context) { /* ... */ }
84+
// func UpdateGoalHandler(c *gin.Context) { /* ... */ }
85+
// func DeleteGoalHandler(c *gin.Context) { /* ... */ }
86+
87+
// Action Handlers (スタブ)
88+
// func CreateActionHandler(c *gin.Context) { /* ... */ }
89+
1890
func main() {
19-
// データベース接続 (後で設定)
20-
// dsn := "user:pass@tcp(db:3306)/refuel_db?charset=utf8mb4&parseTime=True&loc=Local"
21-
// _, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
22-
// if err != nil {
23-
// log.Fatalf("Failed to connect to database: %v", err)
24-
// }
25-
// log.Println("Database connected")
91+
// --- 環境変数からの設定読み込み (例) ---
92+
dbUser := os.Getenv("DB_USER")
93+
dbPassword := os.Getenv("DB_PASSWORD")
94+
dbHost := os.Getenv("DB_HOST")
95+
dbPort := os.Getenv("DB_PORT")
96+
dbName := os.Getenv("DB_NAME")
97+
migrationPath := os.Getenv("MIGRATION_PATH") // e.g., "file://./db/migrations"
98+
serverPort := os.Getenv("SERVER_PORT")
99+
if serverPort == "" {
100+
serverPort = "8080" // デフォルトポート
101+
}
26102

27-
r := gin.Default()
103+
// 必須環境変数のチェック
104+
requiredEnvVars := map[string]string{
105+
"DB_USER": dbUser,
106+
"DB_PASSWORD": dbPassword,
107+
"DB_HOST": dbHost,
108+
"DB_PORT": dbPort,
109+
"DB_NAME": dbName,
110+
}
111+
for key, value := range requiredEnvVars {
112+
if value == "" {
113+
log.Fatalf("🚨 Missing required environment variable: %s", key)
114+
}
115+
}
116+
117+
// --- Validatorの初期化 ---
118+
validate = validator.New()
119+
120+
// --- データベース接続 (GORM) ---
121+
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
122+
dbUser, dbPassword, dbHost, dbPort, dbName,
123+
)
124+
125+
gormLogger := logger.New(
126+
log.New(os.Stdout, "\r\n", log.LstdFlags),
127+
logger.Config{
128+
SlowThreshold: time.Second,
129+
LogLevel: logger.Info, // 開発中はInfo, 本番ではWarnなど
130+
IgnoreRecordNotFoundError: true,
131+
Colorful: true,
132+
},
133+
)
28134

29-
r.GET("/ping", func(c *gin.Context) {
30-
c.JSON(http.StatusOK, gin.H{"message": "pong from backend"})
135+
var err error
136+
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
137+
Logger: gormLogger,
31138
})
139+
if err != nil {
140+
log.Fatalf("🚨 Failed to connect to database: %v", err)
141+
}
142+
log.Println("🎉 Database connected successfully!")
32143

33-
r.POST("/users", func(c *gin.Context) {
34-
var input CreateUserInput
35-
if err := c.ShouldBindJSON(&input); err != nil {
36-
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
37-
return
144+
// --- データベースマイグレーション (golang-migrate/migrate) ---
145+
if migrationPath != "" {
146+
dbURL := fmt.Sprintf("mysql://%s:%s@tcp(%s:%s)/%s",
147+
dbUser, dbPassword, dbHost, dbPort, dbName,
148+
)
149+
m, err := migrate.New(migrationPath, dbURL)
150+
if err != nil { // マイグレーションの初期化失敗は致命的エラーとする場合
151+
log.Fatalf("🚨 Failed to initialize migrations: %v.", err)
38152
}
39-
c.JSON(http.StatusOK, gin.H{"message": "User created (simulated)", "user": input})
40-
})
153+
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
154+
log.Fatalf("🚨 Failed to run migrations: %v", err)
155+
}
156+
log.Println("🎉 Migrations applied successfully or no changes.")
157+
srcErr, dbErr := m.Close()
158+
if srcErr != nil {
159+
log.Printf("⚠️ Error closing migration source: %v", srcErr)
160+
}
161+
if dbErr != nil {
162+
log.Printf("⚠️ Error closing migration database connection: %v", dbErr)
163+
}
164+
} else {
165+
log.Println("ℹ️ MIGRATION_PATH not set, skipping automated migrations. Ensure DB schema is up to date.")
166+
// 開発初期段階ではGORMのAutoMigrateも便利です
167+
// log.Println("Running GORM AutoMigrate for initial schema setup...")
168+
// db.AutoMigrate(&Complex{}, &Goal{}, &Action{}) // ここにモデルを追加
169+
}
41170

42-
log.Println("Backend server starting on port 8080")
43-
if err := r.Run(":8080"); err != nil {
44-
log.Fatalf("Failed to run server: %v", err)
171+
// --- Ginルーターの初期化 ---
172+
// gin.SetMode(gin.ReleaseMode) // 本番環境ではReleaseModeに
173+
r := gin.Default()
174+
175+
// --- ミドルウェア ---
176+
r.Use(gin.Logger()) // 標準のロガー
177+
r.Use(gin.Recovery()) // パニックリカバリ
178+
// CORS設定 (必要に応じてカスタマイズ)
179+
// r.Use(cors.Default())
180+
r.Use(AuthMiddleware()) // 認証ミドルウェア
181+
182+
// --- ルーティング ---
183+
// APIのベースパスを `/api/v1` とします (openapi.yamlのservers.urlに合わせる)
184+
apiV1 := r.Group("/api/v1")
185+
{
186+
apiV1.GET("/ping", PingHandler)
187+
188+
// Complexes
189+
// complexesGroup := apiV1.Group("/complexes")
190+
// {
191+
// // complexesGroup.POST("", CreateComplexHandler)
192+
// // complexesGroup.GET("", GetComplexesHandler)
193+
// // complexesGroup.GET("/:complexId", GetComplexHandler)
194+
// // complexesGroup.PUT("/:complexId", UpdateComplexHandler)
195+
// // complexesGroup.DELETE("/:complexId", DeleteComplexHandler)
196+
// }
197+
198+
// Goals
199+
// goalsGroup := apiV1.Group("/goals")
200+
// {
201+
// // goalsGroup.POST("", CreateGoalHandler)
202+
// // goalsGroup.GET("", GetGoalsHandler)
203+
// // goalsGroup.GET("/:goalId", GetGoalHandler)
204+
// // goalsGroup.PUT("/:goalId", UpdateGoalHandler)
205+
// // goalsGroup.DELETE("/:goalId", DeleteGoalHandler)
206+
// }
207+
208+
// Actions
209+
// actionsGroup := apiV1.Group("/actions")
210+
// {
211+
// // actionsGroup.POST("", CreateActionHandler)
212+
// }
213+
}
214+
215+
// --- サーバー起動 ---
216+
log.Printf("🚀 Server starting on port %s", serverPort)
217+
if err := r.Run(":" + serverPort); err != nil {
218+
log.Fatalf("🚨 Failed to run server: %v", err)
45219
}
46-
}
220+
}

0 commit comments

Comments
 (0)