diff --git a/CLAUDE.md b/CLAUDE.md index 65f78fc12..4d4b618d4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,7 +18,7 @@ Full wayfinding is in [`MAP.md`](MAP.md). This is a **Bun monorepo** using works - **apps/frontend** — React 19 + Vite web app → [`apps/frontend/CLAUDE.md`](apps/frontend/CLAUDE.md) - **apps/demo** — minimal browser SDK integration → [`apps/demo/CLAUDE.md`](apps/demo/CLAUDE.md) -- **apps/gold** — "ouro. by Vortex" gold app served at /gold → [`apps/gold/CLAUDE.md`](apps/gold/CLAUDE.md) +- **apps/gold** — "ouro. by Vortex" gold app served at /pt-br/gold → [`apps/gold/CLAUDE.md`](apps/gold/CLAUDE.md) - **apps/api** — Express backend (PostgreSQL + Sequelize) → [`apps/api/CLAUDE.md`](apps/api/CLAUDE.md) - **apps/dashboard** — authenticated React dashboard → [`apps/dashboard/CLAUDE.md`](apps/dashboard/CLAUDE.md) - **apps/rebalancer** — liquidity rebalancing service → [`apps/rebalancer/CLAUDE.md`](apps/rebalancer/CLAUDE.md) diff --git a/MAP.md b/MAP.md index 93d50d69e..cf40f66cb 100644 --- a/MAP.md +++ b/MAP.md @@ -10,7 +10,7 @@ workspace; use [`docs/README.md`](docs/README.md) to locate durable project cont | `apps/api` | Express API, PostgreSQL/Sequelize models and migrations, block-flow ramp engine, provider integrations, webhooks, and workers. | | `apps/frontend` | React widget and public web surface. XState ramp/KYC flows, wallets, and partner embedding. | | `apps/demo` | Minimal browser-only React example for a BRL/PIX to BSC USDC onramp through `@vortexfi/sdk`. | -| `apps/gold` | "ouro. by Vortex" consumer app for BRL/PIX to PAXG through `@vortexfi/sdk`, served by the frontend site at `/gold`. | +| `apps/gold` | "ouro. by Vortex" consumer app for BRL/PIX to PAXG through `@vortexfi/sdk`, served by the frontend site at `/pt-br/gold`. | | `apps/dashboard` | React account dashboard. Auth, customer entities, onboarding, recipients, history, and self-ramp flows. | | `apps/rebalancer` | Standalone service for cross-chain liquidity correction and profitability-aware rebalancing. | diff --git a/apps/frontend/_redirects b/apps/frontend/_redirects index a54f88f0c..237010d0f 100644 --- a/apps/frontend/_redirects +++ b/apps/frontend/_redirects @@ -13,12 +13,10 @@ # Support the lowercase widget alias without turning unknown localized paths into soft 404s. /pt-br/widget /_shell.html 200 -# Gold lives as plain files under dist/client/gold/ (see netlify.toml), so /gold/ needs no rule. -# The locale-first alias mirrors /pt-BR/widget; Gold's canonical link still points at /gold/. -/pt-BR/gold /gold/index.html 200 -/pt-BR/gold/* /gold/:splat 200 -/pt-br/gold /gold/index.html 200 -/pt-br/gold/* /gold/:splat 200 +# Gold's canonical URL is /pt-br/gold/ (plain files under dist/client/pt-BR/gold/, see +# netlify.toml). The unprefixed path redirects until an international Gold landing exists. +/gold /pt-br/gold/ 301 +/gold/* /pt-br/gold/:splat 301 # Everything else is a real 404 /* /404.html 404 diff --git a/apps/frontend/netlify.toml b/apps/frontend/netlify.toml index 3685aa296..fd989cce8 100644 --- a/apps/frontend/netlify.toml +++ b/apps/frontend/netlify.toml @@ -7,8 +7,9 @@ # Redirect rules live in `_redirects` (copied into dist/client by the build), not here. # Marketing routes are prerendered to static HTML by TanStack Start, so they are plain files # under `dist/client`; only the SSR-disabled widget route needs a rewrite. -# Gold (apps/gold) is a separate Vite app built with base /gold/ and copied into the -# published tree, so Netlify serves it as plain files before any redirect rule applies. +# Gold (apps/gold) is a separate Vite app built with base /pt-br/gold/ and copied into the +# published tree next to the prerendered locale pages (the pt-BR directory; Netlify matches +# files case-insensitively), so it is served as plain files before any redirect rule applies. # Gold's build reads these site variables (set in the Netlify UI for all contexts): # VITE_PRIVY_APP_ID – the Privy app id (without it Gold renders a config error); the # original gold.satoshipay.io release used cmtiwhqgf01uu0el8lx3ejr35 @@ -18,7 +19,7 @@ # own domain; this build does not include it. [build] - command = "cd ../.. && bun install --frozen-lockfile && bun run build:shared && bun run build:sdk && bun run build:frontend && bun run build:gold && mkdir -p apps/frontend/dist/client/gold && cp -R apps/gold/dist/client/. apps/frontend/dist/client/gold/" + command = "cd ../.. && bun install --frozen-lockfile && bun run build:shared && bun run build:sdk && bun run build:frontend && bun run build:gold && mkdir -p apps/frontend/dist/client/pt-BR/gold && cp -R apps/gold/dist/client/. apps/frontend/dist/client/pt-BR/gold/" publish = "dist/client" # Netlify's default ignore check only diffs the base directory, so a commit touching only # apps/gold or the shared/sdk packages would be skipped as "no content change". Build when diff --git a/apps/frontend/src/tests/netlify-redirects.test.ts b/apps/frontend/src/tests/netlify-redirects.test.ts index ca256fa62..144e8831c 100644 --- a/apps/frontend/src/tests/netlify-redirects.test.ts +++ b/apps/frontend/src/tests/netlify-redirects.test.ts @@ -11,14 +11,16 @@ const redirects = readFileSync(new URL("../../_redirects", import.meta.url), "ut }); describe("Netlify redirects", () => { - it("routes only the widget shell and the gold alias through lowercase Portuguese paths", () => { + it("routes only the lowercase Portuguese widget path through the SPA shell", () => { expect(redirects.filter(rule => rule.from.startsWith("/pt-br"))).toEqual([ - { from: "/pt-br/widget", status: "200", to: "/_shell.html" }, - { from: "/pt-br/gold", status: "200", to: "/gold/index.html" }, - { from: "/pt-br/gold/*", status: "200", to: "/gold/:splat" } + { from: "/pt-br/widget", status: "200", to: "/_shell.html" } ]); }); + it("redirects the unprefixed gold path to its Brazilian edition", () => { + expect(redirects).toContainEqual({ from: "/gold/*", status: "301", to: "/pt-br/gold/:splat" }); + }); + it("keeps unknown paths on the real 404 fallback", () => { expect(redirects).toContainEqual({ from: "/*", status: "404", to: "/404.html" }); }); diff --git a/apps/gold/CLAUDE.md b/apps/gold/CLAUDE.md index 409463ac2..d51d960f5 100644 --- a/apps/gold/CLAUDE.md +++ b/apps/gold/CLAUDE.md @@ -4,10 +4,12 @@ Brazil-first consumer app for buying and selling PAX Gold with PIX through `@vor branded "ouro. by Vortex". Plain JavaScript React 19 + Vite app with Privy embedded wallets; imported as a snapshot from `pendulum-chain/vortexperiments`, which keeps the pilot history. -- It is served by the frontend Netlify site at `https://www.vortexfinance.co/gold/`: - `apps/frontend/netlify.toml` builds it with Vite `base: "/gold/"` and copies `dist/client` - into the frontend's `dist/client/gold/`. Like `/widget`, the canonical path is unprefixed - and `/pt-BR/gold` is a rewrite alias in `apps/frontend/_redirects`. +- It is served by the frontend Netlify site at `https://www.vortexfinance.co/pt-br/gold/`: + `apps/frontend/netlify.toml` builds it with Vite `base: "/pt-br/gold/"` and copies + `dist/client` into the frontend's `dist/client/pt-BR/gold/`, beside the prerendered locale + pages. The site is locale-first (`/pt-br/business`, `/pt-br/widget`), so future markets go + to `/es-mx/gold/` etc.; the unprefixed `/gold/` 301s to the Brazilian edition until an + international landing exists (`apps/frontend/_redirects`). Reference public assets through `import.meta.env.BASE_URL`, never as root-relative `/brand/...` paths. - The API base comes from `VITE_SIGNING_SERVICE_PATH`, like the frontend: a path such as diff --git a/apps/gold/README.md b/apps/gold/README.md index a95f7b418..13aca44aa 100644 --- a/apps/gold/README.md +++ b/apps/gold/README.md @@ -32,4 +32,4 @@ Set `VITE_DEMO_MODE=false` and build with `bun run build`. The browser integrati The frontend never receives the Privy App Secret or a Vortex server secret. Vortex session tokens remain in session storage; CPF and identity documents are not persisted by the app. -Live deployment: [https://www.vortexfinance.co/gold/](https://www.vortexfinance.co/gold/), built and served by the frontend Netlify site (see `apps/frontend/netlify.toml` and `CLAUDE.md` here). The pilot evidence, deployment notes and production checklist from the standalone `gold.satoshipay.io` release stay in `pendulum-chain/vortexperiments`. +Live deployment: [https://www.vortexfinance.co/pt-br/gold/](https://www.vortexfinance.co/pt-br/gold/), built and served by the frontend Netlify site (see `apps/frontend/netlify.toml` and `CLAUDE.md` here). The pilot evidence, deployment notes and production checklist from the standalone `gold.satoshipay.io` release stay in `pendulum-chain/vortexperiments`. diff --git a/apps/gold/index.html b/apps/gold/index.html index bbada2e9f..ac7dc3879 100644 --- a/apps/gold/index.html +++ b/apps/gold/index.html @@ -6,7 +6,7 @@ - + ouro. by Vortex — Compre ouro com PIX diff --git a/apps/gold/vite.config.mjs b/apps/gold/vite.config.mjs index 9f2f29d30..b63d80622 100644 --- a/apps/gold/vite.config.mjs +++ b/apps/gold/vite.config.mjs @@ -2,7 +2,7 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; export default defineConfig({ - base: "/gold/", + base: "/pt-br/gold/", build: { outDir: "dist/client", },