Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Database
POSTGRES_DB=codesce
POSTGRES_USER=codesce
POSTGRES_PASSWORD=changeme
DB_PORT=5432

# Backend
BACKEND_PORT=6767
GIN_MODE=debug
DATABASE_URL=postgres://codesce:changeme@database:5432/codesce?sslmode=disable

# Frontend
FRONTEND_PORT=3000
VITE_API_URL=http://localhost:6767
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.cursor/
.env
/server
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Backend Dockerfile (Go/Gin)

# --- Build stage ---
FROM golang:1.25-alpine AS build

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN go build -o /bin/server ./cmd/server

# --- Production stage ---
FROM alpine:3.20 AS production

RUN apk add --no-cache ca-certificates

WORKDIR /app

COPY --from=build /bin/server /bin/server

EXPOSE 6767

CMD ["/bin/server"]
15 changes: 15 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Backend Dev Dockerfile (Go/Gin)

FROM golang:1.25-alpine

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .

EXPOSE 6767

CMD ["go", "run", "./cmd/server"]
# Note: app should listen on port 6767
49 changes: 49 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,64 @@
package main

import (
"database/sql"
"log"
"os"

"github.com/gin-gonic/gin"
_ "github.com/jackc/pgx/v5/stdlib"

"CodeSCE/internal/db"
"CodeSCE/internal/handlers"
)

func main() {
dsn := os.Getenv("DATABASE_URL")
if dsn == "" {
log.Fatal("DATABASE_URL environment variable is required")
}

database, err := sql.Open("pgx", dsn)
if err != nil {
log.Fatalf("failed to open database: %v", err)
}
defer database.Close()

if err := database.Ping(); err != nil {
log.Fatalf("failed to ping database: %v", err)
}

if err := db.InitSchema(database); err != nil {
log.Fatalf("failed to initialize schema: %v", err)
}

r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})

api := r.Group("/api")
api.POST("/assessments", handlers.CreateAssessment)
api.GET("/assessments", handlers.ListAssessments)
api.GET("/assessments/:id", handlers.GetAssessment)
api.POST("/assessments/:id/questions", handlers.AddQuestion)
api.POST("/assessments/:id/questions/:qid/test-cases", handlers.AddTestCases)

api.POST("/assessments/:id/invites", handlers.CreateInvite)
api.GET("/invites", handlers.ListInvites)
api.GET("/invites/:token", handlers.ValidateInvite)
api.POST("/invites/:token/start", handlers.StartAttempt)

api.GET("/attempts", handlers.ListAttempts)
api.GET("/attempts/:id", handlers.GetAttempt)
api.GET("/attempts/:id/questions", handlers.GetAttemptQuestions)
api.POST("/attempts/:id/answers", handlers.SaveAnswers)
api.POST("/attempts/:id/submit", handlers.SubmitAttempt)

api.POST("/attempts/:id/questions/:qid/submissions", handlers.CreateSubmission)
api.GET("/submissions/:id", handlers.GetSubmission)
api.POST("/attempts/:id/questions/:qid/run", handlers.RunCode)
r.Run(":6767")
}
38 changes: 38 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
services:
database:
ports:
- "${DB_PORT:-5432}:5432"

backend:
build:
context: .
dockerfile: Dockerfile.dev
environment:
GIN_MODE: debug
PORT: ${BACKEND_PORT:-6767}
DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?sslmode=disable
volumes:
- .:/app
- go-mod-cache:/go/pkg/mod
ports:
- "${BACKEND_PORT:-6767}:6767"
depends_on:
database:
condition: service_healthy

frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
environment:
VITE_API_URL: http://localhost:${BACKEND_PORT:-6767}
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "${FRONTEND_PORT:-3000}:5173"
depends_on:
- backend

volumes:
go-mod-cache:
52 changes: 52 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
services:
database:
image: postgres:16-alpine
container_name: codesce-db
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "${DB_PORT:-5432}:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5

backend:
build:
context: .
dockerfile: Dockerfile
container_name: codesce-backend
environment:
DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?sslmode=disable
GIN_MODE: ${GIN_MODE:-release}
PORT: ${BACKEND_PORT:-6767}
ports:
- "${BACKEND_PORT:-6767}:6767"
depends_on:
database:
condition: service_healthy

frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: codesce-frontend
environment:
VITE_API_URL: ${VITE_API_URL:-http://backend:6767}
ports:
- "${FRONTEND_PORT:-3000}:80"
depends_on:
- backend

volumes:
pgdata:

networks:
default:
external: true
name: sce
23 changes: 23 additions & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Frontend Dockerfile (React/Vite)

# --- Build stage ---
FROM node:20-alpine AS build

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

RUN npm run build

# --- Production stage ---
FROM nginx:alpine AS production

COPY --from=build /app/dist /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
15 changes: 15 additions & 0 deletions frontend/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Frontend Dev Dockerfile (React/Vite)

FROM node:20-alpine

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

EXPOSE 5173

CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
9 changes: 8 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module CodeSCE

go 1.25.0

require github.com/gin-gonic/gin v1.12.0
require (
github.com/gin-gonic/gin v1.12.0
github.com/jackc/pgx/v5 v5.9.1
)

require (
github.com/bytedance/gopkg v0.1.3 // indirect
Expand All @@ -16,6 +19,9 @@ require (
github.com/go-playground/validator/v10 v10.30.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
Expand All @@ -31,6 +37,7 @@ require (
golang.org/x/arch v0.22.0 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/net v0.51.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
Expand Down
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc=
github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
Expand All @@ -56,6 +64,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
Expand All @@ -76,6 +85,8 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
Expand Down
Loading