diff --git a/back/Dockerfile b/back/Dockerfile index 6f40538..a469405 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -21,10 +21,11 @@ FROM scratch # Copy /nix/store and the built result COPY --from=builder /tmp/nix-store-closure /nix/store COPY --from=builder /tmp/build/result /app +COPY --from=builder /tmp/build/back/config.toml /app/config.toml # Expose server port and run ENV PORT=8080 WORKDIR /app EXPOSE 8080 # Pass "dev" to enable the CORS branch in app.main -CMD ["/app/bin/area", "dev"] +CMD ["/app/bin/area", "run"] diff --git a/back/app/main.py b/back/app/main.py index 17bb1a1..2577a06 100644 --- a/back/app/main.py +++ b/back/app/main.py @@ -33,4 +33,4 @@ async def lifespan(_: FastAPI): def main(): - uvicorn.run(app, host="127.0.0.1", port=8080) + uvicorn.run(app, host="0.0.0.0", port=8080) diff --git a/docker-compose.yml b/docker-compose.yml index b5edab1..4abe949 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,38 +1,45 @@ services: + client_mobile: + build: + context: front + dockerfile: ./android/Dockerfile + volumes: + - shared-artifacts:/shared + # Optional: wait for a short while on first run to produce the APK + healthcheck: + test: ["CMD", "test", "-f", "/shared/client.apk"] + interval: 10s + timeout: 5s + retries: 30 + server: build: context: . dockerfile: back/Dockerfile + networks: + - backToFront ports: - "8080:8080" working_dir: /app - volumes: - - ./back/config.toml:/app/config.toml:ro - - # client_mobile: - # build: - # context: . - # dockerfile: front/android/Dockerfile - # volumes: - # - shared-artifacts:/shared - # # Optional: wait for a short while on first run to produce the APK - # healthcheck: - # test: ["CMD", "test", "-f", "/shared/client.apk"] - # interval: 10s - # timeout: 5s - # retries: 30 client_web: build: - context: . - dockerfile: front/Dockerfile + context: front + dockerfile: ./Dockerfile depends_on: - server: condition: service_started + client_mobile: + condition: service_completed_successfully + networks: + - backToFront ports: - - "8081:8081" + - "8081:80" volumes: - - ./shared-artifacts:/app/share/www + - shared-artifacts:/shared/:ro +volumes: + shared-artifacts: +networks: + backToFront: diff --git a/front/.gitignore b/front/.gitignore index 65b27d6..f716dd0 100644 --- a/front/.gitignore +++ b/front/.gitignore @@ -6,3 +6,4 @@ node_modules dist dist-ssr *.local +*.jks diff --git a/front/Dockerfile b/front/Dockerfile index 0a8e887..ebcf49e 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -1,27 +1,33 @@ -# Nix builder -FROM nixos/nix:latest AS builder +FROM node:22-bookworm-slim AS build -# Copy our source and setup our working dir. -COPY .. /tmp/build -WORKDIR /tmp/build +ENV DEBIAN_FRONTEND=noninteractive -# Build our Nix environment (front-web helper) -RUN nix \ - --extra-experimental-features "nix-command flakes" \ - --option filter-syscalls false \ - build .#front +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* -# Copy the Nix store closure into a directory. -RUN mkdir /tmp/nix-store-closure -RUN cp -R $(nix-store -qR result/) /tmp/nix-store-closure +RUN corepack enable && corepack prepare pnpm@latest --activate -# Final image is based on scratch. -FROM scratch +RUN npm install -g serve -# Copy /nix/store and the built result -COPY --from=builder /tmp/nix-store-closure /nix/store -COPY --from=builder /tmp/build/result /app +WORKDIR /app -# Expose client_web port and run -EXPOSE 8081 -CMD ["/app/bin/web"] +COPY package.json pnpm-lock.yaml ./ + +ENV CI=true +RUN pnpm install --frozen-lockfile + +COPY . . + +RUN pnpm build:web + +FROM nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose to 80 and remap it in compose since nginx defaults to 80 without parameters possible +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/front/android/.gitignore b/front/android/.gitignore index 4bf83a8..86c68a7 100644 --- a/front/android/.gitignore +++ b/front/android/.gitignore @@ -12,6 +12,7 @@ out/ .gradle/ build/ local.properties +gradle.properties *.log diff --git a/front/android/Dockerfile b/front/android/Dockerfile new file mode 100644 index 0000000..b2545b1 --- /dev/null +++ b/front/android/Dockerfile @@ -0,0 +1,58 @@ +FROM node:20-bookworm-slim + +# --- System Dependencies --- +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + bash curl unzip git ca-certificates && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# --- Install OpenJDK 21 (Temurin) --- +RUN curl -L https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.9+10/OpenJDK21U-jdk_x64_linux_hotspot_21.0.9_10.tar.gz \ + -o /tmp/jdk21.tar.gz && \ + mkdir -p /usr/lib/jvm && \ + tar -xzf /tmp/jdk21.tar.gz -C /usr/lib/jvm && \ + rm /tmp/jdk21.tar.gz && \ + ln -s /usr/lib/jvm/jdk-21*/bin/java /usr/bin/java && \ + ln -s /usr/lib/jvm/jdk-21*/bin/javac /usr/bin/javac + +ENV JAVA_HOME=/usr/lib/jvm/jdk-21.0.9+10/ +ENV PATH="$JAVA_HOME/bin:$PATH" + + +# --- Install Android SDK --- +ENV ANDROID_SDK_ROOT="/sdk" \ + ANDROID_HOME="/sdk" \ + PATH="$PATH:/sdk/cmdline-tools/bin:/sdk/platform-tools" + +RUN mkdir /sdk && \ + curl -s https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -o /cmdline-tools.zip && \ + unzip /cmdline-tools.zip -d /sdk/ && \ + rm /cmdline-tools.zip && \ + mkdir -p /sdk/cmdline-tools/latest && \ + mv /sdk/cmdline-tools/* /sdk/cmdline-tools/latest/ || true && \ + yes | /sdk/cmdline-tools/latest/bin/sdkmanager --sdk_root=/sdk --install \ + "platform-tools" "platforms;android-35" "build-tools;35.0.0" "cmdline-tools;latest" + +# --- Install Gradle --- +RUN curl -sL https://services.gradle.org/distributions/gradle-8.10-bin.zip -o gradle.zip && \ + mkdir /opt/gradle && \ + unzip gradle.zip -d /opt/gradle && \ + rm gradle.zip +ENV PATH="/opt/gradle/gradle-8.10/bin:$PATH" + +# --- Install pnpm --- +RUN npm install -g pnpm + +# --- Web Build --- +WORKDIR /build +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +COPY . . +RUN pnpm run build:web +RUN npx cap sync android + +# --- Prepare Android Build --- +RUN chmod +x /build/entrypoint.sh + +CMD ["bash", "entrypoint.sh"] diff --git a/front/android/app/build.gradle b/front/android/app/build.gradle index 55c89ad..c66e170 100644 --- a/front/android/app/build.gradle +++ b/front/android/app/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'com.android.application' android { namespace "io.github.sigmapitech" compileSdk rootProject.ext.compileSdkVersion + defaultConfig { applicationId "io.github.sigmapitech" minSdkVersion rootProject.ext.minSdkVersion @@ -13,15 +14,26 @@ android { ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' } } + + signingConfigs { + release { + storeFile file(RELEASE_STORE_FILE) + storePassword RELEASE_STORE_PASSWORD + keyAlias RELEASE_KEY_ALIAS + keyPassword RELEASE_KEY_PASSWORD + } + } + buildTypes { release { minifyEnabled false + signingConfig signingConfigs.release } } } repositories { - flatDir{ + flatDir { dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' } } diff --git a/front/android/gradle.properties b/front/android/gradle.properties deleted file mode 100644 index 2e87c52..0000000 --- a/front/android/gradle.properties +++ /dev/null @@ -1,22 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true diff --git a/front/entrypoint.sh b/front/entrypoint.sh new file mode 100644 index 0000000..1043c49 --- /dev/null +++ b/front/entrypoint.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Output dir +OUTPUT_DIR=/shared +APK_NAME=client.apk + +# Ensure output folder exist +mkdir -p $OUTPUT_DIR +npx cap sync android +cd android +# Clean previous build +./gradlew clean + +# Sync dependencies +./gradlew build --no-daemon --refresh-dependencies + +# Build project for release +./gradlew assembleRelease + +# Copy apk to output dir +cp /build/android/app/build/outputs/apk/release/app-release.apk $OUTPUT_DIR/$APK_NAME + +# Ensure build success +if [ -f "$OUTPUT_DIR/$APK_NAME" ]; then + echo "APK successfully generated : $OUTPUT_DIR/$APK_NAME" +else + echo "APK generation failed." + exit 1 +fi diff --git a/front/nginx.conf b/front/nginx.conf new file mode 100644 index 0000000..00b072f --- /dev/null +++ b/front/nginx.conf @@ -0,0 +1,24 @@ +server { + listen 80; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri /index.html =404; + } + + location /api/ { + proxy_pass http://server:8080/; + proxy_set_header Host $host; + } + + location /client.apk { + alias /shared/client.apk; + } + + location /shared/ { + alias /shared/; + autoindex on; + } +} diff --git a/front/src/api_url.ts b/front/src/api_url.ts index 51e40d0..95b0033 100644 --- a/front/src/api_url.ts +++ b/front/src/api_url.ts @@ -1 +1,3 @@ -export const API_BASE_URL = "http://127.0.0.1:8080"; +export const API_BASE_URL = import.meta.env.PROD + ? "http://localhost:8081/api" + : "http://localhost:8080"; diff --git a/front/src/routes/login/index.tsx b/front/src/routes/login/index.tsx index a23e584..f86c90e 100644 --- a/front/src/routes/login/index.tsx +++ b/front/src/routes/login/index.tsx @@ -57,7 +57,7 @@ export default function LoginPage() { const { email, password } = formData; handleFormSubmit({ - url: `${API_BASE_URL}/auth/login/`, + url: `${API_BASE_URL}/auth/login`, body: { email, password }, onSuccess: (data) => { login(data.token); diff --git a/front/src/routes/register/index.tsx b/front/src/routes/register/index.tsx index da79af6..321b53d 100644 --- a/front/src/routes/register/index.tsx +++ b/front/src/routes/register/index.tsx @@ -94,7 +94,7 @@ export default function RegisterPage() { } handleFormSubmit({ - url: `${API_BASE_URL}/auth/register/`, + url: `${API_BASE_URL}/auth/register`, body: { email, name, password }, onSuccess: (data) => { login(data.token); diff --git a/front/vite-env.d.ts b/front/vite-env.d.ts index c934b98..c555498 100644 --- a/front/vite-env.d.ts +++ b/front/vite-env.d.ts @@ -2,4 +2,12 @@ /// +interface ImportMetaEnv { + readonly PROD: boolean; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} + declare const __APP_PLATFORM__: "mobile" | "web";