Tech stack
Runtime & language
- TypeScript ~5.9 across all packages, strict mode via
packages/config/tsconfig.base.json. - Node 22 (see
.nvmrc). - pnpm 9.15 workspaces + Turborepo 2.9.
API — apps/api
- Hono 4.12 on Cloudflare Workers (
wranglerfor local dev + deploy). - Drizzle ORM against Neon Postgres with the
pgcryptoextension enabled for column-level encryption of PII (see privacy). Two connection factories insrc/db/index.ts:createHyperdriveDb()— production, via Cloudflare Hyperdrive (node-postgres over Hyperdrive binding).createDb()— dev & tests, via Neon HTTP driver.
- Zod for request validation (schemas shared from
@gringo-pay/shared). - Vitest + @cloudflare/vitest-pool-workers for tests.
- Key SDKs:
jose— Apple/Google id_token verification against JWKS + session JWT signing.
- Bindings (see
apps/api/wrangler.toml):HYPERDRIVE— Neon Postgres connection.- Secrets (via
wrangler secret put):SESSION_SECRET,PII_ENCRYPTION_KEY,INFINIA_API_USERNAME,INFINIA_API_PASSWORD,INFINIA_WEBHOOK_SECRET. - Public vars:
APPLE_BUNDLE_ID,GOOGLE_OAUTH_CLIENT_ID,INFINIA_COMPANY_ID,INFINIA_BASE_URL.
See auth for the auth model and payment-providers for the Infinia integration surface.
Mobile — apps/mobile
- Expo SDK ~54 with React Native 0.81 and React 19.
- Expo Router 6 (file-based routing under
app/). - NativeWind 4 (Tailwind on React Native).
- expo-apple-authentication — native Sign in with Apple.
- @react-native-google-signin/google-signin (or Expo AuthSession's Google provider) — Google OAuth.
- expo-secure-store — Keychain / Keystore storage for the session JWT.
- expo-camera — PIX QR scanning.
- expo-web-browser — hosted KYC webview (Infinia's HOSTED flow URL).
- Jest + jest-expo + @testing-library/react-native for tests.
- EAS Build for iOS/Android binaries.
Web — apps/web
- Astro 6 deployed to Cloudflare Pages via
@astrojs/cloudflare. - Currently a single marketing page.
Docs — apps/docs
- Docusaurus 3.9 with the classic preset (TypeScript).
- Deployed to Cloudflare Pages at
https://gringo-pay-docs.pages.devvia.github/workflows/docs.yml.
Shared — packages/shared
- Zod schemas for every API endpoint (request + response) and shared domain types.
- PIX QR parser (
parsePixPayload) and PIX key validators. - Pricing math (
applyGringoSpread). - Vitest.
Config — packages/config
- ESLint 10 flat config (
eslint.config.js) withtypescript-eslintandeslint-plugin-import-x. - tsconfig base (
tsconfig.base.json) — strict mode, ES2022, bundler resolution. - Prettier 3.8 defaults.
- Vitest base config.
Third-party services
| Service | Role |
|---|---|
| Apple / Google | Native OAuth for user identity; ID tokens verified against their JWKS |
| Infinia | KYC (HOSTED), virtual accounts (GBP / EUR / BRL), FX, PIX / FPS / SEPA payouts |
| Neon | Postgres — production + branch DB per PR |
| Cloudflare | Workers (API), Pages (web + docs), Hyperdrive (Postgres pooling) |
| Expo (EAS) | Mobile builds & OTA updates |
| GitHub | Source, CI |
Observability tooling: deferred decision. The observability framework is vendor-agnostic; specific tooling (Cloudflare Analytics Engine + Sentry vs Axiom vs Honeycomb vs Grafana Cloud) is picked when we start instrumenting. See observability § tooling for the options landscape and decision criteria.
Not used: Bridge, Privy, any embedded wallet, any on-chain infrastructure (viem, RPC, paymasters), USDC or any other crypto asset. See custody-model for the trade-off analysis behind that choice.