diff --git a/apps/api/.env.example b/apps/api/.env.example index 4cebb08..bf20945 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -21,9 +21,18 @@ PORT=3333 API_URL="http://localhost:3333" NODE_ENV="development" FRONTEND_URL="http://localhost:3001" # dashboard origin -CHECKOUT_URL="http://localhost:3002" # hosted checkout (apps/checkout) +CHECKOUT_URL="http://localhost:3003" # hosted checkout (apps/checkout, `next dev --port 3003`) TAVVIO_FEE_BPS=50 # default platform fee = 0.5% +# Base stamped onto every generated payment-link URL. It must point at the +# checkout app's `/l` route — the API appends `/` to it. +# +# Undocumented until now, so local setups fell through to the production +# default and every link created in development came out as +# https://pay.useroutr.com/: correct-looking, and not clickable on a +# machine that has no such host. Set it, or dev links go nowhere. +PAYMENT_LINK_BASE_URL="http://localhost:3003/l" + # ── Auth / crypto ──────────────────────────────────────────────────────── JWT_SECRET="replace-with-256-bit-random" JWT_EXPIRY="7d" @@ -71,7 +80,11 @@ STELLAR_ESCROW_HOLDING_SECRET="S..." # USDC's Stellar Asset Contract id, which the escrow contract moves. Distinct # from the classic asset issuer: Soroban addresses assets by contract id. # Derive with: stellar contract id asset --asset USDC: --network -STELLAR_USDC_SAC_TESTNET="C..." +# Testnet's value is filled in because it is public and deterministic — derived +# from USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, and +# verified against the live network (calling `symbol()` on it returns "USDC"). +# Leaving it as "C..." meant every developer re-derived the same constant. +STELLAR_USDC_SAC_TESTNET="CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" STELLAR_USDC_SAC_MAINNET="C..." # ── EVM RPC endpoints ──────────────────────────────────────────────────── diff --git a/apps/checkout/.env.example b/apps/checkout/.env.example new file mode 100644 index 0000000..e53f49e --- /dev/null +++ b/apps/checkout/.env.example @@ -0,0 +1,23 @@ +# Checkout — copy to .env.local for local development. +# +# Both variables are NEXT_PUBLIC_*, so they are inlined into the client bundle +# at build time. Neither is a secret: the API base is public by definition, and +# a Reown project id identifies the app rather than authenticating it. Do not +# add anything here that must stay private. + +# Origin of the Useroutr API. The `/v1` prefix is added by the client — pass the +# origin alone, or with the prefix; `resolveApiBaseUrl` normalises both to +# exactly one `/v1`. The dashboard reads the same variable and agrees on its +# meaning, which it did not always. +# +# Defaults to http://localhost:3333 when unset, which is the local API's port. +NEXT_PUBLIC_API_URL="http://localhost:3333" + +# Reown (formerly WalletConnect) project id, used by RainbowKit for the EVM +# wallet-connect modal. Create one — free — at https://cloud.reown.com. +# +# Without it the code falls back to the string "placeholder", Reown answers 403, +# and the wallet modal opens empty with only an unattributed 403 in the console +# to explain why. The Stellar payment path does not use this and works without +# it; only the EVM chains need it. +NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID="" diff --git a/apps/checkout/.gitignore b/apps/checkout/.gitignore index 5ef6a52..9b105bc 100644 --- a/apps/checkout/.gitignore +++ b/apps/checkout/.gitignore @@ -32,6 +32,10 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +# ...except the committed template. The root .gitignore already un-ignores it, +# but this file's blanket `.env*` is more specific and was winning, so a new +# apps//.env.example silently never got added. +!.env.example # vercel .vercel diff --git a/apps/checkout/providers/WalletProviders.tsx b/apps/checkout/providers/WalletProviders.tsx index 25e3c27..adb9719 100644 --- a/apps/checkout/providers/WalletProviders.tsx +++ b/apps/checkout/providers/WalletProviders.tsx @@ -26,9 +26,36 @@ import { RainbowKitProvider, getDefaultConfig } from "@rainbow-me/rainbowkit"; // STELLAR_NETWORK (testnet → sepolia variants, mainnet → mainnet). The // frontend doesn't know which side the API is on; including both lets // RainbowKit's switcher offer whichever the customer's wallet is on. +const WALLETCONNECT_PROJECT_ID = + process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID ?? "placeholder"; + +// "placeholder" is not a real project id, so Reown answers 403 and the wallet +// modal comes up empty. The only clue was an unattributed 403 in the console, +// which reads like a network blip rather than a missing variable — say what it +// is, in development. +// +// The flag is on `window` rather than module scope because Next re-evaluates +// this module across routes and HMR passes, which printed the same warning +// three times on a single page load. +const WARNED_FLAG = "__useroutrWalletConnectWarned"; + +if ( + process.env.NODE_ENV !== "production" && + WALLETCONNECT_PROJECT_ID === "placeholder" && + typeof window !== "undefined" && + !(window as unknown as Record)[WARNED_FLAG] +) { + (window as unknown as Record)[WARNED_FLAG] = true; + console.warn( + "[checkout] NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID is unset, so wallet " + + "connect will fail with a 403 from Reown. Create a project at " + + "https://cloud.reown.com and set the variable in apps/checkout/.env.local.", + ); +} + const config = getDefaultConfig({ appName: "Useroutr Checkout", - projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID ?? "placeholder", + projectId: WALLETCONNECT_PROJECT_ID, chains: [ mainnet, sepolia, diff --git a/apps/dashboard/.gitignore b/apps/dashboard/.gitignore index 5ef6a52..9b105bc 100644 --- a/apps/dashboard/.gitignore +++ b/apps/dashboard/.gitignore @@ -32,6 +32,10 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +# ...except the committed template. The root .gitignore already un-ignores it, +# but this file's blanket `.env*` is more specific and was winning, so a new +# apps//.env.example silently never got added. +!.env.example # vercel .vercel diff --git a/apps/www/.gitignore b/apps/www/.gitignore index 5ef6a52..9b105bc 100644 --- a/apps/www/.gitignore +++ b/apps/www/.gitignore @@ -32,6 +32,10 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +# ...except the committed template. The root .gitignore already un-ignores it, +# but this file's blanket `.env*` is more specific and was winning, so a new +# apps//.env.example silently never got added. +!.env.example # vercel .vercel