Idiomatically is a site for exploring and connecting equivalent idioms across languages and locales. Visit the production site at idiomatically.net.
- React 19 and React Router 8 Framework Mode
- Server-side rendering with hydrated client-side navigation
- Express 5 serving the React application, GraphQL API, and authentication on one origin
- Apollo Server 5 and Apollo Client 4
- Better Auth with Google OAuth and MongoDB-backed sessions
- MongoDB 7
- Ant Design 6
- Vite 8 and TypeScript 7
- Playwright end-to-end characterization tests
Public idiom list, language directory, and detail routes load through the local GraphQL API during server rendering, so their content is present in the initial HTML. Client-side navigation continues to use React Router without full-page reloads. Authenticated users can propose new idioms and changes; administrators can edit, accept, or reject those proposals.
Local development requires:
- Node.js 22 (
lib/.nvmrc);lib/package.jsonrequires 22.22 or later - npm 11 (
lib/package.jsonpins npm 11.6.2) - MongoDB 7, either installed locally or run through Docker
Install the application dependencies first:
cd lib
npm ciThen start MongoDB with either Homebrew:
brew services start mongodb-community@7.0or Docker:
npm run db:startSeed the development database and start the unified application server:
npm run db:seed
npm run devThe commands after cd lib are intended to run from the lib directory.
npm run db:seed adds an idempotent, local-only demo dataset with connected
idioms across multiple languages. Re-running it refreshes only the seeded
records and leaves manually created idioms untouched.
Open http://localhost:3000. Vite development middleware, React Router SSR, GraphQL, and authentication all run on that single origin.
The committed lib/.env.development configuration enables a local role picker
for General, Contributor, and Administrator users. It exercises Better Auth
sessions plus the application's real role and GraphQL authorization paths
without contacting Google.
To test Google OAuth, create a local override, set
LOCAL_AUTH_ENABLED=false, and add Google credentials:
cp .env.example.local .env.development.localRegister these authorized redirect URIs with Google:
http://localhost:3000/api/auth/callback/google
https://idiomatically.net/api/auth/callback/google
Google supports localhost callbacks, so ngrok is not required.
This manual Google login is the only way to verify the complete provider round-trip before production. The automated suite also verifies that Better Auth creates a Google authorization request with OAuth state, PKCE, a state cookie, and the expected callback URL.
After deploying, run the non-interactive authentication and SEO smoke checks:
npm run auth:smoke -- https://idiomatically.net
npm run seo:smoke -- https://idiomatically.netThe authentication check validates the deployed Better Auth route and callback
URL without logging in or exposing Google credentials. The SEO check validates
canonical URLs, redirects, pagination errors, structured data, and sitemap
behavior. Before directing users to a new deployment, manually sign in once
through https://idiomatically.net/login using a Google test account you
control. If the Google OAuth consent screen is in testing mode, add that account
as an authorized test user first. Verify that Google returns to Idiomatically,
the user is signed in, and /me loads successfully. New accounts receive the
General role unless their email is listed in ADMIN_EMAILS.
Useful commands:
npm run dev # unified development server
npm run codegen # regenerate GraphQL schema and typed artifacts
npm run typecheck # React Router type generation and TypeScript
npm run build # production React Router build
npm run check # typecheck followed by the production build
npm run test:e2e # isolated Chromium end-to-end suite
npm run test:e2e:headed # end-to-end suite with a visible browser
npm run test:e2e:report # open the most recent Playwright HTML report
npm run auth:smoke -- https://idiomatically.net
npm run seo:smoke -- https://idiomatically.net
npm run --silent seo:content-report -- https://idiomatically.net > seo-content.csv
npm run db:stop # stop the Docker MongoDB serviceInstall Chromium once before the first local end-to-end test run:
npx playwright install chromiumThe content report produces a prioritized CSV of idioms with missing or short
descriptions, literal translations, or transliterations. The end-to-end suite
starts the application on port 3100, resets the idiomatically-e2e database
before every test, and stores failure traces and screenshots under
lib/test-results.
For local development, Docker Compose is used to run MongoDB through
npm run db:start; the application itself runs through npm run dev. The
production Dockerfile is built by the deployment workflow described below.
Production requires:
SERVER_URL: public HTTPS origin, currentlyhttps://idiomatically.netDB_CONNECTION: MongoDB connection stringMONGO_DB: MongoDB database nameBETTER_AUTH_SECRET: non-placeholder secret with at least 32 charactersGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET: Google OAuth credentials
Optional settings include PORT, comma-separated ADMIN_EMAILS, and
SENDGRID_API_KEY for proposal notifications. LOCAL_AUTH_ENABLED=true is
available only outside production. Environment-specific files are loaded from
lib/.env.<NODE_ENV> and then lib/.env.<NODE_ENV>.local, with the local file
taking precedence.
Production startup fails if SERVER_URL is missing, is not a public HTTPS URL,
the Better Auth secret is missing or too short, or Google credentials are
missing or placeholders.
Pushing to the release branch builds and publishes an immutable container
tagged with the full commit SHA. The workflow also updates the production
alias, deploys the immutable SHA tag to Azure, and verifies both authentication
configuration and production SEO behavior.
To roll back, run the Deploy production workflow manually against the
release branch and enter the full 40-character commit SHA from a previous
successful deployment as image_tag. The workflow verifies that image exists,
deploys it directly, and reruns both production smoke checks.
The Node CI workflow runs on every push and pull request using Node.js 22
and MongoDB 7. It installs dependencies with npm ci, regenerates GraphQL
artifacts and rejects uncommitted generated changes, type-checks and builds the
application, installs Chromium, and runs the end-to-end suite.