From 5a64ebf560aee6bb2adf587d54e939f5e217069d Mon Sep 17 00:00:00 2001 From: mjalmoudy94 Date: Tue, 13 Oct 2026 08:05:58 +0000 Subject: [PATCH] =?UTF-8?q?=D8=B1=D9=81=D8=B9=20=D8=A8=D8=A7=DA=AF:=20?= =?UTF-8?q?=D8=AA=D8=B5=D8=AD=DB=8C=D8=AD=20=D9=85=D8=B3=DB=8C=D8=B1=D8=AF?= =?UTF-8?q?=D9=87=DB=8C=20=D8=A7=D8=B1=D8=AA=D8=A8=D8=A7=D8=B7=20=DA=A9?= =?UTF-8?q?=D9=84=D8=A7=DB=8C=D9=86=D8=AA=20=D8=A8=D8=A7=20=D8=B3=D8=B1?= =?UTF-8?q?=D9=88=DB=8C=D8=B3=20=D9=88=20=D8=AD=D9=84=20=D8=AE=D8=B7=D8=A7?= =?UTF-8?q?=DB=8C=20=D8=AF=D8=B3=D8=AA=D8=B1=D8=B3=DB=8C=20=D8=B4=D8=A8?= =?UTF-8?q?=DA=A9=D9=87=20=D8=A8=D9=87=20=D9=87=D9=85=D8=B1=D8=A7=D9=87=20?= =?UTF-8?q?=D8=A7=D9=81=D8=B2=D9=88=D8=AF=D9=86=20=D8=A2=DB=8C=DA=A9=D9=88?= =?UTF-8?q?=D9=86=20=D8=B3=D8=A7=D9=85=D8=A7=D9=86=D9=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + apps/web/next.config.mjs | 10 +++++++++- apps/web/package.json | 2 +- apps/web/public/favicon.ico | Bin 0 -> 1163 bytes apps/web/src/app/icon.svg | 16 ++++++++++++++++ apps/web/src/lib/api.ts | 29 ++++++++++++++++++++++++++--- apps/web/src/lib/version.ts | 2 +- package.json | 2 +- 8 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 apps/web/public/favicon.ico create mode 100644 apps/web/src/app/icon.svg diff --git a/.gitignore b/.gitignore index 9197675..6c45d1d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ venv/ # env & secrets .env .env.local +.env.production .env.*.local !.env.example diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index bad8e31..b1b11e2 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -4,7 +4,15 @@ const nextConfig = { // Workspace packages ship TypeScript source, so Next must transpile them. transpilePackages: ["@agy/ui", "@agy/contracts"], env: { - NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000", + NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL ?? "", + }, + async rewrites() { + return [ + { + source: "/api/:path*", + destination: "http://127.0.0.1:8000/api/:path*", + }, + ]; }, }; diff --git a/apps/web/package.json b/apps/web/package.json index 17577ef..fb3c203 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@agy/web", - "version": "0.1.1", + "version": "0.1.2", "private": true, "description": "Smart Organization frontend — Next.js App Router, RTL, dark-first.", "scripts": { diff --git a/apps/web/public/favicon.ico b/apps/web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..20558e8246959a383af298a805f22aca2762e6ed GIT binary patch literal 1163 zcmV;61a$iV0096301yxW0000W0Mh~h044wc03aX$0000W0FnU!0Qmv{0EtjeM-2)Z z3IG5A4M|8uQUCw|5C8xG5C{eU001BJ|6u?C0-8xgK~#90eUndUR96(nf9Kx&-u$0u zCSxL*79yHZv~^V_G*kq;P^4I)i&CNOrf%Jo>Y@~v>Z0qeT3VqBg3_(DyXvCQh3Fy_ z6cw?gW|~Yg^JeD#xyQwfF;?1dbK!E&?|kRu9;sBfsaQv`G64vnY)WKw>Xy6ln?Y|C z%`==BM_7tT`Ws})-~~Vos7HN{xDb5432thmJBe)jk*h)U1z`gfjw955G@?V4|-rm_Kk64w~PQ= zCB~9ZO|KEYJ0cm%Q>5sp}InO_jm+%f|cb*^_ zt|4Oo3m}NKB%Ng%i^r+%TO^p?#oli((cW9)^~NDgP(n3Fw&Y-*7ki)Jvy@`gV*2y1 zS^4Q3I=^1WKkD(L|H+=+pD|3<$u&b5Lz=C5Emb0|)|-0d=v6&+I@X0VHxy7p zl&GwLF6{nDubosqd+@r}>f5zkiFEtSygDO}WZ2=r!Ug8v_>hf_Hg7$BlYNWdA=v<* zX9QuD!>@fxJm~P=><2uF@A2d9FQ}OoM%80&fxnk;(eHPu)FxSu?~o2Vh&Ze((oZ_v zUipQoa>VK&W~qG>XA7u$XwJ-O)M%-7=&rfr`p&!OwNh&+!FYraB|t0nhJNz)Mcu#i zgc6`pqovK6IhAU?sbRTJo($>to|0t=#bSgt0jQ#Yh>-h~IO$+)K)pPL2@53gISxH1eRCt`#m$43lFc5~XjT>>1O^FF3F+72@ ziKC;=J{L1}bM!roadc5PAHWF*g*4?3+7nB>gv1ux|G%%7(u!a>DgcQvO0aHrJg#T7 ze?SRS1GquWD|7;3lyokP8PPSQPjP@Z0eyL;PjSqIZ29lcLrjx-!OcG1->cup)!2D_ z7$tlHx;WOh4VD2)jANqr8u(8GRKalyu`>d*-IF!$YXisCxXOIJx%e?qR=bW|`e-0+m=G@NJdR^Lf%tLq4F5A z + + + + + + + + + + + + + + + diff --git a/apps/web/src/lib/api.ts b/apps/web/src/lib/api.ts index 4b9ea47..dc22973 100644 --- a/apps/web/src/lib/api.ts +++ b/apps/web/src/lib/api.ts @@ -8,8 +8,30 @@ import type { ApiErrorBody } from "@agy/contracts"; -export const API_BASE_URL = - process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000"; +/** + * Resolves the API base URL. + * In a browser: + * - If NEXT_PUBLIC_API_URL is configured and not pointing to localhost on a remote host, use it. + * - Otherwise default to relative path "" so requests go directly to the current origin (e.g. /api/*) + * behind reverse proxies (Caddy), preventing ERR_CONNECTION_REFUSED on clients. + * In SSR / Node / tests: + * - Fall back to NEXT_PUBLIC_API_URL or "http://localhost:8000". + */ +export function getApiBaseUrl(): string { + const configured = process.env.NEXT_PUBLIC_API_URL?.trim(); + if (typeof window !== "undefined") { + const isLocalhost = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; + if (!configured || (!isLocalhost && configured.includes("localhost"))) { + return ""; + } + return configured; + } + return configured || "http://localhost:8000"; +} + +export const API_BASE_URL = getApiBaseUrl(); export class ApiError extends Error { readonly status: number; @@ -73,9 +95,10 @@ export async function apiRequest(path: string, options: RequestOptions = {}): const authToken = token ?? getStoredToken(); if (authToken) headers.Authorization = `Bearer ${authToken}`; + const baseUrl = getApiBaseUrl(); let response: Response; try { - response = await fetch(`${API_BASE_URL}${path}`, { + response = await fetch(`${baseUrl}${path}`, { method, headers, body: body === undefined ? undefined : JSON.stringify(body), diff --git a/apps/web/src/lib/version.ts b/apps/web/src/lib/version.ts index fc4be2f..9235c65 100644 --- a/apps/web/src/lib/version.ts +++ b/apps/web/src/lib/version.ts @@ -12,7 +12,7 @@ * "the app is on the wrong version" bug into a failing test, which is the * whole point of keeping them separate. */ -export const APP_VERSION = "0.1.1"; +export const APP_VERSION = "0.1.2"; /** What the footer pill renders — ``v`` prefix keeps it unambiguous in the UI. */ export const APP_VERSION_LABEL = `v${APP_VERSION}`; diff --git a/package.json b/package.json index a343adb..034c729 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "smart-org", - "version": "0.1.1", + "version": "0.1.2", "private": true, "description": "Smart Organization — AI Workforce Platform. Standalone multi-tenant SaaS, independent of the Telegram bot runtime.", "packageManager": "pnpm@9.12.0",