diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 629d2976..d7b58640 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -75,7 +75,7 @@ This document lists every environment variable used by the RemitLend platform. E | `SENTRY_AUTH_TOKEN` | — | ✓ | ✓ | — | Sentry auth token for source maps | `frontend/next.config.ts` | | `NODE_ENV` | ✓ | ✓ | ✓ | `development` | Node environment (`development`, `test`, `production`) | `next.config.ts` | | `NEXT_PUBLIC_STELLAR_EXPLORER_URL` | ✓ | ✓ | ✓ | `https://stellar.expert/explorer/testnet` | Stellar explorer base URL for transaction links | `frontend/src/components/ui/TxHashLink.tsx` | - +| `NEXT_PUBLIC_STELLAR_NETWORK` | ✓ | ✓ | ✓ | `testnet` | Stellar network name shown in the build-info footer | `frontend/src/components/BuildInfoFooter.tsx` | --- ## Contracts / Scripts (`contracts/`, `scripts/`) diff --git a/frontend/.env.example b/frontend/.env.example index 0fdbb1b8..0d079bd1 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -17,3 +17,10 @@ NODE_ENV=development # Mainnet: https://stellar.expert/explorer/public # Testnet: https://stellar.expert/explorer/testnet (default) NEXT_PUBLIC_STELLAR_EXPLORER_URL=https://stellar.expert/explorer/testnet + +# ── Build Info (auto-injected by next.config.ts) ───────────────────────────── +# These are set automatically at build time. Override only if needed. +# NEXT_PUBLIC_COMMIT_SHA — short git SHA, defaults to 'local' when git is unavailable +# NEXT_PUBLIC_APP_VERSION — read from package.json version field +# NEXT_PUBLIC_STELLAR_NETWORK — 'testnet' | 'mainnet', defaults to 'testnet' +NEXT_PUBLIC_STELLAR_NETWORK=testnet diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 86d92f43..952e4085 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -288,6 +288,10 @@ "submit": "Build, Sign & Submit" } }, + "BuildInfo": { + "ariaLabel": "Build information", + "label": "v{version} · {network} · {sha}" + }, "Lend": { "cooldownActive": "Withdraw available in about {minutes} minute(s) while cooldown is active." }, diff --git a/frontend/next.config.ts b/frontend/next.config.ts index 6849d915..50dcedee 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,7 +1,22 @@ +import { execSync } from "child_process"; import createNextIntlPlugin from "next-intl/plugin"; import type { NextConfig } from "next"; import { withSentryConfig } from "@sentry/nextjs"; import withSerwistInit from "@serwist/next"; +import packageJson from "./package.json" with { type: "json" }; + +/* ── Build-time environment variables ────────────────────────────────── */ +function getCommitSha(): string { + try { + return execSync("git rev-parse --short HEAD").toString().trim(); + } catch { + return "local"; + } +} + +const commitSha = getCommitSha(); +const appVersion = packageJson.version; +const stellarNetwork = process.env.NEXT_PUBLIC_STELLAR_NETWORK ?? "testnet"; const withNextIntl = createNextIntlPlugin("./i18n.config.ts"); @@ -12,6 +27,11 @@ const withSerwist = withSerwistInit({ const nextConfig: NextConfig = { reactCompiler: true, + env: { + NEXT_PUBLIC_COMMIT_SHA: commitSha, + NEXT_PUBLIC_APP_VERSION: appVersion, + NEXT_PUBLIC_STELLAR_NETWORK: stellarNetwork, + }, }; const config = withSerwist(nextConfig); diff --git a/frontend/src/app/[locale]/layout.tsx b/frontend/src/app/[locale]/layout.tsx index fa340a0e..26205f26 100644 --- a/frontend/src/app/[locale]/layout.tsx +++ b/frontend/src/app/[locale]/layout.tsx @@ -2,6 +2,7 @@ import { NextIntlClientProvider } from "next-intl"; import { getMessages } from "next-intl/server"; import { notFound } from "next/navigation"; import type { Metadata } from "next"; +import BuildInfoFooter from "@/components/BuildInfoFooter"; export const metadata: Metadata = { manifest: "/manifest.webmanifest", @@ -25,6 +26,7 @@ export default async function LocaleLayout({ return ( {children} + ); } diff --git a/frontend/src/components/BuildInfoFooter.tsx b/frontend/src/components/BuildInfoFooter.tsx new file mode 100644 index 00000000..dc960d39 --- /dev/null +++ b/frontend/src/components/BuildInfoFooter.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useTranslations } from "next-intl"; + +/** + * Displays a minimal build-info footer: version · network · commit SHA. + * + * All values come from NEXT_PUBLIC_* env vars injected at build time, + * so there are no hydration mismatches. + * + * TODO: fetch /version from the backend API once the endpoint exists. + */ +export default function BuildInfoFooter() { + const t = useTranslations("BuildInfo"); + + const version = process.env.NEXT_PUBLIC_APP_VERSION ?? "0.0.0"; + const network = process.env.NEXT_PUBLIC_STELLAR_NETWORK ?? "testnet"; + const sha = process.env.NEXT_PUBLIC_COMMIT_SHA ?? "local"; + + return ( + + ); +}