Compare commits

..

4 commits

Author SHA1 Message Date
Ashwin Kumar Sivakumar
e63f47195e fix: use dind service for forgejo builds
Some checks failed
build-and-push / build (push) Failing after 29s
2026-06-12 22:09:56 +05:30
Ashwin Kumar Sivakumar
bfdea41bd1 fix: install docker cli in forgejo workflow namespace
Some checks failed
build-and-push / build (push) Failing after 21s
2026-06-12 22:08:11 +05:30
Ashwin Kumar Sivakumar
9c472ce9a5 fix: add main forgejo sync workflow 2026-06-12 22:00:25 +05:30
Ashwin Kumar Sivakumar
6887e64ddb fix: restore forgejo build workflow filename 2026-06-12 21:58:20 +05:30
30 changed files with 300 additions and 231 deletions

View file

@ -1,13 +0,0 @@
#!/busybox/sh
set -eu
mkdir -p /kaniko/.docker
cat > /kaniko/.docker/config.json <<JSON
{"auths":{"${REGISTRY_HOSTPORT}":{"username":"${REGISTRY_USERNAME}","password":"${REGISTRY_PASSWORD}"}}}
JSON
/kaniko/executor \
--context "${GITHUB_WORKSPACE}" \
--dockerfile "${GITHUB_WORKSPACE}/Dockerfile" \
--destination "${REGISTRY_HOSTPORT}/${IMAGE_NAME}:${COMMIT_SHA}" \
--destination "${REGISTRY_HOSTPORT}/${IMAGE_NAME}:${LATEST_TAG}"

View file

@ -9,22 +9,73 @@ on:
jobs:
build:
runs-on: ubuntu-latest
env:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
services:
docker:
image: docker:27-dind
env:
DOCKER_TLS_CERTDIR: ""
options: --privileged
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and push
uses: docker://gcr.io/kaniko-project/executor:v1.23.2-debug
- name: Install Docker CLI
run: |
apt-get update
apt-get install -y docker.io
- name: Set up Docker Buildx
run: |
export DOCKER_HOST=tcp://docker:2375
docker version
docker buildx create --use || true
docker buildx inspect --bootstrap
- name: Login to Registry
env:
REGISTRY_HOSTPORT: ${{ secrets.REGISTRY_HOSTPORT }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
IMAGE_NAME: nxtgauge-frontend-solid
LATEST_TAG: high-performance-latest
COMMIT_SHA: ${{ github.sha }}
with:
entrypoint: /busybox/sh
args: ${{ github.workspace }}/.forgejo/scripts/kaniko-build.sh
run: |
set -euo pipefail
export DOCKER_HOST=tcp://docker:2375
SHA="$(git rev-parse HEAD)"
test -n "$REGISTRY_HOSTPORT"
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_HOSTPORT" -u "$REGISTRY_USERNAME" --password-stdin
- name: Build and push
env:
REGISTRY_HOSTPORT: ${{ secrets.REGISTRY_HOSTPORT }}
run: |
set -euo pipefail
export DOCKER_HOST=tcp://docker:2375
SHA="$(git rev-parse HEAD)"
build_and_push() {
docker buildx build --push \
-f Dockerfile \
-t "$REGISTRY_HOSTPORT/nxtgauge-frontend-solid:${SHA}" \
-t "$REGISTRY_HOSTPORT/nxtgauge-frontend-solid:high-performance-latest" \
.
}
for attempt in 1 2 3; do
echo "Build attempt $attempt"
if build_and_push; then
exit 0
fi
echo "Build attempt $attempt failed; recreating builder and retrying"
docker buildx rm --all-inactive --force || true
docker buildx create --use || true
docker buildx inspect --bootstrap
sleep $((attempt * 10))
done
echo "Build failed after retries"
exit 1
- name: Prune old image tags (keep latest 1 SHA)
if: success()

View file

@ -11,7 +11,7 @@ Usage:
This script:
1. Updates the newTag for the specified service to the SHA
2. Commits and pushes to the gitops repo
3. Flux detects the change and deploys
3. ArgoCD detects the change and deploys
"""
import argparse
@ -98,14 +98,10 @@ def main():
image_name = f"nxtgauge-{args.service}"
# Find the right kustomization file based on service
if "frontend" in args.service:
if "frontend" in args.service or "admin" in args.service:
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-frontend-solid/overlays/prod/kustomization.yaml")
if not os.path.exists(kustomization_path):
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-frontend-solid/base/kustomization.yaml")
elif "admin" in args.service:
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-admin-solid/overlays/prod/kustomization.yaml")
if not os.path.exists(kustomization_path):
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-admin-solid/base/kustomization.yaml")
elif "ai-assistant" in args.service:
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-ai-assistant/overlays/prod/kustomization.yaml")
if not os.path.exists(kustomization_path):

46
.github/workflows/sync-to-gitea.yml vendored Normal file
View file

@ -0,0 +1,46 @@
name: sync-to-gitea
on:
push:
branches:
- high-performance
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sync to Gitea
env:
GITEA_TOKEN: ${{ secrets.GITEA_SECRET }}
REPO: ${{ github.event.repository.name }}
BRANCH: ${{ github.ref_name }}
run: |
set -euxo pipefail
export GIT_TERMINAL_PROMPT=0
export GIT_TRACE=1
export GIT_CURL_VERBOSE=1
USER="Admin"
TARGET="https://ci.nxtgauge.com/Admin/${REPO}.git"
AUTH="$(printf '%s' "${USER}:${GITEA_TOKEN}" | base64 -w0)"
test -n "${GITEA_TOKEN:-}" || (echo "GITEA_TOKEN empty" && exit 1)
curl -fsS -H "Authorization: token ${GITEA_TOKEN}" https://ci.nxtgauge.com/api/v1/user >/dev/null
curl -fsS -H "Authorization: Basic ${AUTH}" "${TARGET}/info/refs?service=git-receive-pack" >/dev/null
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git config --global http.version HTTP/1.1
git config --global http.postBuffer 524288000
git remote remove gitea 2>/dev/null || true
git remote add gitea "${TARGET}"
git -c http.extraheader="Authorization: Basic ${AUTH}" push gitea "HEAD:${BRANCH}" --force
git -c http.extraheader="Authorization: Basic ${AUTH}" push gitea --tags --force

View file

@ -12,6 +12,3 @@ See `docs/MIGRATION_MASTER_PLAN.md` for the staged plan.
Required secrets:
- `REGISTRY_USERNAME`
- `REGISTRY_PASSWORD`
# Mon Jun 8 09:06:25 PM IST 2026
# Mon Jun 8 09:16:18 PM IST 2026

View file

@ -102,9 +102,9 @@ Visual tests compare screenshots against baselines in `tests/e2e/visual/`.
## CI / Nightly Runs
GitHub Actions runs tests nightly via `.forgejo/workflows/test.yaml`:
GitHub Actions runs tests nightly via `.gitea/workflows/test.yaml`:
- **2:30 AM daily** — all test suites
- **On-demand** — use `workflow_dispatch` trigger in Forgejo
- **On-demand** — use `workflow_dispatch` trigger in Gitea
Artifacts are uploaded:
- `vitest-coverage/` — coverage reports

View file

@ -21,52 +21,53 @@ export default function CaptchaCanvas(props: CaptchaCanvasProps) {
const width = 176;
const height = 52;
const dpr = typeof window !== 'undefined' ? Math.max(1, window.devicePixelRatio || 1) : 1;
// Set canvas resolution (fixed at 1x to prevent zoom issues)
canvas.width = width;
canvas.height = height;
// Set canvas resolution first (before any drawing)
canvas.width = Math.floor(width * dpr);
canvas.height = Math.floor(height * dpr);
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
// Clear and fill background
ctx.clearRect(0, 0, width, height);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, width, height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw decorative lines (within bounds)
// Draw decorative lines
for (let i = 0; i < 2; i += 1) {
ctx.strokeStyle = i % 2 === 0 ? 'rgba(253,98,22,0.16)' : 'rgba(27,36,64,0.14)';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(Math.random() * width, Math.random() * height);
ctx.lineTo(Math.random() * width, Math.random() * height);
ctx.moveTo(Math.random() * canvas.width, Math.random() * canvas.height);
ctx.lineTo(Math.random() * canvas.width, Math.random() * canvas.height);
ctx.stroke();
}
// Draw decorative circles (within bounds)
// Draw decorative circles
for (let i = 0; i < 3; i += 1) {
ctx.fillStyle = i % 2 === 0 ? 'rgba(253,98,22,0.10)' : 'rgba(27,36,64,0.09)';
ctx.beginPath();
ctx.arc(Math.random() * width, Math.random() * height, Math.random() * 1.8 + 0.6, 0, Math.PI * 2);
ctx.arc(Math.random() * canvas.width, Math.random() * canvas.height, Math.random() * 1.8 + 0.6, 0, Math.PI * 2);
ctx.fill();
}
// Draw characters (fixed positioning)
// Draw characters
const chars = String(props.code || '').slice(0, 6).split('');
const startX = 16;
const charGap = 24;
const startX = 16 * dpr;
const charGap = 24 * dpr;
chars.forEach((char, index) => {
const x = startX + index * charGap;
const y = height / 2;
const y = canvas.height / 2;
const rotation = 0;
ctx.save();
ctx.translate(x, y);
ctx.rotate(rotation);
ctx.textBaseline = 'middle';
ctx.font = `800 22px "Courier New", monospace`;
ctx.font = `800 ${22 * dpr}px "Courier New", monospace`;
ctx.fillStyle = index % 2 === 0 ? '#0f172a' : '#c2410c';
ctx.lineWidth = 0;
ctx.fillText(char, 0, 0);

View file

@ -98,7 +98,7 @@ export default function DashboardLayout(props: ParentProps) {
const token = sessionStorage.getItem("nxtgauge_access_token");
if (token) {
try {
const res = await fetch("/api/gateway/auth/session", {
const res = await fetch("/api/auth/session", {
headers: {
Accept: "application/json",
Authorization: `Bearer ${token}`,

View file

@ -115,7 +115,7 @@ export default function RoleLandingPage(props: Props) {
return item;
});
const canonical = createMemo(() => `https://test111.nxtgauge.com${props.pathBase}/${encodeURIComponent(String(props.slug || ''))}`);
const canonical = createMemo(() => `https://test121.nxtgauge.com${props.pathBase}/${encodeURIComponent(String(props.slug || ''))}`);
const pageTitle = createMemo(() => (content() ? `${content()!.shortTitle} | Nxtgauge` : 'Role | Nxtgauge'));
const pageDescription = createMemo(() =>
content() ? `${content()!.heroDescription} Most role reviews complete in 24-48 hours.` : 'Role landing page on Nxtgauge.'

View file

@ -1054,7 +1054,7 @@ export default function DashboardDesignPreview(props: {
try {
const token = getToken();
if (!token) return;
const res = await fetch('/api/gateway/me/notifications/unread-count', {
const res = await fetch('/api/me/notifications/unread-count', {
headers: { Authorization: `Bearer ${token}` },
credentials: 'include',
});

View file

@ -267,14 +267,14 @@ export default function MyDashboardPage(props: Props) {
try {
if (roleKey === 'COMPANY') {
const [jobsRes, appsRes] = await Promise.all([
fetch('/api/gateway/companies/jobs?page=1&limit=100', {
fetch('/api/companies/jobs?page=1&limit=100', {
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.sessionStorage.getItem('nxtgauge_access_token') || ''}`,
},
}),
fetch('/api/gateway/companies/jobs?page=1&limit=1', {
fetch('/api/companies/jobs?page=1&limit=1', {
credentials: 'include',
headers: {
'Content-Type': 'application/json',
@ -293,7 +293,7 @@ export default function MyDashboardPage(props: Props) {
);
if (!jobsRes.ok && !appsRes.ok) setErr('Some company metrics could not be loaded.');
} else if (roleKey === 'CUSTOMER') {
const res = await fetch('/api/gateway/customers/requirements?page=1&limit=100', {
const res = await fetch('/api/customers/requirements?page=1&limit=100', {
credentials: 'include',
headers: {
'Content-Type': 'application/json',
@ -311,14 +311,14 @@ export default function MyDashboardPage(props: Props) {
if (!res.ok) setErr('Some customer metrics could not be loaded.');
} else if (roleKey === 'JOB_SEEKER') {
const [jobsRes, appsRes] = await Promise.all([
fetch('/api/gateway/jobseeker/jobs?page=1&limit=100', {
fetch('/api/jobseeker/jobs?page=1&limit=100', {
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.sessionStorage.getItem('nxtgauge_access_token') || ''}`,
},
}),
fetch('/api/gateway/jobseeker/applications?page=1&limit=100', {
fetch('/api/jobseeker/applications?page=1&limit=100', {
credentials: 'include',
headers: {
'Content-Type': 'application/json',

View file

@ -82,7 +82,7 @@ async function fetchSession(): Promise<AuthUser | null> {
const token = getToken();
if (!token) return null;
try {
const res = await fetch("/api/gateway/auth/session", {
const res = await fetch("/api/auth/session", {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,

View file

@ -42,7 +42,7 @@ export async function fetchHelpCenterArticles(input: {
// Fallback: when backend search returns sparse/empty data, apply local filtering
// so users can still find articles by simple keywords.
if (input.q && items.length === 0) {
const allRes = await fetch("/api/gateway/kb/articles");
const allRes = await fetch("/api/kb/articles");
if (allRes.ok) {
const allData = await allRes.json();
const allRaw: any[] = Array.isArray(allData) ? allData : (allData.articles ?? []);
@ -62,7 +62,7 @@ export async function fetchHelpCenterArticles(input: {
export async function fetchHelpCenterCategories(): Promise<HelpCategory[]> {
try {
const res = await fetch("/api/gateway/kb/categories");
const res = await fetch("/api/kb/categories");
if (!res.ok) return HELP_CENTER_SEED_CATEGORIES;
const data = await res.json();
const raw: any[] = Array.isArray(data) ? data : (data.categories ?? []);
@ -98,7 +98,7 @@ export async function fetchRelatedArticles(input: {
limit?: number;
}): Promise<HelpArticle[]> {
try {
const res = await fetch("/api/gateway/kb/articles");
const res = await fetch("/api/kb/articles");
if (!res.ok)
return pickRelated(
HELP_CENTER_SEED_ARTICLES as HelpArticle[],

View file

@ -1,147 +0,0 @@
/**
* SolidStart server middleware (runs on every request).
*
* Workaround for a Vinxi 0.5.7 + @solidjs/start 1.3.2 build issue where
* file-based API routes in `src/routes/api/*` are registered in the page
* router tree but never mounted as Nitro handlers, so every `/api/*`
* request returns a 404 from the SolidStart page renderer.
*
* This middleware intercepts `/api/*` paths at the SolidStart middleware
* layer (which IS in the request pipeline) and proxies them to the Rust
* gateway.
*
* Responsibilities:
* - /api/gateway/*path proxy to Rust gateway
* - /api/kb/categories proxy to Rust gateway
* - /api/kb/articles proxy to Rust gateway
* - /api/kb/articles/:slug proxy to Rust gateway
*
* Uses the @solidjs/start `createMiddleware` pattern, which Vinxi/h3 will
* actually invoke via the `onRequest` hook.
*/
import { createMiddleware } from "@solidjs/start/middleware";
const GATEWAY_URL = (
process.env.GATEWAY_URL || "http://nxtgauge-rust-gateway:9100"
).replace(/\/+$/, "");
const PUBLIC_API_URL = (
process.env.PUBLIC_API_URL ||
process.env.NEXT_PUBLIC_API_URL ||
`${GATEWAY_URL}/api`
).replace(/\/+$/, "");
function buildUpstream(path: string, query: string = ""): string {
// PUBLIC_API_URL ends with /api; path starts with /api/...
// Strip the /api prefix from path so we don't double up.
if (PUBLIC_API_URL.endsWith("/api")) {
const stripped = path.replace(/^\/api/, "");
return `${PUBLIC_API_URL}${stripped}${query}`;
}
return `${PUBLIC_API_URL}${path}${query}`;
}
async function proxyToGateway(fetchEvent: any, upstreamPath: string) {
const req = fetchEvent.request;
const method = req.method.toUpperCase();
const url = new URL(req.url);
const queryString = url.search || "";
// Read body for methods that have one
let body: BodyInit | undefined;
if (["POST", "PUT", "PATCH", "DELETE"].includes(method)) {
try {
body = await req.clone().text();
} catch {
body = undefined;
}
}
// Forward auth + content-type + cookie
const headers: Record<string, string> = {
"Content-Type":
req.headers.get("content-type") || "application/json",
};
const auth = req.headers.get("authorization");
if (auth) headers["Authorization"] = auth;
const cookie = req.headers.get("cookie");
if (cookie) headers["Cookie"] = cookie;
const upstream = buildUpstream(upstreamPath, queryString);
let response: Response;
try {
response = await fetch(upstream, {
method,
headers,
body,
cache: "no-store",
});
} catch (err: any) {
return new Response(
JSON.stringify({
success: false,
error: `Gateway unreachable: ${err?.message || "unknown"}`,
}),
{
status: 502,
headers: { "Content-Type": "application/json" },
},
);
}
// Copy response headers (skip hop-by-hop), ensure Content-Type
const respHeaders = new Headers();
response.headers.forEach((value, key) => {
const k = key.toLowerCase();
if (k === "server" || k === "transfer-encoding" || k === "connection") return;
respHeaders.set(key, value);
});
if (!respHeaders.get("content-type")) {
respHeaders.set("Content-Type", "application/json");
}
const respBody = await response.text();
return new Response(respBody, {
status: response.status,
statusText: response.statusText,
headers: respHeaders,
});
}
export default createMiddleware({
onRequest: async (fetchEvent) => {
const url = new URL(fetchEvent.request.url);
const path = url.pathname;
// Only handle /api/* paths
if (!path.startsWith("/api/")) return;
// Gateway proxy catch-all: /api/gateway/* → strip /api/gateway, send rest
if (path === "/api/gateway" || path.startsWith("/api/gateway/")) {
const subPath = path.slice("/api/gateway".length) || "/";
// Normalize to /api/... contract for the Rust gateway
const normalized =
subPath.startsWith("/api/") || subPath === "/api"
? subPath
: `/api${subPath}`;
return proxyToGateway(fetchEvent, normalized);
}
// Knowledge base routes
if (path === "/api/kb/categories") {
return proxyToGateway(fetchEvent, "/api/kb/categories");
}
if (path === "/api/kb/articles") {
return proxyToGateway(fetchEvent, "/api/kb/articles");
}
if (path.startsWith("/api/kb/articles/")) {
return proxyToGateway(fetchEvent, path);
}
// Everything else under /api/* — let it fall through.
// Returning undefined tells the framework to continue.
return;
},
});

View file

@ -0,0 +1,87 @@
import { gatewayUrl, withAuthHeaders } from '~/lib/server/gateway';
/**
* Generic gateway proxy endpoint
* Forwards all requests to the Rust backend gateway with proper auth headers
* Usage: /api/gateway/api/companies/jobs forwards to gateway /api/companies/jobs
*/
export async function GET({ request, params }: { request: Request; params: any }) {
return proxyRequest('GET', request, params);
}
export async function POST({ request, params }: { request: Request; params: any }) {
return proxyRequest('POST', request, params);
}
export async function PUT({ request, params }: { request: Request; params: any }) {
return proxyRequest('PUT', request, params);
}
export async function DELETE({ request, params }: { request: Request; params: any }) {
return proxyRequest('DELETE', request, params);
}
export async function PATCH({ request, params }: { request: Request; params: any }) {
return proxyRequest('PATCH', request, params);
}
async function proxyRequest(method: string, request: Request, params: any) {
try {
// Handle different param structures
let pathArray = params.path;
if (!Array.isArray(pathArray)) {
pathArray = [pathArray];
}
const rawPath = `/${pathArray.join('/')}`;
// Normalize all forwarded routes to the Rust gateway's /api/* contract.
const path = rawPath.startsWith('/api/') || rawPath === '/api'
? rawPath
: `/api${rawPath}`;
// Preserve query string
const url = new URL(request.url);
const queryString = url.search ? url.search : '';
// Build request body if needed
let body: string | undefined;
if (['POST', 'PUT', 'PATCH'].includes(method)) {
body = await request.text();
}
// Forward to gateway
const upstreamUrl = gatewayUrl(path + queryString);
const upstreamRequest = new Request(upstreamUrl, {
method,
headers: withAuthHeaders(request, {
'Content-Type': request.headers.get('Content-Type') || 'application/json',
}),
body,
cache: 'no-store',
});
const response = await fetch(upstreamRequest);
// Copy response headers and return
const responseHeaders = new Headers();
response.headers.forEach((value, key) => {
if (!['server', 'transfer-encoding', 'connection'].includes(key.toLowerCase())) {
responseHeaders.set(key, value);
}
});
responseHeaders.set('Content-Type', 'application/json');
const responseBody = await response.text();
return new Response(responseBody, {
status: response.status,
statusText: response.statusText,
headers: responseHeaders,
});
} catch (error: any) {
return new Response(
JSON.stringify({ success: false, error: error?.message || 'Internal Server Error' }),
{ status: 500, headers: { 'Content-Type': 'application/json' } },
);
}
}

View file

@ -0,0 +1,19 @@
import { gatewayUrl } from '~/lib/server/gateway';
export async function GET({ request }: { request: Request }) {
const url = new URL(request.url);
const upstream = gatewayUrl('/api/kb/articles' + url.search);
try {
const res = await fetch(upstream, { cache: 'no-store' });
const body = await res.text();
return new Response(body, {
status: res.status,
headers: { 'Content-Type': 'application/json' },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err?.message || 'Gateway error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
});
}
}

View file

@ -0,0 +1,18 @@
import { gatewayUrl } from '~/lib/server/gateway';
export async function GET({ params }: { params: { slug: string } }) {
const upstream = gatewayUrl(`/api/kb/articles/${params.slug}`);
try {
const res = await fetch(upstream, { cache: 'no-store' });
const body = await res.text();
return new Response(body, {
status: res.status,
headers: { 'Content-Type': 'application/json' },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err?.message || 'Gateway error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
});
}
}

View file

@ -0,0 +1,18 @@
import { gatewayUrl } from '~/lib/server/gateway';
export async function GET() {
const upstream = gatewayUrl('/api/kb/categories');
try {
const res = await fetch(upstream, { cache: 'no-store' });
const body = await res.text();
return new Response(body, {
status: res.status,
headers: { 'Content-Type': 'application/json' },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err?.message || 'Gateway error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
});
}
}

View file

@ -158,7 +158,7 @@ export default function ContactPage() {
"Job Seeker (Apply jobs)": "GENERAL",
};
const category = userTypeToCategory[values().userType] || "GENERAL";
const res = await fetch("/api/gateway/support/tickets", {
const res = await fetch("/api/support/tickets", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",

View file

@ -648,7 +648,7 @@ export default function RuntimeDashboardPage() {
const email = authEmail || getEmailFromStorage();
if (!email) return;
const checkRes = await fetch("/api/gateway/auth/check-email", {
const checkRes = await fetch("/api/auth/check-email", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -671,7 +671,7 @@ export default function RuntimeDashboardPage() {
const token = getToken();
if (token) {
const switchRes = await fetch("/api/gateway/auth/switch-role", {
const switchRes = await fetch("/api/auth/switch-role", {
method: "POST",
headers: {
"Content-Type": "application/json",

View file

@ -48,7 +48,7 @@ export default function ForgotPasswordRoute() {
}
setSubmitting(true);
try {
const res = await fetch('/api/gateway/auth/forgot-password', {
const res = await fetch('/api/auth/forgot-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email().trim().toLowerCase() }),
@ -82,7 +82,7 @@ export default function ForgotPasswordRoute() {
}
setSubmitting(true);
try {
const res = await fetch('/api/gateway/auth/reset-password', {
const res = await fetch('/api/auth/reset-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({

View file

@ -26,7 +26,7 @@ export default function HelpCenterArticlePage() {
(item) => (item ? fetchRelatedArticles({ article: item, limit: 4 }) : [])
);
const canonical = createMemo(
() => `https://test111.nxtgauge.com/help-center/article/${encodeURIComponent(slug())}`
() => `https://test121.nxtgauge.com/help-center/article/${encodeURIComponent(slug())}`
);
const pageTitle = createMemo(() => {
const a = article();

View file

@ -10,7 +10,7 @@ export default function HelpCenterPage() {
const title = "Help Center | Nxtgauge";
const description =
"Browse Nxtgauge guides for getting started, roles, requests, approvals, and platform troubleshooting.";
const canonical = "https://test111.nxtgauge.com/help-center";
const canonical = "https://test121.nxtgauge.com/help-center";
const [query, setQuery] = createSignal("");
const [category, setCategory] = createSignal("");

View file

@ -4,7 +4,7 @@ import PublicLanding from '~/components/PublicLanding';
export default function Home() {
const title = 'Nxtgauge | Verified Jobs & Professional Services Platform';
const description = 'Trusted hiring and opportunity discovery for customers, companies, professionals, and job seekers with verification built in.';
const canonical = 'https://test111.nxtgauge.com/';
const canonical = 'https://test121.nxtgauge.com/';
return (
<>

View file

@ -133,7 +133,7 @@ export default function LoginRoute() {
}
setCheckingRole(true);
try {
const response = await fetch("/api/gateway/auth/check-email", {
const response = await fetch("/api/auth/check-email", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -243,7 +243,7 @@ export default function LoginRoute() {
}
setSubmitting(true);
try {
const res = await fetch("/api/gateway/auth/login", {
const res = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -283,7 +283,7 @@ export default function LoginRoute() {
if (discoveredRoleKeys.length === 0 || isJobSeekerRole(discoveredActiveRole)) {
try {
const checkRes = await fetch("/api/gateway/auth/check-email", {
const checkRes = await fetch("/api/auth/check-email", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -324,7 +324,7 @@ export default function LoginRoute() {
let desiredRoleKey = discoveredActiveRole;
if (finalAccessToken && requestedRoleKey && requestedRoleKey !== discoveredActiveRole) {
try {
const switchRes = await fetch("/api/gateway/auth/switch-role", {
const switchRes = await fetch("/api/auth/switch-role", {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -385,7 +385,7 @@ export default function LoginRoute() {
setError("");
setSubmitting(true);
try {
const res = await fetch("/api/gateway/auth/resend-otp", {
const res = await fetch("/api/auth/resend-otp", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -409,7 +409,7 @@ export default function LoginRoute() {
}
setSubmitting(true);
try {
const verifyRes = await fetch("/api/gateway/auth/verify-email", {
const verifyRes = await fetch("/api/auth/verify-email", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",

View file

@ -17,7 +17,7 @@ const chipNodes = [
export default function ProfessionalsIndexPage() {
const [scrollY, setScrollY] = createSignal(0);
const [reduceMotion, setReduceMotion] = createSignal(false);
const canonical = 'https://test111.nxtgauge.com/professionals';
const canonical = 'https://test121.nxtgauge.com/professionals';
const title = 'Professionals | Nxtgauge Verified Service Categories';
const description = 'Explore verified professional categories on Nxtgauge and register with a trust-first workflow built for better opportunity quality.';

View file

@ -133,7 +133,7 @@ export default function SignupRoute() {
}
try {
const response = await fetch("/api/gateway/auth/check-email", {
const response = await fetch("/api/auth/check-email", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -218,7 +218,7 @@ export default function SignupRoute() {
setSubmitting(true);
try {
console.log('[register] after canSubmit guard, calling API...');
const res = await fetch("/api/gateway/auth/register", {
const res = await fetch("/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -311,7 +311,7 @@ export default function SignupRoute() {
}
setSubmitting(true);
try {
const verifyRes = await fetch("/api/gateway/auth/verify-email", {
const verifyRes = await fetch("/api/auth/verify-email", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",
@ -376,7 +376,7 @@ export default function SignupRoute() {
setServerError("");
setSubmitting(true);
try {
const res = await fetch("/api/gateway/auth/resend-otp", {
const res = await fetch("/api/auth/resend-otp", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
credentials: "include",

View file

@ -2,10 +2,6 @@
import { defineConfig } from "@solidjs/start/config";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
// Register our Nitro middleware that handles all /api/* paths.
// Workaround for Vinxi 0.5.7 + @solidjs/start 1.3.2 build issue
// where file-based API routes are not mounted as Nitro handlers.
middleware: "./src/middleware.ts",
vite: {
plugins: [tailwindcss()],
server: {
@ -18,7 +14,7 @@ export default defineConfig({
.replace(/^\/api\/gateway\/api(\/|$)/, "/api$1")
.replace(/^\/api\/gateway(\/|$)/, "/api$1"),
},
"/api/kb": {
"/api": {
target: "http://localhost:9100",
changeOrigin: true,
},