From 2046a32202d70753bb67d122b8a8748ac080ff6e Mon Sep 17 00:00:00 2001
From: cdricms <36056008+cdricms@users.noreply.github.com>
Date: Sat, 18 Jan 2025 21:13:03 +0100
Subject: [PATCH] Should be able to deploy
---
.env.template | 17 ++++++
backend/main.go | 4 +-
docker-compose.yaml | 11 +++-
frontend/Dockerfile | 66 ++++++++++++++++++-----
frontend/Dockerfile.old | 25 +++++++++
frontend/app/(main)/about/page.tsx | 2 -
frontend/eslint.config.mjs | 16 ------
frontend/lib/constants.ts | 2 +-
frontend/middleware.ts | 7 ++-
frontend/next.config.ts | 10 ++++
init.py | 84 ++++++++++++++++++++++++++++++
init.sh | 4 --
nginx.conf | 11 ----
nginx/default.conf | 20 +++++++
nginx/default.conf.template | 20 +++++++
15 files changed, 248 insertions(+), 51 deletions(-)
create mode 100644 .env.template
create mode 100644 frontend/Dockerfile.old
delete mode 100644 frontend/eslint.config.mjs
create mode 100644 init.py
delete mode 100755 init.sh
delete mode 100644 nginx.conf
create mode 100644 nginx/default.conf
create mode 100644 nginx/default.conf.template
diff --git a/.env.template b/.env.template
new file mode 100644
index 0000000..ae23f5c
--- /dev/null
+++ b/.env.template
@@ -0,0 +1,17 @@
+ENVIRONMENT=${ENVIRONMENT:-PRODUCTION}
+POSTGRES_USER=${POSTGRES_USER:-latosa}
+POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-1234}
+POSTGRES_DB=${POSTGRES_DB:-latosa}
+# Docker inner port container
+POSTGRES_DOCKER_PORT=${POSTGRES_DOCKER_PORT:-5432}
+BACKEND_DOCKER_PORT=${BACKEND_DOCKER_PORT:-3001}
+FRONTEND_DOCKER_PORT=${FRONTEND_DOCKER_PORT:-3000}
+
+POSTGRES_PORT=${POSTGRES_PORT:-5432}
+BACKEND_PORT=${BACKEND_PORT:-3001}
+FRONTEND_PORT=${FRONTEND_PORT:-3000}
+
+FRONTEND_HOSTNAME=${FRONTEND_HOSTNAME:-latosa-frontend}
+BACKEND_HOSTNAME=${BACKEND_HOSTNAME:-latosa-backend}
+DATABASE_HOSTNAME=${DATABASE_HOSTNAME:-latosa-database}
+SERVER_NAME=${SERVER_NAME:-localhost}
diff --git a/backend/main.go b/backend/main.go
index aa115ae..4bbeb6e 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -41,12 +41,14 @@ func main() {
environ := os.Getenv("ENVIRONMENT")
port := os.Getenv("BACKEND_DOCKER_PORT")
+ hostname := os.Getenv("DATABASE_HOSTNAME")
if environ == "DEV" {
port = os.Getenv("BACKEND_PORT")
+ hostname = "localhost"
}
dsn := core.DSN{
- Hostname: "localhost",
+ Hostname: hostname,
Port: os.Getenv("POSTGRES_PORT"),
DBName: os.Getenv("POSTGRES_DB"),
User: os.Getenv("POSTGRES_USER"),
diff --git a/docker-compose.yaml b/docker-compose.yaml
index dbd3c6c..206c5cf 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,7 +1,12 @@
services:
latosa-escrima.fr-frontend:
container_name: latosa-frontend
- image: cems.dev:5000/latosa-escrima.fr:latest
+ # image: cems.dev:5000/latosa-escrima.fr:latest
+ build:
+ context: ./frontend/
+ dockerfile: Dockerfile
+ depends_on:
+ - latosa-escrima.fr-backend
env_file: .env
ports:
- ${FRONTEND_PORT}:${FRONTEND_DOCKER_PORT}
@@ -9,7 +14,10 @@ services:
networks:
- le-network
latosa-escrima.fr-backend:
+ restart: always
container_name: latosa-backend
+ depends_on:
+ - psql
build:
context: ./backend/
dockerfile: Dockerfile
@@ -35,3 +43,4 @@ volumes:
networks:
le-network:
+ driver: bridge
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 1ba1333..33b45ca 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -1,24 +1,62 @@
-# Use Deno image
-FROM denoland/deno:alpine
+# syntax=docker.io/docker/dockerfile:1
-# Set working directory
+FROM node:18-alpine AS base
+
+# Install dependencies only when needed
+FROM base AS deps
+# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
+RUN apk add --no-cache libc6-compat
WORKDIR /app
-# Copy project files
+# Install dependencies based on the preferred package manager
+COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
+RUN \
+ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
+ elif [ -f package-lock.json ]; then npm ci; \
+ elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
+ else echo "Lockfile not found." && exit 1; \
+ fi
+
+
+# Rebuild the source code only when needed
+FROM base AS builder
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
COPY . .
+# Next.js collects completely anonymous telemetry data about general usage.
+# Learn more here: https://nextjs.org/telemetry
+# Uncomment the following line in case you want to disable telemetry during the build.
+# ENV NEXT_TELEMETRY_DISABLED=1
+
+RUN \
+ if [ -f yarn.lock ]; then yarn run build; \
+ elif [ -f package-lock.json ]; then npm run build; \
+ elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
+ else echo "Lockfile not found." && exit 1; \
+ fi
+
+# Production image, copy all the files and run next
+FROM base AS runner
+WORKDIR /app
+
ENV NODE_ENV=production
-RUN deno install
+# Uncomment the following line in case you want to disable telemetry during runtime.
+ENV NEXT_TELEMETRY_DISABLED=1
-# Install Next.js dependencies
-RUN deno task build
+RUN addgroup --system --gid 1001 nodejs
+RUN adduser --system --uid 1001 nextjs
-# Move everything to the standalone
-RUN cp -r public .next/standalone/public
-RUN cp -r .next/static .next/standalone/.next/static
-RUN mv .next/standalone/server.js .next/standalone/server.cjs
+COPY --from=builder /app/public ./public
-RUN rm -r ./node_modules
+# Automatically leverage output traces to reduce image size
+# https://nextjs.org/docs/advanced-features/output-file-tracing
+COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
+COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
-# Start the Next.js app
-CMD ["deno", "run", "--allow-env", "--allow-read", "--allow-sys", "--allow-net", ".next/standalone/server.cjs"]
+USER nextjs
+
+# server.js is created by next build from the standalone output
+# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
+ENV HOSTNAME="0.0.0.0"
+CMD ["node", "server.js"]
diff --git a/frontend/Dockerfile.old b/frontend/Dockerfile.old
new file mode 100644
index 0000000..e3705ee
--- /dev/null
+++ b/frontend/Dockerfile.old
@@ -0,0 +1,25 @@
+# Use Deno image
+FROM node
+
+# Set working directory
+WORKDIR /app
+
+# Copy project files
+COPY . .
+
+ENV NODE_PATH=.
+ENV NODE_ENV=production
+RUN npm install
+
+# Install Next.js dependencies
+RUN npm run build
+
+# Move everything to the standalone
+RUN cp -r public .next/standalone/public
+RUN cp -r .next/static .next/standalone/.next/static
+RUN mv .next/standalone/server.js .next/standalone/server.cjs
+
+RUN rm -r ./node_modules
+
+# Start the Next.js app
+CMD ["node", ".next/standalone/server.cjs"]
diff --git a/frontend/app/(main)/about/page.tsx b/frontend/app/(main)/about/page.tsx
index 2668b5a..025e9b5 100644
--- a/frontend/app/(main)/about/page.tsx
+++ b/frontend/app/(main)/about/page.tsx
@@ -1,8 +1,6 @@
"use server";
export default async function About() {
- const res = await fetch("api");
- console.log(res);
return (
diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs
deleted file mode 100644
index 1a9ff38..0000000
--- a/frontend/eslint.config.mjs
+++ /dev/null
@@ -1,16 +0,0 @@
-import { dirname } from "path";
-import { fileURLToPath } from "url";
-import { FlatCompat } from "@eslint/eslintrc";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
-
-const compat = new FlatCompat({
- baseDirectory: __dirname,
-});
-
-const eslintConfig = [
- ...compat.extends("next/core-web-vitals", "next/typescript"),
-];
-
-export default eslintConfig;
diff --git a/frontend/lib/constants.ts b/frontend/lib/constants.ts
index 7ef418c..4b606d6 100644
--- a/frontend/lib/constants.ts
+++ b/frontend/lib/constants.ts
@@ -1 +1 @@
-export const API_URL = `http://localhost:${process.env.NEXT_PUBLIC_BACKEND_PORT}`;
+export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "";
diff --git a/frontend/middleware.ts b/frontend/middleware.ts
index 74eee25..404163b 100644
--- a/frontend/middleware.ts
+++ b/frontend/middleware.ts
@@ -5,6 +5,7 @@ import IUser from "./interfaces/IUser";
export async function middleware(request: NextRequest) {
const sessionCookie = request.cookies.get("auth_token")?.value;
+ // console.log(sessionCookie);
if (!sessionCookie) {
return NextResponse.redirect(
new URL(
@@ -15,18 +16,22 @@ export async function middleware(request: NextRequest) {
}
try {
+ console.log(API_URL);
const res = await fetch(`${API_URL}/users/me`, {
headers: { Authorization: `Bearer ${sessionCookie}` },
});
const js: ApiResponse = await res.json();
- if (js.status === "Error")
+ if (js.status === "Error") {
+ console.log(js.message);
return NextResponse.redirect(
new URL(
`/login?redirectTo=${encodeURIComponent(request.url)}`,
request.url,
),
);
+ }
} catch (e: any) {
+ console.log(e);
return NextResponse.redirect(
new URL(
`/login?redirectTo=${encodeURIComponent(request.url)}`,
diff --git a/frontend/next.config.ts b/frontend/next.config.ts
index de9111d..1bf2e6b 100644
--- a/frontend/next.config.ts
+++ b/frontend/next.config.ts
@@ -1,8 +1,17 @@
import type { NextConfig } from "next";
+const apiUrl =
+ process.env.NODE_ENV !== "production"
+ ? `http://localhost:${process.env.BACKEND_PORT ?? 3001}`
+ : `https://${process.env.SERVER_NAME}/api`;
+
const nextConfig: NextConfig = {
/* config options here */
output: "standalone",
+ // webpack: (config) => {
+ // config.resolve.alias["@"] = path.resolve(__dirname, "./");
+ // return config;
+ // },
images: {
remotePatterns: [
{
@@ -13,6 +22,7 @@ const nextConfig: NextConfig = {
},
env: {
NEXT_PUBLIC_BACKEND_PORT: process.env.BACKEND_PORT,
+ NEXT_PUBLIC_API_URL: apiUrl,
},
};
diff --git a/init.py b/init.py
new file mode 100644
index 0000000..e639a94
--- /dev/null
+++ b/init.py
@@ -0,0 +1,84 @@
+import re
+import os
+
+# Define template and output file paths
+TEMPLATE_FILE = ".env.template"
+OUTPUT_FILE = ".env"
+
+def load_template(template_path):
+ """
+ Load the .env.template file.
+ """
+ if not os.path.exists(template_path):
+ raise FileNotFoundError(f"Template file '{template_path}' not found.")
+
+ with open(template_path, 'r') as file:
+ return file.readlines()
+
+def parse_variable(line):
+ """
+ Extract the variable name and default value from a template line.
+ """
+ match = re.match(r"(.*?)\$\{([^}]+)\}(.*)", line)
+ if match:
+ prefix, var_value, suffix = match.groups()
+
+ # Extract variable name and default value (if any)
+ var_name, default_value = (var_value.split(":-") + [""])[:2]
+ return prefix, var_name, default_value, suffix
+ return None, None, None, None
+
+def prompt_variable(var_name, default_value):
+ """
+ Prompt the user to input a value for the variable, using a default if no input is provided.
+ """
+ user_input = input(f"Enter value for {var_name} [default: {default_value}]: ").strip()
+ return user_input if user_input else default_value
+
+def generate_env(template_lines):
+ """
+ Generate the .env file content by substituting variables from the template.
+ """
+ output_lines = ["# Generated .env file\n"]
+ for line in template_lines:
+ # Skip comments and empty lines
+ if line.strip().startswith("#") or not line.strip():
+ output_lines.append(line)
+ continue
+
+ # Parse and process variables
+ prefix, var_name, default_value, suffix = parse_variable(line)
+ if var_name:
+ # Get the default value from the template (already handled in the parsing)
+ value = prompt_variable(var_name, default_value)
+ output_lines.append(f"{prefix}{value}{suffix}\n")
+ else:
+ # Unprocessed line (e.g., no variables)
+ output_lines.append(line)
+
+ return output_lines
+
+def write_env(output_path, lines):
+ """
+ Write the generated .env file content to the output file.
+ """
+ with open(output_path, 'w') as file:
+ file.writelines(lines)
+ print(f".env file has been successfully created at '{output_path}'.")
+
+def main():
+ try:
+ # Load the template file
+ template_lines = load_template(TEMPLATE_FILE)
+
+ # Generate the .env content
+ output_lines = generate_env(template_lines)
+
+ # Write the content to the .env file
+ write_env(OUTPUT_FILE, output_lines)
+
+ except Exception as e:
+ print(f"Error: {e}")
+
+if __name__ == "__main__":
+ main()
diff --git a/init.sh b/init.sh
deleted file mode 100755
index 05604a9..0000000
--- a/init.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/sh
-printf "ENVIRONMENT=DEV\nPOSTGRES_USER=\nPOSTGRES_PASSWORD=\nPOSTGRES_DB=\n#\nDocker\ninner\nport\ncontainer\nPOSTGRES_DOCKER_PORT=5432\nBACKEND_DOCKER_PORT=3000\nFRONTEND_DOCKER_PORT=3000\nPOSTGRES_PORT=5432\nBACKEND_PORT=3001\nFRONTEND_PORT=3000\n" > .env
-ln $(pwd)/.env $(pwd)/backend
-ln $(pwd)/.env $(pwd)/frontend
diff --git a/nginx.conf b/nginx.conf
deleted file mode 100644
index 198bdb4..0000000
--- a/nginx.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-server {
- server_name TO BE SET;
-
- location / {
- proxy_pass http://localhost:FRONTEND_PORT; # Set frontend port based on what you have exposed
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- }
-}
diff --git a/nginx/default.conf b/nginx/default.conf
new file mode 100644
index 0000000..0764da9
--- /dev/null
+++ b/nginx/default.conf
@@ -0,0 +1,20 @@
+server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ proxy_pass http://latosa-frontend:3000; # Set frontend port based on what you have exposed
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
+ location /api {
+ proxy_pass http://latosa-backend:3001; # Set frontend port based on what you have exposed
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+}
diff --git a/nginx/default.conf.template b/nginx/default.conf.template
new file mode 100644
index 0000000..e507f9e
--- /dev/null
+++ b/nginx/default.conf.template
@@ -0,0 +1,20 @@
+server {
+ listen 80;
+ server_name ${SERVER_NAME};
+
+ location / {
+ proxy_pass http://${FRONTEND_HOSTNAME}:${FRONTEND_PORT}; # Set frontend port based on what you have exposed
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
+ location /api {
+ proxy_pass http://${BACKEND_HOSTNAME}:${BACKEND_PORT}; # Set frontend port based on what you have exposed
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+}