From a6e203c188fbebbc39a4d690f9fcff7ee1a1866b Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 05:09:53 +0000 Subject: [PATCH 1/4] Setting up GitHub Classroom Feedback From 2f3e7676ca40d38a2fdfc1ae49d1f2faad9299a8 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 05:09:55 +0000 Subject: [PATCH 2/4] add deadline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e6a0a352..4fd9b5ea 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/QUdQy4ix) # CS3219 Project (PeerPrep) - AY2526S1 ## Group: Gxx From b242399ccfbc2f2c80ccfc6e305b3102f5bb559c Mon Sep 17 00:00:00 2001 From: hjungwoo01 Date: Mon, 15 Sep 2025 23:24:12 +0800 Subject: [PATCH 3/4] chore: init boilerplate code for user, question, match, and collab services --- .github/ci.yml | 32 ++++++++++++++++ .gitignore | 14 +++++++ README.md | 23 +++++++++++- deploy/docker-compose.yaml | 45 ++++++++++++++++++++++ services/collab/.dockerignore | 14 +++++++ services/collab/Dockerfile | 18 +++++++++ services/collab/cmd/server/main.go | 41 ++++++++++++++++++++ services/collab/go.mod | 10 +++++ services/collab/go.sum | 16 ++++++++ services/match/.dockerignore | 14 +++++++ services/match/Dockerfile | 22 +++++++++++ services/match/cmd/server/main.go | 56 ++++++++++++++++++++++++++++ services/match/go.mod | 10 +++++ services/match/go.sum | 16 ++++++++ services/question/.dockerignore | 14 +++++++ services/question/Dockerfile | 22 +++++++++++ services/question/cmd/server/main.go | 44 ++++++++++++++++++++++ services/question/go.mod | 10 +++++ services/question/go.sum | 16 ++++++++ services/user/.dockerignore | 14 +++++++ services/user/Dockerfile | 18 +++++++++ services/user/cmd/server/main.go | 51 +++++++++++++++++++++++++ services/user/go.mod | 10 +++++ services/user/go.sum | 16 ++++++++ 24 files changed, 545 insertions(+), 1 deletion(-) create mode 100644 .github/ci.yml create mode 100644 .gitignore create mode 100644 deploy/docker-compose.yaml create mode 100644 services/collab/.dockerignore create mode 100644 services/collab/Dockerfile create mode 100644 services/collab/cmd/server/main.go create mode 100644 services/collab/go.mod create mode 100644 services/collab/go.sum create mode 100644 services/match/.dockerignore create mode 100644 services/match/Dockerfile create mode 100644 services/match/cmd/server/main.go create mode 100644 services/match/go.mod create mode 100644 services/match/go.sum create mode 100644 services/question/.dockerignore create mode 100644 services/question/Dockerfile create mode 100644 services/question/cmd/server/main.go create mode 100644 services/question/go.mod create mode 100644 services/question/go.sum create mode 100644 services/user/.dockerignore create mode 100644 services/user/Dockerfile create mode 100644 services/user/cmd/server/main.go create mode 100644 services/user/go.mod create mode 100644 services/user/go.sum diff --git a/.github/ci.yml b/.github/ci.yml new file mode 100644 index 00000000..feae8d01 --- /dev/null +++ b/.github/ci.yml @@ -0,0 +1,32 @@ +name: ci +on: + push: + branches: [ "main" ] + pull_request: +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.22" + - name: Test all services + run: | + for d in services/*; do + echo "==> Testing $d" + (cd "$d" && go test ./...) + done + + docker-build: + runs-on: ubuntu-latest + needs: build-and-test + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Build images (no push) + run: | + for d in services/*; do + name=$(basename "$d") + docker build -t peerprep/$name:ci "$d" + done diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..dc0e5d20 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Binaries +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.test +*.out +bin/ +dist/ + +# Go +vendor/ +**/*.local diff --git a/README.md b/README.md index 4fd9b5ea..69573a1a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,27 @@ [![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/QUdQy4ix) # CS3219 Project (PeerPrep) - AY2526S1 -## Group: Gxx +## Group: G21 + +## Quick start (local) + +```bash +docker compose -f deploy/docker-compose.yaml up --build +``` + +Services: +- user: http://localhost:8081 +- question: http://localhost:8082 +- match: http://localhost:8083 +- collab: http://localhost:8084 + +MongoDB: mongodb://localhost:27017 +Redis: redis://localhost:6379 + +## Structure +- services/ : Go microservice with chi router and health endpoints +- deploy/docker-compose.yaml : local dev +- .github/workflows/ci.yml : minimal CI (test + build) + ### Note: - You are required to develop individual microservices within separate folders within this repository. diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml new file mode 100644 index 00000000..a8d449e8 --- /dev/null +++ b/deploy/docker-compose.yaml @@ -0,0 +1,45 @@ +services: + mongo: + image: mongo:7 + ports: ["27017:27017"] + volumes: [mongo-data:/data/db] + redis: + image: redis:7 + ports: ["6379:6379"] + + user: + build: ../services/user + environment: + - PORT=8080 + - MONGO_URI=mongodb://mongo:27017 + - JWT_PUBLIC_KEY=dev + depends_on: [mongo] + ports: ["8081:8080"] + + question: + build: ../services/question + environment: + - PORT=8080 + - MONGO_URI=mongodb://mongo:27017 + depends_on: [mongo] + ports: ["8082:8080"] + + match: + build: ../services/match + environment: + - PORT=8080 + - REDIS_URL=redis://redis:6379 + - MONGO_URI=mongodb://mongo:27017 + depends_on: [redis, mongo] + ports: ["8083:8080"] + + collab: + build: ../services/collab + environment: + - PORT=8080 + - MONGO_URI=mongodb://mongo:27017 + depends_on: [mongo] + ports: ["8084:8080"] + +volumes: + mongo-data: diff --git a/services/collab/.dockerignore b/services/collab/.dockerignore new file mode 100644 index 00000000..5f793c26 --- /dev/null +++ b/services/collab/.dockerignore @@ -0,0 +1,14 @@ +.git +.gitignore +.vscode +.idea + +bin +dist +*.out +*.test + +.DS_Store + +node_modules +venv \ No newline at end of file diff --git a/services/collab/Dockerfile b/services/collab/Dockerfile new file mode 100644 index 00000000..f34b2649 --- /dev/null +++ b/services/collab/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.22 AS build +WORKDIR /app + +COPY go.mod ./ +RUN go mod download + +COPY . . +RUN go mod tidy + +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app ./cmd/server + +FROM gcr.io/distroless/base-debian12 +WORKDIR / +COPY --from=build /out/app /app +USER 65532:65532 +ENV PORT=8080 +EXPOSE 8080 +ENTRYPOINT ["/app"] diff --git a/services/collab/cmd/server/main.go b/services/collab/cmd/server/main.go new file mode 100644 index 00000000..0350b464 --- /dev/null +++ b/services/collab/cmd/server/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "log" + "net/http" + "os" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "go.uber.org/zap" +) + +func registerRoutes(r *chi.Mux, logger *zap.Logger) { + // F4.* stubs + r.Post("/api/v1/session/start", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"status":"session_started_stub"}`)) + }) + r.Post("/api/v1/session/end", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"status":"session_ended_stub"}`)) + }) +} + +func main() { + logger, _ := zap.NewProduction() + defer logger.Sync() + + r := chi.NewRouter() + r.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer, middleware.Timeout(60*time.Second)) + + r.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("ok")) }) + registerRoutes(r, logger) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + addr := ":" + port + log.Printf("collab-svc listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, r)) +} diff --git a/services/collab/go.mod b/services/collab/go.mod new file mode 100644 index 00000000..a1dcbd4a --- /dev/null +++ b/services/collab/go.mod @@ -0,0 +1,10 @@ +module peerprep/collab + +go 1.22 + +require ( + github.com/go-chi/chi/v5 v5.0.12 + go.uber.org/zap v1.27.0 +) + +require go.uber.org/multierr v1.10.0 // indirect diff --git a/services/collab/go.sum b/services/collab/go.sum new file mode 100644 index 00000000..c0e9e80a --- /dev/null +++ b/services/collab/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/services/match/.dockerignore b/services/match/.dockerignore new file mode 100644 index 00000000..5f793c26 --- /dev/null +++ b/services/match/.dockerignore @@ -0,0 +1,14 @@ +.git +.gitignore +.vscode +.idea + +bin +dist +*.out +*.test + +.DS_Store + +node_modules +venv \ No newline at end of file diff --git a/services/match/Dockerfile b/services/match/Dockerfile new file mode 100644 index 00000000..df4cb3c6 --- /dev/null +++ b/services/match/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1 +FROM golang:1.22 AS build +WORKDIR /app + +# pull what's in go.mod (fast cacheable layer) +COPY go.mod ./ +RUN go mod download + +# now bring in code and resolve any new imports (adds go.sum entries) +COPY . . +RUN go mod tidy + +# build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app ./cmd/server + +FROM gcr.io/distroless/base-debian12 +WORKDIR / +COPY --from=build /out/app /app +USER 65532:65532 +ENV PORT=8080 +EXPOSE 8080 +ENTRYPOINT ["/app"] \ No newline at end of file diff --git a/services/match/cmd/server/main.go b/services/match/cmd/server/main.go new file mode 100644 index 00000000..01671981 --- /dev/null +++ b/services/match/cmd/server/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "log" + "net/http" + "os" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "github.com/gorilla/websocket" + "go.uber.org/zap" +) + +var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }} + +func registerRoutes(r *chi.Mux, logger *zap.Logger) { + // F2.* stubs + r.Post("/api/v1/match/request", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusAccepted) + w.Write([]byte(`{"status":"enqueued_stub"}`)) + }) + r.Delete("/api/v1/match/request", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"status":"cancelled_stub"}`)) + }) + r.Get("/api/v1/match/counters", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"waiting":0}`)) + }) + r.Get("/ws", func(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return + } + defer conn.Close() + conn.WriteJSON(map[string]any{"type": "waiting_count_update", "waiting": 0}) + }) +} + +func main() { + logger, _ := zap.NewProduction() + defer logger.Sync() + + r := chi.NewRouter() + r.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer, middleware.Timeout(60*time.Second)) + + r.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("ok")) }) + registerRoutes(r, logger) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + addr := ":" + port + log.Printf("match-svc listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, r)) +} diff --git a/services/match/go.mod b/services/match/go.mod new file mode 100644 index 00000000..0cad6fbe --- /dev/null +++ b/services/match/go.mod @@ -0,0 +1,10 @@ +module peerprep/match + +go 1.22 + +require ( + github.com/go-chi/chi/v5 v5.0.12 + go.uber.org/zap v1.27.0 +) + +require go.uber.org/multierr v1.10.0 // indirect diff --git a/services/match/go.sum b/services/match/go.sum new file mode 100644 index 00000000..c0e9e80a --- /dev/null +++ b/services/match/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/services/question/.dockerignore b/services/question/.dockerignore new file mode 100644 index 00000000..5f793c26 --- /dev/null +++ b/services/question/.dockerignore @@ -0,0 +1,14 @@ +.git +.gitignore +.vscode +.idea + +bin +dist +*.out +*.test + +.DS_Store + +node_modules +venv \ No newline at end of file diff --git a/services/question/Dockerfile b/services/question/Dockerfile new file mode 100644 index 00000000..df4cb3c6 --- /dev/null +++ b/services/question/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1 +FROM golang:1.22 AS build +WORKDIR /app + +# pull what's in go.mod (fast cacheable layer) +COPY go.mod ./ +RUN go mod download + +# now bring in code and resolve any new imports (adds go.sum entries) +COPY . . +RUN go mod tidy + +# build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app ./cmd/server + +FROM gcr.io/distroless/base-debian12 +WORKDIR / +COPY --from=build /out/app /app +USER 65532:65532 +ENV PORT=8080 +EXPOSE 8080 +ENTRYPOINT ["/app"] \ No newline at end of file diff --git a/services/question/cmd/server/main.go b/services/question/cmd/server/main.go new file mode 100644 index 00000000..72fac1b7 --- /dev/null +++ b/services/question/cmd/server/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "log" + "net/http" + "os" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "go.uber.org/zap" +) + +func registerRoutes(r *chi.Mux, logger *zap.Logger) { + // F3.* stubs + r.Get("/api/v1/questions", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"items":[]}`)) + }) + r.Get("/api/v1/questions/{id}", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"id":"stub"}`)) + }) + r.Get("/api/v1/questions/pick", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"questionId":"stub"}`)) + }) +} + +func main() { + logger, _ := zap.NewProduction() + defer logger.Sync() + + r := chi.NewRouter() + r.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer, middleware.Timeout(60*time.Second)) + + r.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("ok")) }) + registerRoutes(r, logger) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + addr := ":" + port + log.Printf("question-svc listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, r)) +} diff --git a/services/question/go.mod b/services/question/go.mod new file mode 100644 index 00000000..b241030b --- /dev/null +++ b/services/question/go.mod @@ -0,0 +1,10 @@ +module peerprep/question + +go 1.22 + +require ( + github.com/go-chi/chi/v5 v5.0.12 + go.uber.org/zap v1.27.0 +) + +require go.uber.org/multierr v1.10.0 // indirect diff --git a/services/question/go.sum b/services/question/go.sum new file mode 100644 index 00000000..c0e9e80a --- /dev/null +++ b/services/question/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/services/user/.dockerignore b/services/user/.dockerignore new file mode 100644 index 00000000..5f793c26 --- /dev/null +++ b/services/user/.dockerignore @@ -0,0 +1,14 @@ +.git +.gitignore +.vscode +.idea + +bin +dist +*.out +*.test + +.DS_Store + +node_modules +venv \ No newline at end of file diff --git a/services/user/Dockerfile b/services/user/Dockerfile new file mode 100644 index 00000000..f34b2649 --- /dev/null +++ b/services/user/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.22 AS build +WORKDIR /app + +COPY go.mod ./ +RUN go mod download + +COPY . . +RUN go mod tidy + +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app ./cmd/server + +FROM gcr.io/distroless/base-debian12 +WORKDIR / +COPY --from=build /out/app /app +USER 65532:65532 +ENV PORT=8080 +EXPOSE 8080 +ENTRYPOINT ["/app"] diff --git a/services/user/cmd/server/main.go b/services/user/cmd/server/main.go new file mode 100644 index 00000000..d1c7b4d7 --- /dev/null +++ b/services/user/cmd/server/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "log" + "net/http" + "os" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "go.uber.org/zap" +) + +func registerRoutes(r *chi.Mux, logger *zap.Logger) { + // F1.* stubs + r.Post("/api/v1/auth/register", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"status":"registered_stub"}`)) + }) + r.Post("/api/v1/auth/login", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"accessToken":"stub","refreshToken":"stub"}`)) + }) + r.Post("/api/v1/auth/logout", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"status":"logged_out_stub"}`)) + }) + r.Put("/api/v1/account", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"status":"account_updated_stub"}`)) + }) + r.Delete("/api/v1/account", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`{"status":"account_deleted_stub"}`)) + }) +} + +func main() { + logger, _ := zap.NewProduction() + defer logger.Sync() + + r := chi.NewRouter() + r.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer, middleware.Timeout(60*time.Second)) + + r.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("ok")) }) + registerRoutes(r, logger) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + addr := ":" + port + log.Printf("user-svc listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, r)) +} diff --git a/services/user/go.mod b/services/user/go.mod new file mode 100644 index 00000000..18aa9ce2 --- /dev/null +++ b/services/user/go.mod @@ -0,0 +1,10 @@ +module peerprep/user + +go 1.22 + +require ( + github.com/go-chi/chi/v5 v5.0.12 + go.uber.org/zap v1.27.0 +) + +require go.uber.org/multierr v1.10.0 // indirect diff --git a/services/user/go.sum b/services/user/go.sum new file mode 100644 index 00000000..c0e9e80a --- /dev/null +++ b/services/user/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 27829e14c82fad8e48a546aeb60f64b7be0ad20a Mon Sep 17 00:00:00 2001 From: hjungwoo01 Date: Mon, 15 Sep 2025 23:26:35 +0800 Subject: [PATCH 4/4] chore: init boilerplate code for user, question, match, and collab services --- services/match/Dockerfile | 6 +----- services/question/Dockerfile | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/services/match/Dockerfile b/services/match/Dockerfile index df4cb3c6..f34b2649 100644 --- a/services/match/Dockerfile +++ b/services/match/Dockerfile @@ -1,16 +1,12 @@ -# syntax=docker/dockerfile:1 FROM golang:1.22 AS build WORKDIR /app -# pull what's in go.mod (fast cacheable layer) COPY go.mod ./ RUN go mod download -# now bring in code and resolve any new imports (adds go.sum entries) COPY . . RUN go mod tidy -# build RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app ./cmd/server FROM gcr.io/distroless/base-debian12 @@ -19,4 +15,4 @@ COPY --from=build /out/app /app USER 65532:65532 ENV PORT=8080 EXPOSE 8080 -ENTRYPOINT ["/app"] \ No newline at end of file +ENTRYPOINT ["/app"] diff --git a/services/question/Dockerfile b/services/question/Dockerfile index df4cb3c6..f34b2649 100644 --- a/services/question/Dockerfile +++ b/services/question/Dockerfile @@ -1,16 +1,12 @@ -# syntax=docker/dockerfile:1 FROM golang:1.22 AS build WORKDIR /app -# pull what's in go.mod (fast cacheable layer) COPY go.mod ./ RUN go mod download -# now bring in code and resolve any new imports (adds go.sum entries) COPY . . RUN go mod tidy -# build RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app ./cmd/server FROM gcr.io/distroless/base-debian12 @@ -19,4 +15,4 @@ COPY --from=build /out/app /app USER 65532:65532 ENV PORT=8080 EXPOSE 8080 -ENTRYPOINT ["/app"] \ No newline at end of file +ENTRYPOINT ["/app"]