Skip to main content

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 (wrangler for local dev + deploy).
  • Drizzle ORM against Neon Postgres with the pgcrypto extension enabled for column-level encryption of PII (see privacy). Two connection factories in src/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.dev via .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) with typescript-eslint and eslint-plugin-import-x.
  • tsconfig base (tsconfig.base.json) — strict mode, ES2022, bundler resolution.
  • Prettier 3.8 defaults.
  • Vitest base config.

Third-party services

ServiceRole
Apple / GoogleNative OAuth for user identity; ID tokens verified against their JWKS
InfiniaKYC (HOSTED), virtual accounts (GBP / EUR / BRL), FX, PIX / FPS / SEPA payouts
NeonPostgres — production + branch DB per PR
CloudflareWorkers (API), Pages (web + docs), Hyperdrive (Postgres pooling)
Expo (EAS)Mobile builds & OTA updates
GitHubSource, 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.