Skip to content
Draft
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
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ NEXT_PUBLIC_API_BASE_URL=http://localhost:3001/api

# Optional
## Environment
APP_ENV=development
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_APP_GIT_SHORT_SHA=$(git rev-parse --short=7 HEAD)
PORT=3000
CI=false

Expand Down
34 changes: 31 additions & 3 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@
branches:
- main
tags:
- 'v*'
- "v*"

Check failure on line 8 in .github/workflows/cd.yml

View workflow job for this annotation

GitHub Actions / Lint & Type Check

Strings must use singlequote
pull_request:
branches:
- main
workflow_dispatch:
inputs:
environment:
description: Target environment
required: true
type: choice
options:
- staging
- dev
- prod

env:
REGISTRY: ghcr.io
Expand All @@ -17,6 +27,7 @@
jobs:
docker:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
permissions:
contents: read
packages: write
Expand All @@ -33,8 +44,12 @@
type=ref,event=pr,prefix=pr-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=main-,format=short,enable={{is_default_branch}}
type=raw,value=latest,enable={{is_default_branch}}
type=sha,prefix=main-,format=short,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
type=sha,prefix=staging-,format=short,enable=${{ inputs.environment == 'staging' }}
type=sha,prefix=dev-,format=short,enable=${{ inputs.environment == 'dev' }}
type=raw,value=latest,enable=${{ inputs.environment == 'prod' }}
type=raw,value=staging,enable=${{ inputs.environment == 'staging' }}
type=raw,value=dev,enable=${{ inputs.environment == 'dev' }}

- name: Login to Registry
uses: docker/login-action@v3
Expand All @@ -48,6 +63,18 @@
shell: bash
run: echo "SHORT_SHA=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_ENV"

- name: Set API base URL
id: api-url
shell: bash
run: |
if [ "${{ inputs.environment }}" = "staging" ]; then
echo "url=https://planifets.staging.cedille.club" >> "$GITHUB_OUTPUT"
elif [ "${{ inputs.environment }}" = "dev" ]; then
echo "url=https://planifets.dev.cedille.club" >> "$GITHUB_OUTPUT"
else
echo "url=https://planifets.prodv2.cedille.club" >> "$GITHUB_OUTPUT"
fi

- name: Build and push
uses: docker/build-push-action@v5
with:
Expand All @@ -58,6 +85,7 @@
labels: ${{ steps.meta.outputs.labels }}
build-args: |
NEXT_PUBLIC_APP_GIT_SHORT_SHA=${{ env.SHORT_SHA }}
NEXT_PUBLIC_APP_ENV=${{ inputs.environment == 'prod' && 'production' || inputs.environment || 'production' }}
NEXT_PUBLIC_API_BASE_URL=https://planifets.prodv2.cedille.club
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
NEXT_PUBLIC_POSTHOG_UI_HOST=https://us.posthog.com
Expand Down
7 changes: 5 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ RUN \
# Development
FROM base AS dev
WORKDIR /app
RUN apk add --no-cache git
COPY --from=deps /app/node_modules ./node_modules
ENV NODE_ENV=development
ENV NEXT_TELEMETRY_DISABLED=1
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["yarn", "dev"]
CMD ["sh", "-c", "export NEXT_PUBLIC_APP_GIT_SHORT_SHA=$(git rev-parse --short=7 HEAD 2>/dev/null || echo localdev) && yarn dev"]

# Rebuild the source code only when needed
FROM base AS builder
Expand All @@ -42,12 +43,14 @@ ENV NEXT_TELEMETRY_DISABLED=1

ARG NEXT_PUBLIC_API_BASE_URL
ARG NEXT_PUBLIC_APP_GIT_SHORT_SHA
ARG NEXT_PUBLIC_APP_ENV
ARG NEXT_PUBLIC_POSTHOG_HOST
ARG NEXT_PUBLIC_POSTHOG_UI_HOST
ARG NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN
ARG NEXT_PUBLIC_UMAMI_WEBSITE_ID
ENV NEXT_PUBLIC_API_BASE_URL=${NEXT_PUBLIC_API_BASE_URL}
ENV NEXT_PUBLIC_APP_GIT_SHORT_SHA=${NEXT_PUBLIC_APP_GIT_SHORT_SHA}
ENV NEXT_PUBLIC_APP_ENV=${NEXT_PUBLIC_APP_ENV}
ENV NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
ENV NEXT_PUBLIC_POSTHOG_UI_HOST=${NEXT_PUBLIC_POSTHOG_UI_HOST}
ENV NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN=${NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN}
Expand All @@ -64,7 +67,7 @@ RUN \
FROM base AS runner
WORKDIR /app

ENV APP_ENV=production
ENV NEXT_PUBLIC_APP_ENV=production
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ services:
ports:
- '${PORT:-3500}:3000'
environment:
APP_ENV: production
NEXT_PUBLIC_APP_ENV: production
NODE_ENV: production
profiles:
- production
Expand All @@ -26,8 +26,8 @@ services:
- /app/node_modules
- /app/.next
environment:
APP_ENV: development
NODE_ENV: development
NEXT_PUBLIC_API_BASE_URL: ${NEXT_PUBLIC_API_BASE_URL:-http://localhost:3001/api}
NEXT_PUBLIC_APP_ENV: ${NEXT_PUBLIC_APP_ENV:-development}
profiles:
- dev
5 changes: 1 addition & 4 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ import createNextIntlPlugin from 'next-intl/plugin';

const withNextIntl = createNextIntlPlugin();

const appEnv = process.env.APP_ENV ?? 'development';
const appEnv = process.env.NEXT_PUBLIC_APP_ENV ?? 'development';
const posthogApiHost = process.env.NEXT_PUBLIC_POSTHOG_HOST ?? 'https://us.i.posthog.com';
const posthogAssetsHost = posthogApiHost.replace(/\/\/(\w+)\./, '//$1-assets.'); // https://eu.i.posthog.com → https://eu-assets.i.posthog.com

const baseConfig: NextConfig = {
output: 'standalone',
env: {
NEXT_PUBLIC_APP_ENV: appEnv,
},
// Required for PostHog
// SDK sends requests with trailing slashes that Next.js would otherwise redirect, breaking the proxy.
skipTrailingSlashRedirect: true,
Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<html lang="en" suppressHydrationWarning>
<head>
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.webp" />
{process.env.APP_ENV !== 'development'
{process.env.NEXT_PUBLIC_APP_ENV !== 'development'
? (
<script
defer
Expand Down
32 changes: 32 additions & 0 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,33 @@

import { useTranslations } from 'next-intl';
import Image from 'next/image';
import { useEffect, useState } from 'react';
import { apiClient } from '@/api/client';
import { API_ENDPOINTS } from '@/api/endpoints';

type BackendInfo = {
gitSha: string | null;
environment: string;
};

export function Footer() {
const t = useTranslations('Footer');
const linkClasses = 'text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition-colors';
const [backendInfo, setBackendInfo] = useState<BackendInfo | null>(null);

useEffect(() => {
apiClient
.get<BackendInfo>(API_ENDPOINTS.INFO)
.then((res) => {
if (res.data) setBackendInfo(res.data);

Check failure on line 23 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

Expected { after 'if' condition
})
.catch(() => {
// silently ignore — info is non-critical
});
}, []);

const frontendSha = process.env.NEXT_PUBLIC_APP_GIT_SHORT_SHA;
const environment = process.env.NEXT_PUBLIC_APP_ENV;

return (
<footer className="bg-gray-100 text-gray-800 border-t border-gray-200 dark:bg-gray-900 dark:text-gray-100 dark:border-gray-800 not-prose" data-testid="site-footer">
Expand Down Expand Up @@ -114,6 +137,15 @@
</li>
</ul>
</div>

{/* build info band */}
<div className="max-w-6xl mx-auto px-6 pb-3 flex justify-end">
<p className="text-xs text-gray-400 dark:text-gray-600 font-mono">
{environment && <span className="mr-3">{t('environment')}: {environment}</span>}

Check failure on line 144 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`{environment}` must be placed on a new line

Check failure on line 144 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`: ` must be placed on a new line

Check failure on line 144 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`{t('environment')}` must be placed on a new line
<span className="mr-3">{t('frontend')}: {frontendSha ?? 'dev'}</span>

Check failure on line 145 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`{frontendSha ?? 'dev'}` must be placed on a new line

Check failure on line 145 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`: ` must be placed on a new line

Check failure on line 145 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`{t('frontend')}` must be placed on a new line
<span>{t('backend')}: {backendInfo ? (backendInfo.gitSha ?? 'dev') : '…'}</span>

Check failure on line 146 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`: ` must be placed on a new line

Check failure on line 146 in src/components/Footer.tsx

View workflow job for this annotation

GitHub Actions / Lint & Type Check

`{t('backend')}` must be placed on a new line
</p>
</div>
</footer>
);
}
1 change: 1 addition & 0 deletions src/lib/api/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const API_ENDPOINTS = {
INFO: '/api/info',
PROGRAMS: {
LIST: '/api/programs',
BY_ID: (programId: string) => `/api/programs/${programId}`,
Expand Down
5 changes: 4 additions & 1 deletion src/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
"Footer": {
"addressLabel": "Adresse",
"contactLabel": "Contact",
"signature": "Made by the ApplETS club at École de technologie supérieure"
"signature": "Made by the ApplETS club at École de technologie supérieure",
"environment": "Env",
"frontend": "Frontend",
"backend": "Backend"
}
}
5 changes: 4 additions & 1 deletion src/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
"Footer": {
"addressLabel": "Adresse",
"contactLabel": "Contact",
"signature": "Fait par le club ApplETS de l'École de technologie supérieure"
"signature": "Fait par le club ApplETS de l'École de technologie supérieure",
"environment": "Env",
"frontend": "Frontend",
"backend": "Backend"
}
}
Loading