diff --git a/.env.example b/.env.example
index b86b39a..2f46d8c 100644
--- a/.env.example
+++ b/.env.example
@@ -1 +1,8 @@
-VITE_PORT=8081
\ No newline at end of file
+VITE_PORT=8081
+
+# Server database environment variables
+DB_NAME=area
+DB_PASSWORD=change-me
+DB_HOST=mariadb
+DB_PORT=3306
+DB_USER=root
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index e4c9141..93ed00d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,3 +136,5 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
+
+ssl/
diff --git a/Makefile b/Makefile
index 35c5e34..f9aec34 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ TARGET_MAX_CHAR_NUM=20
.PHONY: start build stop restart reset logs clean help
-PROJECT_IMAGES = area-client-web area-client-mobile
+PROJECT_IMAGES = area-client-web area-client-mobile area-server mariadb rabbitmq
## Show help
help:
@@ -56,4 +56,16 @@ logs:
## Clean up containers, images, volumes and orphans
clean:
- docker compose down --rmi local -v --remove-orphans
\ No newline at end of file
+ docker compose down --rmi local -v --remove-orphans
+
+# Flutter mobile client commands
+flutter-build:
+ docker build -t flutter-app ./client_mobile
+
+flutter-run:
+ docker run -it \
+ --network host \
+ -v $(PWD)/client_mobile:/app \
+ -v /tmp/.X11-unix:/tmp/.X11-unix \
+ -e DISPLAY=${DISPLAY} \
+ flutter-app
\ No newline at end of file
diff --git a/README.md b/README.md
index fc47963..2560090 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,11 @@ With AREA, you can create automated workflows that integrate various services an
## Table of Contents
- [Getting Started](#getting-started)
- - [Prerequisites](#prerequisites)
- - [Installation & Usage](#installation--usage)
+ - [Prerequisites](#prerequisites)
+ - [Installation & Usage](#installation--usage)
- [Documentation](#documentation)
- - [Requirements](#requirements)
- - [Usage](#usage)
+ - [Requirements](#requirements)
+ - [Usage](#usage)
- [Tests](#tests)
- [License](#license)
- [Contributors](#contributors)
@@ -19,9 +19,8 @@ With AREA, you can create automated workflows that integrate various services an
### Prerequisites
-- vite js
-- go
- docker
+- make
### Installation & Usage
@@ -29,40 +28,30 @@ With AREA, you can create automated workflows that integrate various services an
Click to expand
1. Clone the repo
+
```sh
git clone git@github.com:ASM-Studios/AREA.git
```
2. Create .env files
+
- Run the following command to create private env files
+
```sh
cp .env.example .env
+cp server/.env.server.example server/.env.server
cp client_web/.env.local.example .env.local
cp client_mobile/.env.mobile.example .env.mobile
```
+
- Fill the .env, .env.web and .env.mobile files
-3. Install NPM packages
-```sh
-cd AREA/client-web
-npm install
-```
+4. Run the project
-3. Install Go packages
```sh
-cd AREA/server
-
+make start
```
-4. Run the project
-```sh
-cd AREA/client-web
-npm run start
-```
-```sh
-cd AREA/server
-go run ./...
-```
### Documentation
@@ -87,6 +76,7 @@ The documentation is automatically built and deployed to GitHub Pages when a pus
You can consult the documentation online at [AREA Documentation](https://asm-studios.github.io/AREA/).
You can build the documentation locally by running the following command:
+
```sh
cd AREA/docs
make docs
diff --git a/client_mobile/.env.mobile.example b/client_mobile/.env.mobile.example
index 965d1d9..e538184 100644
--- a/client_mobile/.env.mobile.example
+++ b/client_mobile/.env.mobile.example
@@ -1,17 +1,3 @@
-VITE_PORT=8081
-VITE_ENDPOINT=http://localhost:8080
-
-VITE_GOOGLE_CLIENT_ID=
-VITE_GOOGLE_CLIENT_SECRET=
-
-VITE_MICROSOFT_CLIENT_ID=
-
-VITE_LINKEDIN_CLIENT_ID=
-VITE_LINKEDIN_CLIENT_SECRET=
-
-VITE_SPOTIFY_CLIENT_ID=
-VITE_SPOTIFY_CLIENT_SECRET=
-
# Server URLs
API_URL=http://localhost:8080
WEB_CLIENT_URL=http://localhost:8081
diff --git a/client_mobile/Dockerfile b/client_mobile/Dockerfile
index 778bcff..824acdd 100644
--- a/client_mobile/Dockerfile
+++ b/client_mobile/Dockerfile
@@ -1,26 +1,22 @@
-FROM ghcr.io/cirruslabs/flutter:stable
+FROM ghcr.io/cirruslabs/flutter:3.24.5 AS builder
WORKDIR /app
-ARG VITE_PORT
-ARG VITE_ENDPOINT
-ARG VITE_GOOGLE_CLIENT_ID
-ARG VITE_GOOGLE_CLIENT_SECRET
-ARG VITE_MICROSOFT_CLIENT_ID
-ARG VITE_LINKEDIN_CLIENT_ID
-ARG VITE_LINKEDIN_CLIENT_SECRET
-ARG VITE_SPOTIFY_CLIENT_ID
-ARG VITE_SPOTIFY_CLIENT_SECRET
+RUN git config --system --add safe.directory /sdks/flutter && \
+ git config --system --add safe.directory /app && \
+ chmod -R 777 /sdks/flutter
+
+COPY pubspec.* ./
+
+RUN flutter pub get
+
+COPY . .
+
ARG API_URL
ARG WEB_CLIENT_URL
ARG MOBILE_CLIENT_URL
ARG GITHUB_CLIENT_ID
ARG GITHUB_CLIENT_SECRET
-COPY . .
-
-RUN flutter pub get
RUN flutter build apk --release
-
-RUN mv build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/client.apk
-RUN chmod -R 755 build/app/outputs/flutter-apk/
\ No newline at end of file
+RUN mv build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/client.apk
\ No newline at end of file
diff --git a/client_mobile/pubspec.yaml b/client_mobile/pubspec.yaml
index a5640fa..248ced5 100644
--- a/client_mobile/pubspec.yaml
+++ b/client_mobile/pubspec.yaml
@@ -19,7 +19,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
- sdk: '>=3.4.1 <4.0.0'
+ sdk: '^3.5.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
diff --git a/client_web/Dockerfile b/client_web/Dockerfile
index 2d06b21..cbc4058 100644
--- a/client_web/Dockerfile
+++ b/client_web/Dockerfile
@@ -1,25 +1,26 @@
###----------------------- Certificate generation stage -----------------------###
-FROM alpine:3.19 AS cert-builder
+FROM alpine:3.20.3 AS cert-builder
-# Install mkcert dependencies
-RUN apk add --no-cache \
- curl \
- nss \
- nss-tools
-
-# Install mkcert
-RUN curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" \
- && chmod +x mkcert-v*-linux-amd64 \
- && mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert \
- && mkcert -install \
- && mkcert localhost
+RUN apk add --no-cache openssl
+RUN mkdir -p /etc/nginx/ssl && \
+ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
+ -keyout /etc/nginx/ssl/private.key \
+ -out /etc/nginx/ssl/certificate.crt \
+ -subj "/C=FR/ST=Paris/L=Paris/O=Area/OU=IT/CN=localhost" \
+ -addext "subjectAltName = DNS:localhost" && \
+ chmod 644 /etc/nginx/ssl/certificate.crt /etc/nginx/ssl/private.key
###----------------------- Build stage for Node.js application -----------------------###
-FROM node:latest AS builder
+FROM node:20-alpine AS builder
WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+
+COPY . .
+
ARG VITE_PORT
ARG VITE_ENDPOINT
ARG VITE_GOOGLE_CLIENT_ID
@@ -35,20 +36,33 @@ ARG MOBILE_CLIENT_URL
ARG GITHUB_CLIENT_ID
ARG GITHUB_CLIENT_SECRET
-COPY ./package*.json ./
-RUN npm install
-COPY . .
-
RUN npm run build
###----------------------- Production stage -----------------------###
-FROM nginx:alpine AS production
+FROM nginx:1.25.3-alpine
-COPY --from=builder /app/dist /usr/share/nginx/html
-COPY ./nginx.conf /etc/nginx/conf.d/default.conf
-RUN mkdir -p /usr/share/nginx/html/mobile_builds
+ARG VITE_PORT
+
+RUN adduser -D nginxuser && \
+ mkdir -p /usr/share/nginx/html/mobile_builds && \
+ mkdir -p /etc/nginx/ssl && \
+ chown -R nginxuser:nginxuser /usr/share/nginx/html && \
+ chown -R nginxuser:nginxuser /etc/nginx/ssl && \
+ chown -R nginxuser:nginxuser /var/cache/nginx && \
+ chown -R nginxuser:nginxuser /var/log/nginx && \
+ touch /var/run/nginx.pid && \
+ chown -R nginxuser:nginxuser /var/run/nginx.pid
+
+COPY --from=cert-builder --chown=nginxuser:nginxuser /etc/nginx/ssl /etc/nginx/ssl
+COPY --from=builder --chown=nginxuser:nginxuser /app/dist /usr/share/nginx/html
+COPY --chown=nginxuser:nginxuser ./nginx.conf /etc/nginx/conf.d/default.conf
+
+USER nginxuser
EXPOSE ${VITE_PORT}
+HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
+ CMD wget --no-verbose --tries=1 --spider http://localhost:${VITE_PORT}/health || exit 1
+
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
diff --git a/client_web/nginx.conf b/client_web/nginx.conf
index 036ee9a..32e8d6e 100644
--- a/client_web/nginx.conf
+++ b/client_web/nginx.conf
@@ -1,7 +1,12 @@
server {
- listen 8081;
+ listen 8081 ssl;
server_name localhost;
+ ssl_certificate /etc/nginx/ssl/certificate.crt;
+ ssl_certificate_key /etc/nginx/ssl/private.key;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
location / {
root /usr/share/nginx/html;
index index.html index.htm;
diff --git a/client_web/vite.config.ts b/client_web/vite.config.ts
index 1371208..42b73cd 100644
--- a/client_web/vite.config.ts
+++ b/client_web/vite.config.ts
@@ -1,6 +1,5 @@
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
-import fs from 'fs'
import path from 'path'
export default defineConfig(({ mode }) => {
@@ -10,10 +9,6 @@ export default defineConfig(({ mode }) => {
plugins: [react()],
server: {
port: parseInt(env.VITE_PORT) || 8081,
- https: {
- key: fs.readFileSync(path.resolve(__dirname, 'localhost-key.pem')),
- cert: fs.readFileSync(path.resolve(__dirname, 'localhost.pem')),
- },
},
resolve: {
alias: {
diff --git a/docker-compose.yml b/docker-compose.yml
index f8dde58..7fa6411 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,27 +1,81 @@
services:
+ rabbitmq:
+ image: rabbitmq:4.0.4-management-alpine
+ ports:
+ - "8082:15672"
+ - "5000:5673"
+ networks:
+ - area_network
+ volumes:
+ - ./rabbit-mq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro
+ healthcheck:
+ test: [ "CMD", "rabbitmqctl", "status" ]
+ interval: 5s
+ timeout: 15s
+ retries: 5
+ restart: unless-stopped
+
+ mariadb:
+ image: mariadb:11.4.4
+ ports:
+ - "3306:3306"
+ environment:
+ MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
+ MYSQL_DATABASE: ${DB_NAME}
+ MYSQL_ROOT_HOST: "%"
+ volumes:
+ - mariadb_data:/var/lib/mysql
+ - ./server/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
+ networks:
+ - area_network
+ healthcheck:
+ test: [ "CMD", "mariadb-admin", "ping", "-h", "localhost", "-u", "root", "-p${DB_PASSWORD}" ]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ env_file:
+ - .env
+ restart: unless-stopped
+
+ area-server:
+ build:
+ context: ./server
+ dockerfile: Dockerfile
+ ports:
+ - "8080:8080"
+ volumes:
+ - ./ssl:/app/ssl:ro
+ environment:
+ DB_HOST: ${DB_HOST}
+ DB_PORT: ${DB_PORT}
+ DB_USER: ${DB_USER}
+ DB_NAME: ${DB_NAME}
+ DB_PASSWORD: ${DB_PASSWORD}
+ depends_on:
+ mariadb:
+ condition: service_healthy
+ rabbitmq:
+ condition: service_healthy
+ networks:
+ - area_network
+ env_file:
+ - server/.env.server
+ restart: unless-stopped
+
area-client-mobile:
build:
context: ./client_mobile
dockerfile: Dockerfile
args:
- - VITE_PORT
- - VITE_ENDPOINT
- - VITE_GOOGLE_CLIENT_ID
- - VITE_GOOGLE_CLIENT_SECRET
- - VITE_MICROSOFT_CLIENT_ID
- - VITE_LINKEDIN_CLIENT_ID
- - VITE_LINKEDIN_CLIENT_SECRET
- - VITE_SPOTIFY_CLIENT_ID
- - VITE_SPOTIFY_CLIENT_SECRET
- API_URL
- WEB_CLIENT_URL
- MOBILE_CLIENT_URL
- GITHUB_CLIENT_ID
- GITHUB_CLIENT_SECRET
volumes:
- - area-client-data:/app/build/app/outputs/flutter-apk
+ - area_client_data:/app/build/app/outputs/flutter-apk
networks:
- - area-network
+ - area_network
env_file:
- ./client_mobile/.env.mobile
@@ -47,17 +101,21 @@ services:
ports:
- "${VITE_PORT}:${VITE_PORT}"
volumes:
- - area-client-data:/usr/share/nginx/html/mobile_builds
+ - area_client_data:/usr/share/nginx/html/mobile_builds:ro
depends_on:
- area-client-mobile
+ - area-server
networks:
- - area-network
+ - area_network
env_file:
- ./client_web/.env.local
+ restart: unless-stopped
volumes:
- area-client-data:
+ area_client_data:
+ mariadb_data:
networks:
- area-network:
+ area_network:
+ driver: bridge
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..a268295
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,5 @@
+dependencies:
+ flutter:
+ sdk: flutter
+ flutter_dotenv: ^5.2.1
+ go_router: ^14.6.1
\ No newline at end of file
diff --git a/server/.env.example b/server/.env.example
deleted file mode 100644
index 510adf3..0000000
--- a/server/.env.example
+++ /dev/null
@@ -1,7 +0,0 @@
-SECRET_KEY=
-DB_HOST=
-DB_PORT=
-DB_NAME=
-DB_USER=
-DB_PASSWORD=
-RMQ_URL=
diff --git a/server/.env.server.example b/server/.env.server.example
new file mode 100644
index 0000000..d544f4a
--- /dev/null
+++ b/server/.env.server.example
@@ -0,0 +1,7 @@
+SECRET_KEY="change-this-secret-key"
+DB_HOST=localhost
+DB_PORT=3306
+DB_NAME=area
+DB_USER=root
+DB_PASSWORD=change-me
+RMQ_URL="amqp://root:root@localhost:5672/"
\ No newline at end of file
diff --git a/server/.gitignore b/server/.gitignore
new file mode 100644
index 0000000..796fa7f
--- /dev/null
+++ b/server/.gitignore
@@ -0,0 +1,2 @@
+.env
+.env.server
diff --git a/server/Dockerfile b/server/Dockerfile
index cc75960..dbe5521 100644
--- a/server/Dockerfile
+++ b/server/Dockerfile
@@ -1,22 +1,36 @@
-FROM golang:1.23.3-alpine as builder
+FROM golang:1.23.4-alpine3.20 AS builder
+
+RUN apk add --no-cache gcc musl-dev
+
WORKDIR /app
-COPY . .
-RUN go mod tidy
+COPY go.mod go.sum ./
+
RUN go mod download
-RUN go get -u github.com/swaggo/swag
-RUN go get -u github.com/gin-gonic/gin
-RUN go build -o main .
+COPY . .
+
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
-FROM debian:bullseye-slim
+FROM alpine:3.20.3
+
+RUN apk add --no-cache ca-certificates && \
+ adduser -D appuser
WORKDIR /app
+
COPY --from=builder /app/main .
-COPY --from=builder /app/.env .
COPY --from=builder /app/config.json .
+COPY .env.server .env
+
+RUN chown -R appuser:appuser /app && \
+ chmod +x /app/main
-RUN chmod +x /app/main
+USER appuser
EXPOSE 8080
+
+HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
+
CMD ["./main"]
diff --git a/server/build/docker-compose.yml b/server/build/docker-compose.yml
deleted file mode 100644
index a3aeff1..0000000
--- a/server/build/docker-compose.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-services:
- rabbitmq:
- image: rabbitmq:3-management
- ports:
- - "8082:15672"
- - "5000:5673"
- networks:
- - app_network
- volumes:
- - ./rabbit-mq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
- healthcheck:
- test: [ "CMD", "rabbitmqctl", "status" ]
- interval: 5s
- timeout: 15s
- retries: 5
-
- mariadb:
- image: mariadb:10.4
- ports:
- - "3306:3306"
- environment:
- MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
- MYSQL_DATABASE: ${DB_NAME}
- volumes:
- - mariadb_data:/var/lib/mysql
- networks:
- - app_network
- healthcheck:
- test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
- interval: 10s
- timeout: 5s
- retries: 5
-
- go-app:
- build:
- context: ../.
- dockerfile: Dockerfile
- ports:
- - "8080:8080"
- environment:
- DB_HOST: mariadb
- DB_PORT: 3306
- DB_NAME: ${DB_NAME}
- DB_USER: root
- DB_PASSWORD: ${DB_PASSWORD}
- SECRET_KEY: ${SECRET_KEY}
- depends_on:
- mariadb:
- condition: service_healthy
- rabbitmq:
- condition: service_healthy
- networks:
- - app_network
-
-volumes:
- mariadb_data:
-
-networks:
- app_network:
- driver: bridge
\ No newline at end of file
diff --git a/server/init.sql b/server/init.sql
new file mode 100644
index 0000000..ea08740
--- /dev/null
+++ b/server/init.sql
@@ -0,0 +1,6 @@
+CREATE DATABASE IF NOT EXISTS area;
+USE area;
+
+-- Grant all privileges to root user from any host
+GRANT ALL PRIVILEGES ON area.* TO 'root'@'%' IDENTIFIED BY 'root';
+FLUSH PRIVILEGES;
\ No newline at end of file
diff --git a/server/main.go b/server/main.go
index bfb0bef..cd03209 100644
--- a/server/main.go
+++ b/server/main.go
@@ -8,6 +8,7 @@ import (
"fmt"
"github.com/gin-gonic/gin"
"log"
+ "net/http"
"strconv"
)
@@ -36,7 +37,13 @@ func main() {
router := routers.SetupRouter()
port := strconv.Itoa(config.AppConfig.Port)
log.Printf("Starting %s on port %s in %s mode", config.AppConfig.AppName, port, config.AppConfig.GinMode)
- if err := router.Run(fmt.Sprintf(":%s", port)); err != nil {
- log.Fatalf("Failed to start server: %v", err)
+
+ server := &http.Server{
+ Addr: fmt.Sprintf(":%s", port),
+ Handler: router,
+ }
+
+ if err := server.ListenAndServe(); err != nil {
+ log.Printf("Server error: %v", err)
}
}
diff --git a/server/start_server.sh b/server/start_server.sh
deleted file mode 100755
index 257b7b0..0000000
--- a/server/start_server.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#! /bin/bash
-
-# Start the server
-COMPOSE_FILE=build/docker-compose.yml
-ENV_FILE=.env
-
-if command -v docker-compose &> /dev/null
-then
- docker-compose --env-file $ENV_FILE -f $COMPOSE_FILE -p server up --build -d
-else
- docker compose --env-file $ENV_FILE -f $COMPOSE_FILE -p server up --build -d
-fi
diff --git a/server/stop_server.sh b/server/stop_server.sh
deleted file mode 100755
index f703b8f..0000000
--- a/server/stop_server.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#! /bin/bash
-
-# Stop the server
-COMPOSE_FILE=build/docker-compose.yml
-ENV_FILE=.env
-
-if command -v docker-compose &> /dev/null
-then
- docker-compose --env-file $ENV_FILE -f $COMPOSE_FILE down --remove-orphans
-else
- docker compose --env-file $ENV_FILE -f $COMPOSE_FILE down --remove-orphans
-fi