diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 93a727a..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: CI
-
-on:
- pull_request:
- branches: [main]
- push:
- branches: [main]
-
-jobs:
- test:
- name: Run tests
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
-
- - uses: actions/setup-go@v5
- with:
- go-version-file: go.mod
- cache: true
-
- - name: Download dependencies
- run: go mod download
-
- - name: Run tests
- run: go test ./test/... -v -count=1
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..d3d4238
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,45 @@
+name: Deploy to College Server
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+jobs:
+ test:
+ name: Run tests
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-go@v5
+ with:
+ go-version-file: go.mod
+ cache: true
+
+ - name: Download dependencies
+ run: go mod download
+
+ - name: Run tests
+ run: go test ./test/... -v -count=1
+
+ deploy:
+ name: Deploy via SSH
+ needs: test
+ runs-on: ubuntu-latest
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+ steps:
+ - name: Deploy to Server via SSH
+ uses: appleboy/ssh-action@v1.0.3
+ with:
+ host: ${{ secrets.SSH_HOST }}
+ username: ${{ secrets.SSH_USERNAME }}
+ password: ${{ secrets.SSH_PASSWORD }}
+ port: 22
+ script: |
+ cd ~/cms-webb
+ git pull origin main
+ sudo docker compose up -d --build
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..814c1d1
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,15 @@
+# Stage 1: Build the Go application
+FROM golang:1.26-alpine AS builder
+WORKDIR /app
+COPY go.mod go.sum ./
+RUN go mod download
+COPY . .
+RUN CGO_ENABLED=0 GOOS=linux go build -o main .
+
+# Stage 2: Final minimal image
+FROM alpine:latest
+RUN apk --no-cache add ca-certificates
+WORKDIR /root/
+COPY --from=builder /app/main .
+EXPOSE 8080
+CMD ["./main"]
diff --git a/README.md b/README.md
index c546102..90b7405 100644
--- a/README.md
+++ b/README.md
@@ -26,4 +26,6 @@ the official web interface of the Estate Office of NIT Hamirpur to manage compla
### Complaint status public dashboard
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/app/Dockerfile b/app/Dockerfile
new file mode 100644
index 0000000..81e9f44
--- /dev/null
+++ b/app/Dockerfile
@@ -0,0 +1,14 @@
+# Stage 1: Build the React application
+FROM node:20-alpine AS builder
+WORKDIR /app
+COPY package.json package-lock.json ./
+RUN npm ci
+COPY . .
+RUN npm run build
+
+# Stage 2: Serve the static files using Nginx
+FROM nginx:alpine
+COPY --from=builder /app/dist /usr/share/nginx/html
+COPY nginx.conf /etc/nginx/conf.d/default.conf
+EXPOSE 80
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/app/nginx.conf b/app/nginx.conf
new file mode 100644
index 0000000..02a947b
--- /dev/null
+++ b/app/nginx.conf
@@ -0,0 +1,20 @@
+server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ try_files $uri $uri/ /index.html;
+ }
+
+ # Proxy API requests to the Go backend
+ location /api/ {
+ proxy_pass http://backend:8080;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
+}
diff --git a/config/db.go b/config/db.go
index 823d356..2e24913 100644
--- a/config/db.go
+++ b/config/db.go
@@ -17,9 +17,10 @@ func ConnectDB() {
DB_USER := helpers.GetEnv("DB_USER")
DB_NAME := helpers.GetEnv("DB_NAME")
DB_PASS := helpers.GetEnv("DB_PASS")
- // DB_PORT := helpers.GetEnv("DB_PORT") // will see during deployment
+ DB_HOST := helpers.GetEnvWithDefault("DB_HOST", "localhost")
+ DB_PORT := helpers.GetEnvWithDefault("DB_PORT", "5432")
- dsn := fmt.Sprintf("host=localhost user=%s password=%s dbname=%s port=5432 sslmode=disable", DB_USER, DB_PASS, DB_NAME)
+ dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable", DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..eb42c65
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,45 @@
+version: '3.8'
+
+services:
+ db:
+ image: postgres:15-alpine
+ container_name: cms-db
+ restart: always
+ environment:
+ POSTGRES_USER: ${DB_USER:-postgres}
+ POSTGRES_PASSWORD: ${DB_PASS:-postgres}
+ POSTGRES_DB: ${DB_NAME:-cms}
+ ports:
+ - "5433:5432"
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+ backend:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: cms-backend
+ restart: always
+ depends_on:
+ - db
+ env_file:
+ - .env
+ environment:
+ DB_HOST: db
+ DB_PORT: 5432
+ ports:
+ - "8082:8080"
+
+ frontend:
+ build:
+ context: ./app
+ dockerfile: Dockerfile
+ container_name: cms-frontend
+ restart: always
+ ports:
+ - "8083:80"
+ depends_on:
+ - backend
+
+volumes:
+ postgres_data:
diff --git a/handlers/admin_auth.go b/handlers/admin_auth.go
index 2f47b2c..5036a1b 100644
--- a/handlers/admin_auth.go
+++ b/handlers/admin_auth.go
@@ -77,7 +77,7 @@ func (h *AdminHandler) AdminLogin (c *gin.Context) {
token,
30 * 24 * 60 * 60,
"/",
- "localhost",
+ helpers.GetEnvWithDefault("COOKIE_DOMAIN", "localhost"),
false,
true,
)
diff --git a/handlers/admin_status.go b/handlers/admin_status.go
index 50c151c..a4343ed 100644
--- a/handlers/admin_status.go
+++ b/handlers/admin_status.go
@@ -15,6 +15,7 @@ import (
"strings"
"time"
+ "github.com/ayush00git/cms-web/helpers"
"github.com/ayush00git/cms-web/middleware"
"github.com/ayush00git/cms-web/models"
"github.com/ayush00git/cms-web/services"
@@ -90,7 +91,8 @@ func (h *AdminHandler) AdminFacultyPostStatus(c *gin.Context) {
}
// create the postURL
- postURL := fmt.Sprintf(`http://localhost:5173/admin/posts/%s/%d`, "faculty", post.ID)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ postURL := fmt.Sprintf(`%s/admin/posts/%s/%d`, frontendURL, "faculty", post.ID)
switch post.Status {
// ** Posts with status type mentioned PendingXEN **
@@ -436,7 +438,8 @@ func (h *AdminHandler) AdminWardenPostStatus(c *gin.Context) {
}
// create the postURL
- postURL := fmt.Sprintf(`http://localhost:5173/admin/posts/%s/%d`, "warden", post.ID)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ postURL := fmt.Sprintf(`%s/admin/posts/%s/%d`, frontendURL, "warden", post.ID)
switch post.Status {
// ** Posts with status type mentioned PendingXEN **
@@ -782,7 +785,8 @@ func (h *AdminHandler) AdminCentreheadPostStatus(c *gin.Context) {
}
// create the postURL
- postURL := fmt.Sprintf(`http://localhost:5173/admin/posts/%s/%d`, "centrehead", post.ID)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ postURL := fmt.Sprintf(`%s/admin/posts/%s/%d`, frontendURL, "centrehead", post.ID)
switch post.Status {
// ** Posts with status type mentioned PendingXEN **
diff --git a/handlers/auth.go b/handlers/auth.go
index de01b49..5035556 100644
--- a/handlers/auth.go
+++ b/handlers/auth.go
@@ -16,7 +16,7 @@ func (h *AuthHandler) Logout (c *gin.Context) {
" ",
-1,
"/",
- "localhost",
+ helpers.GetEnvWithDefault("COOKIE_DOMAIN", "localhost"),
false,
true,
)
diff --git a/handlers/centrehead_auth.go b/handlers/centrehead_auth.go
index 8ee37e8..b4b7f7e 100644
--- a/handlers/centrehead_auth.go
+++ b/handlers/centrehead_auth.go
@@ -115,7 +115,7 @@ func (h *AuthHandler) CentreheadLogin(c *gin.Context) {
token,
30 * 24 * 60 * 60,
"/",
- "localhost",
+ helpers.GetEnvWithDefault("COOKIE_DOMAIN", "localhost"),
false,
true,
)
diff --git a/handlers/centrehead_post.go b/handlers/centrehead_post.go
index 64a6c97..1a65e89 100644
--- a/handlers/centrehead_post.go
+++ b/handlers/centrehead_post.go
@@ -7,6 +7,7 @@ import (
"strconv"
"time"
+ "github.com/ayush00git/cms-web/helpers"
"github.com/ayush00git/cms-web/middleware"
"github.com/ayush00git/cms-web/models"
"github.com/ayush00git/cms-web/services"
@@ -80,9 +81,8 @@ func (h *PostHandler) CentreheadPost(c *gin.Context) {
return
}
- // send the mail to the corresponding xen
- // } />
- postURL := fmt.Sprintf(`http://localhost:5173/admin/posts/%s/%d`, head.Role, post.ID)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ postURL := fmt.Sprintf(`%s/admin/posts/%s/%d`, frontendURL, head.Role, post.ID)
go func() {
var position models.PositionType
if post.TypeOfPost == "Civil" {
diff --git a/handlers/faculty_auth.go b/handlers/faculty_auth.go
index 83e508c..282d05c 100644
--- a/handlers/faculty_auth.go
+++ b/handlers/faculty_auth.go
@@ -137,7 +137,7 @@ func (h *AuthHandler) FacultyLogin (c *gin.Context) {
token,
30 * 24 * 60 * 60, // 30 days
"/",
- "localhost",
+ helpers.GetEnvWithDefault("COOKIE_DOMAIN", "localhost"),
false, // set to true during deployment (secure bool)
true, // set to false during deployment (httpOnly bool)
)
diff --git a/handlers/faculty_post.go b/handlers/faculty_post.go
index af99f67..c019890 100644
--- a/handlers/faculty_post.go
+++ b/handlers/faculty_post.go
@@ -7,6 +7,7 @@ import (
"strconv"
"time"
+ "github.com/ayush00git/cms-web/helpers"
"github.com/ayush00git/cms-web/middleware"
"github.com/ayush00git/cms-web/models"
"github.com/ayush00git/cms-web/services"
@@ -87,9 +88,8 @@ func (h *PostHandler) FacultyPost(c *gin.Context) {
return
}
- // send the mail to the corresponding xen
- // } />
- postURL := fmt.Sprintf(`http://localhost:5173/admin/posts/%s/%d`, faculty.Role, post.ID)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ postURL := fmt.Sprintf(`%s/admin/posts/%s/%d`, frontendURL, faculty.Role, post.ID)
go func() {
var position models.PositionType
if post.TypeOfPost == "Civil" {
diff --git a/handlers/warden_auth.go b/handlers/warden_auth.go
index 385e735..9875c7e 100644
--- a/handlers/warden_auth.go
+++ b/handlers/warden_auth.go
@@ -115,7 +115,7 @@ func (h *AuthHandler) WardenLogin (c *gin.Context) {
token,
30 * 24 * 60 * 60,
"/",
- "localhost",
+ helpers.GetEnvWithDefault("COOKIE_DOMAIN", "localhost"),
false,
true,
)
diff --git a/handlers/warden_post.go b/handlers/warden_post.go
index 8391629..cfc298b 100644
--- a/handlers/warden_post.go
+++ b/handlers/warden_post.go
@@ -7,6 +7,7 @@ import (
"strconv"
"time"
+ "github.com/ayush00git/cms-web/helpers"
"github.com/ayush00git/cms-web/middleware"
"github.com/ayush00git/cms-web/models"
"github.com/ayush00git/cms-web/services"
@@ -84,9 +85,8 @@ func (h *PostHandler) WardenPost(c *gin.Context) {
return
}
- // send the mail to the corresponding xen
- // } />
- postURL := fmt.Sprintf(`http://localhost:5173/admin/posts/%s/%d`, warden.Role, post.ID)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ postURL := fmt.Sprintf(`%s/admin/posts/%s/%d`, frontendURL, warden.Role, post.ID)
go func() {
var position models.PositionType
if post.TypeOfPost == "Civil" {
diff --git a/helpers/env.go b/helpers/env.go
index 2b82ec8..0cf2976 100644
--- a/helpers/env.go
+++ b/helpers/env.go
@@ -12,3 +12,11 @@ func GetEnv(target string) string {
}
return value
}
+
+func GetEnvWithDefault(target, defaultValue string) string {
+ value := os.Getenv(target)
+ if value == "" {
+ return defaultValue
+ }
+ return value
+}
diff --git a/main.go b/main.go
index 0d99070..df73d5b 100644
--- a/main.go
+++ b/main.go
@@ -2,10 +2,10 @@ package main
import (
"fmt"
- "log"
"github.com/ayush00git/cms-web/config"
"github.com/ayush00git/cms-web/handlers"
+ "github.com/ayush00git/cms-web/helpers"
"github.com/ayush00git/cms-web/routes"
"github.com/gin-contrib/cors"
@@ -14,10 +14,8 @@ import (
)
func main() {
- err := godotenv.Load()
- if err != nil {
- log.Fatal("Error while loading the environment variables")
- }
+ // Load .env file if it exists, ignore error if missing (e.g. in docker containers)
+ _ = godotenv.Load()
// db connection
config.ConnectDB()
@@ -26,7 +24,8 @@ func main() {
// CORS policy and config
corsConfig := cors.DefaultConfig()
- corsConfig.AllowOrigins = []string{"http://localhost:5173"}
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ corsConfig.AllowOrigins = []string{frontendURL}
corsConfig.AllowCredentials = true
r.Use(cors.New(corsConfig))
diff --git a/services/email.go b/services/email.go
index 7a45f09..a24037c 100644
--- a/services/email.go
+++ b/services/email.go
@@ -42,7 +42,8 @@ func SendVerificationMail(userId uint, email, role string) (error) {
}
// create the verification url
- verificationURL := fmt.Sprintf(`http://localhost:5173/account/verify?token=%s`, token)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ verificationURL := fmt.Sprintf(`%s/account/verify?token=%s`, frontendURL, token)
// send the email
mail := fmt.Sprintf(`
@@ -79,7 +80,8 @@ func SendPasswordResetMail(userID uint, email, role string) error {
if err != nil {
return err
}
- resetURL := fmt.Sprintf(`http://localhost:5173/account/reset-password?user=%s`, token)
+ frontendURL := helpers.GetEnvWithDefault("FRONTEND_URL", "http://localhost:5173")
+ resetURL := fmt.Sprintf(`%s/account/reset-password?user=%s`, frontendURL, token)
// send the email
mail := fmt.Sprintf(`