Frontend Architectural choices
The frontend is a react application with a ruby on rails backend.
We use redux as a state manager with redux actions.
For the router we use react-router.
There are some peculiarities in the architectural choices that we will outline in this section.
Backend (Rails) architecture
- API-first Rails app serving a JSON REST API under 
/api/v1consumed by the SPA.- See 
config/routes.rbfor the full map. Major domains include: Locations, NDCs (texts, SDG linkages, content_overview), LTS, Net-zero, Country profile, Historical emissions, Socioeconomics, Quantifications, Metadata, Timeline, Stories, LSE Laws & Policies, Notifications, Key Visualizations, Zip files. Downloadable CSV/ZIP endpoints live under the/api/v1/data/*namespaces. - Controllers live in 
app/controllers/api/v1/**, backed by AR models inapp/models/**and JSON serializers inapp/serializers/api/v1/**. 
 - See 
 - Admin and jobs 
- Admin: Devise + ActiveAdmin; Sidekiq UI is mounted at 
/sidekiqfor authenticated admins. - Background processing via Sidekiq; configuration in 
config/initializers/sidekiq.rb. 
 - Admin: Devise + ActiveAdmin; Sidekiq UI is mounted at 
 - Data ingestion pipeline 
- Central orchestration in 
lib/tasks/db.rake:db:importchains dataset imports (locations, ndcs, sdgs, historical_emissions, adaptation, wri_metadata, wb_extra, timeline, quantifications, socioeconomics, stories, key_visualizations, country_profile, zip_files).db:reimportresets a set of tables then invokesdb:import(destructive; see task body for the exact list).
 - Dataset-specific tasks reside under 
lib/tasks/*.rake(e.g.,historical_emissions.rake,indc.rake,ndcs.rake,agriculture_profile.rake, etc.). 
 - Central orchestration in 
 - Geolocation 
- Uses MaxMind GeoLite2 to resolve user IP to a country code; see 
app/services/geolocation_service.rb. db:import_maxminddownloads the real DB (requiresMAXMIND_LICENSE_KEY). In development, you can force the real DB viaMAXMIND_REAL_DB=1or override withCW_USER_COUNTRY_OVERRIDE.
 - Uses MaxMind GeoLite2 to resolve user IP to a country code; see 
 - Persistence and environment 
- PostgreSQL is the DB (CI uses PostgreSQL 13). Local connection is read from 
POSTGRES_URL(config/database.yml). 
 - PostgreSQL is the DB (CI uses PostgreSQL 13). Local connection is read from 
 
Frontend (React) architecture
- Entry points and bootstrapping 
- Webpacker pack at 
app/javascript/packs/main.jsxrenders<App />into#root. app/javascript/app/app.jsxwiresProvider+BrowserRouterand builds the store fromapp/javascript/app/store.js(Redux + redux-thunk). The routerbasenameis computed at runtime based on containment.
 - Webpacker pack at 
 - Routing as data 
- Routes are defined as configuration in 
app/javascript/app/routes/and rendered withreact-router-config. - The tree contains two major branches: 
/embedand the main app/; the main app may be wrapped by a “contained” layout depending onisPageContained. 
 - Routes are defined as configuration in 
 - State and modules 
- Module-based structure: each feature co-locates component, actions, reducers, selectors, and styles.
 - Reducers are assembled via a 
handleActionswrapper and combined inapp/javascript/app/reducers.js, which composes three groups: providers (data-fetching modules), pages, and reusable components. - Async flows use 
redux-thunk. A large set of provider modules live underapp/javascript/app/providers/**and are attached to the store (seereducers.js). 
 - Styling and theming 
- CSS Modules with SCSS are the default; theming via 
react-css-themrfor reusable components. 
 - CSS Modules with SCSS are the default; theming via 
 - Environment-driven behavior 
- Frontend reads 
CW_API,ESP_API, andGFW_APIfrom the environment (injected at build time). Seeapp/javascript/app/data/constants.jsfor login URLs and other constants derived from these values. 
 - Frontend reads 
 
Routing model (Rails ↔ SPA)
- Rails serves the HTML shell at 
/and falls back toapplication#indexfor client-side routes. - API endpoints are strictly under 
/api/v1/**. The browser-only routes are handled by React Router; embedded experiences are mounted at/embed/*. 
Build system and asset pipeline
- Webpack 5 via Webpacker with custom configs under 
config/webpack/*:shared.jsinjects.envvalues, sets up CSS Modules, SCSS loaders, SVG sprite loader, file-loader assets, module aliases (app,components,routes), and a manifest plugin.development.jsconfigures the dev server (CORS headers, historyApiFallback, polling watch).production.jsadds Terser, MiniCssExtract, environment plugin (GA and API variables), WebP optimization, and gzip compression with hashed filenames.
 - Node version is pinned to 12.13.0 (
.nvmrc). Yarn 1.x is used across scripts. 
Testing and CI
- Frontend: Jest configured in 
jest.config.jswithrootDir: app/javascript/app, Babel transform, and moduleNameMapper for SCSS and path aliases. - Backend: RSpec lives under 
spec/**with controllers, models, services, factories, and JSON schema matchers. - GitHub Actions split suites: 
- Backend tests: bundle, set up Postgres service, prepare the test DB, run 
bundle exec rspec. - Frontend tests: set up Node/Ruby, install, prepare DB (for parity), run 
yarn test. - Security: Brakeman and bundle-audit.
 
 - Backend tests: bundle, set up Postgres service, prepare the test DB, run 
 
Environment and configuration
- Key environment variables (also see 
.env.sampleand_docs/env.md):POSTGRES_URL,REDIS_SERVER,CW_API,ESP_API,GFW_API,DEV_USER_ID,DEV_USER_TOKEN,MAXMIND_LICENSE_KEY, GA/Tag Manager IDs, and feature flags (FEATURE_*).
 - Docker compose is available for local orchestration of Rails, Webpack dev server, PostgreSQL, and Redis.
 
Useful entry points (by file path)
- Rails API surface: 
config/routes.rb - Data import orchestration: 
lib/tasks/db.rake - SPA entry and composition: 
app/javascript/packs/main.jsxapp/javascript/app/app.jsxapp/javascript/app/store.jsapp/javascript/app/reducers.jsapp/javascript/app/routes/routes.js
 - Environment-driven constants: 
app/javascript/app/data/constants.js - Webpack configuration: 
config/webpack/* - Tests: 
jest.config.js,spec/**