Scope & Architecture

June 2026

What we're building: a country-agnostic fork of the Base Adresse Nationale (France's national address platform) — so any country can run the same stack with its own administrative geography, address format, and map tiles. France's existing BAN is the upstream source and reference implementation; the fork is validated against French data and workflows before adapting for other countries.

What the platform produces

The editor (mes-adresses) is the input side — the tool municipalities use to create and maintain a Local Address Base (BAL/LAB). The platform's actual output is:

OutputDescriptionUpdate freq.
Geocoding API HTTP endpoint /search?q=address → coordinates + structured result. The primary product consumed by downstream apps, GIS tools, emergency services. Real-time
National CSV download ~25 M address rows (France). One position per address, open license. The canonical bulk dataset. Daily
Vector tiles (MVT) Address tile layer for embedding in any MapLibre/Mapbox map. Real-time
WFS / WMS OGC services for traditional GIS tooling. Monthly

A BAL created in the editor flows through the pipeline and eventually appears in geocoding responses and in the national CSV. That's the visible result. The public portal (adresse.data.gouv.fr) is a GUI over the geocoder and download files specific to the French deployment — see the Portal section.

The six-repo pipeline

The full pipeline from address editing to geocodable output spans six components:

mes-adresses
Next.js · TypeScript
Editor UI — creates and edits the local address base
mes-adresses-api
NestJS · PostgreSQL + PostGIS · Redis
Editor backend — stores BAL, triggers publish to api-depot
publishes BAL CSV file
api-depot
NestJS · PostgreSQL
Submission gateway — versions BAL files, manages authorizations, notifies the platform
NOTIFY_BAN webhook
ban-plateforme
Express.js · MongoDB · Redis
Aggregation engine — consolidates all BALs + other sources, produces CSV + addok exports
addok bundle (CSV export)
addok-docker
Python · Docker
Geocoder — loads the ban-plateforme export, serves /search queries on :7878
adresse.data.gouv.fr out of scope
Next.js · French government DSFR design system
Public explorer + download portal — a GUI over the geocoder. Not part of the pluggable stack.
adresse.data.gouv.fr is out of scope. It is built on the French government DSFR design system — porting it requires a full reskin, not just translation. Downstream consumers (GIS tools, routing apps, emergency services) integrate the geocoder API directly. Suggested demo replacement: a MapLibre GL page (1–2 days) querying the geocoder. No localization required.

i18n scope: what actually needs translation infrastructure

ComponentHas UI?i18n needed?Rationale
mes-adresses Yes — full editor Yes — ~260 strings The only user-facing app in the stack. next-intl wired; EN + ES catalogs available.
mes-adresses-api No — REST API only No API error messages stay in technical English. Frontend does the display translation.
api-depot No — REST API only No ~24 strings, technical. Keep in English.
ban-plateforme No — aggregation engine No No user-facing surface.
addok-docker No — geocoder API No Returns structured JSON. Language-neutral.
adresse.data.gouv.fr Yes — public portal Skipped Out of scope. Would require i18n + full reskin.
i18n work is scoped to one repo: mes-adresses, ~260 strings. Wire next-intl and extract all ~260 strings into messages/fr.json. Adding a language later means creating a new JSON file — no code changes. Estimated effort: 16–24 h.

String count breakdown

CategoryStringsNotes
App-flow UI strings~260Labels, toasts, validation messages, status text — what users see in the editor
components/help~150 linesLong-form instructional prose — low priority, ship last
Legal / accessibility pages~100 linesFrench gov institutional content — rewritten per country, not translated
accent-tool.tsx43Not strings to translate — these ARE the accent characters (keyboard tool for street names)

The correct methodology is to grep for lines containing French accented characters, exclude non-UI categories (help prose, institutional pages, the accent keyboard tool), extract only quoted string literals, and deduplicate. A broader regex pass over all string literals yields a misleading count by capturing English technical strings, API paths, and TypeScript constants.

DB enum — separate problem

Six position type values are stored as French strings in the database: 'entrée', 'bâtiment', 'délivrance postale', 'montée', 'formation spéciale', 'présentation'. This is what shows as "entrée" on map pins. It cannot be fixed with next-intl alone — it requires a TypeORM migration to language-neutral DB keys (entrance, building, …), then display-translation via the i18n catalog.

Making the stack pluggable: what to abstract

Eight France-specific pieces need to be generalized. Priority order:

#WhatWhereAbstractionEffort
1 Administrative unit identifier
INSEE commune code everywhere
mes-adresses-api
api-depot
ban-plateforme
Replace commune: string with generic locality_id: string. Define LocalityService interface; FR COG = default impl. High
2 Bundled FR administrative database
@etalab/decoupage-administratif compiled into API
mes-adresses-api/libs/shared/src/utils/cog.utils.ts Abstract getLocality(id); FR COG becomes one pluggable data source. Modeled on existing yarn update-cog pipeline. High
3 Map tile sources
Hardcoded FR govt URLs in 3 JSON style files
mes-adresses/src/components/map/styles/*.json
styles/index.ts
Convert static JSON to env-templated objects. Add NEXT_PUBLIC_MAP_TILES_URL, NEXT_PUBLIC_MAP_GLYPHS_URL, NEXT_PUBLIC_MAP_SPRITES_URL. Medium
4 Locality search API
geo.api.gouv.fr for commune autocomplete
mes-adresses/src/lib/geo-api/index.ts URL already env-driven (NEXT_PUBLIC_GEO_API_URL). Reimplement ApiGeoService.searchLocalities() + getLocality(). Two methods; rest of app unchanged. Low
5 i18n framework in editor
~260 hardcoded French strings
mes-adresses/src/** Wire next-intl, extract all strings to messages/fr.json. Adding a language = new JSON file. High
6 Position type enum
French strings stored in DB: 'entrée', 'bâtiment'
mes-adresses-api entity + DB column Store language-neutral keys in DB ('entrance', 'building'…); translate display values in the frontend. Requires one TypeORM migration. Low
7 FR identifier column widths
commune_deleguee varchar(5), code_voie varchar(4)
mes-adresses-api/libs/shared/src/entities/ Generalize column lengths; rename to sub_locality_id, street_id. Migration required. Low
8 Authorization / habilitation
ProConnect (French govt SSO)
api-depot habilitation flow Make auth provider configurable. Phase 1: email-based pin only (already exists as fallback). ProConnect = optional plugin. Medium

Workstreams

WS1 String extraction + DB enum 16–24 h

Wire next-intl into mes-adresses and extract all ~260 French strings into translation catalogs. Strings stay in French in fr.json; adding a language means adding a new JSON file with no code changes.

  • Wire next-intl — key/namespace strategy, pluralization, date/number formatting
  • Extract all ~260 strings into messages/fr.json
  • TypeORM migration for the 6 DB position-type enum values → language-neutral keys
  • Wrap Evergreen UI components where needed; handle pluralization
  • Deliverable: app running in French with zero hardcoded strings
WS2 Pluggability layer 60–100 h

Implement the eight abstractions from the Pluggability slide. Priority order: locality identifier + COG abstraction (items 1–2) → map tile env vars (item 3) → geo search service (item 4) → position enum migration (item 6). Items 7–8 are lower priority and can follow.

  • Define LocalityService interface; FR COG = default implementation
  • Convert map style JSON files to env-templated objects
  • Generalize commune field and related column widths across all 3 backend repos
  • Position type enum: DB migration to language-neutral keys
WS3 Pipeline wiring for demo 16–28 h

Wire the submission and geocoding pipeline using the env vars and service interfaces established in WS2. French public services are kept where they don't write to the real BAN; everything that does is self-hosted locally.

  • Keep as public: geo.api.gouv.fr (commune search), FR government map tiles
  • Self-host: api-depot, ban-plateforme (with MongoDB), addok-docker
  • Configure via env vars set in WS2 — no hardcoded service URLs
  • Verify end-to-end: create BAL → publish to local api-depot → ban-plateforme consolidates → addok returns the address
WS4 Manual testing & demo 8–14 h

Verify the full pipeline end-to-end with French data. Seed dataset: a sample commune + BAL with voies and numéros. Build the lightweight geocoder demo page. Key flows to test:

  • Create a BAL → add voies + numéros → publish → geocoder returns the address
  • All editor UI displays correctly in French, no broken keys
  • CSV download contains the submitted address

Estimate summary

WorkstreamEffort
WS1 String extraction + DB enum16–24 h
WS2 Pluggability layer (8 abstractions)60–100 h
WS3 Pipeline wiring for demo16–28 h
WS4 Manual testing + demo page8–14 h
Total~100–166 h