<doxa-country-map> reads its profile from profile-config, like the manifest's own snippet
({"profile":"country-map",...}) and like this site's other maps (profile: 'doxa-simple-map').
Without it the element drew nothing but 'Profile "" not found' on every country page
(rega, 1440 and 390, en and ar).
On the subdomain and Plugin Studio branches, the Research item became a plain link to the gallery's
own address, and it took the external links' markup: target=_blank and the external-link icon.
Choosing Research opened a new tab and left the reader on the page they were on. On /embed-test that
read as a page that would not let them go to Research. The gallery is this site's own, so it now
opens in the same tab like every other page. Only the real external link (Give) opens a new one.
popupHtml() escaped the name, the subtitle, the stats, the description, the photo address and the two
button labels, but put prayUrl and profileUrl into href raw. Both end in the people group's slug,
which comes from the API, so a slug with a double quote would close the attribute. Both now go
through the escapeHtml the popup already uses. Found by the regions plugin, which fixed the same
inherited code in its dx-maps port.
LAPTOP-6WAY described two routes. The third, the public Plugin Studio (bun run laptop plugin-studio),
had only its compose profile and the command's help. It now has its own section: what the command
starts, the addresses, the admin password for publishing and PocketBase's dashboard, how the two
per-request addresses are set, and what to set while dx-maps' development has no public mode yet.
"Checked" records what was proven on 2026-09-29, the halves separately, and says the one command
end to end has not been run yet.
The subdomain and Plugin Studio routes both publish the dx-maps container on port 4616. Starting one
while the other runs failed inside docker compose with a port error. bun run laptop now stops first
and says to run bun run laptop down.
dx-base's three commits from research-gallery-plugin-studio (the runtime loader, check:origins and
its lint pass) apply here unchanged: the code is byte-identical to that branch. What differs is what
the two settings point at on this route. The Research Gallery is the research site the team's
dx-maps container serves, and the maps load from the container's published tree, which the research
subdomain serves at /dx-maps (the Studio's host serves the same tree at /cdn/dx-maps; both send
CORS). The comments, .env.example and DX-MAPS-GALLERY.md now say so, with this route's laptop
values (research.localhost:4615, as compose.laptop.yaml already sets).
DX-MAPS-GALLERY.md's "Run it" said no .env is needed for /research. That stopped being true when the
default maps host was removed, so it now names the one setting the maps need.
check:origins: 15 problems on research-gallery-subdomain before, PASS (306 files) after.
The map slot's template puts one attribute per line. The runtime loader and the
map composable put one statement per line. The origins check drops a redundant
pair of parentheses. No behaviour changes. Every file this branch touched now
has no more lint findings than it had before.
bun scripts/check-runtime-origins.ts (bun run check:origins) holds the
branch's rule:
- nuxt.config declares neither per-deployment address;
- under app/, only the runtime loader reads dxMapsBase, and only it and the
menu read researchGalleryUrl;
- no source file or static page names a deployment host (nuxtbase.app,
sslip.io, a *.localhost address or a 46xx laptop port).
It refuses to pass on fewer than 50 files.
This branch: PASS, 306 files. The subdomain branch it was cut from fails
with 12 problems: two addresses in nuxt.config, six reads under app/, and
the hardcoded maps host in nuxt.config and in the two static pages.
This branch sends readers to the Research Gallery (the public Plugin Studio
on its own subdomain) and loads the site's maps from that subdomain's /cdn.
Both addresses belong to the deployment:
NUXT_PUBLIC_RESEARCH_GALLERY_URL https://research.<host>/
NUXT_PUBLIC_DX_MAPS_BASE https://research.<host>/cdn/dx-maps
About 4,000 pages are prerendered, and a prerendered page carries the
build's runtime config, so an address read there is baked into the build.
One build could then serve only one deployment; the CDN branch failed that
way. So neither address is in nuxt.config any more:
- the server reads both from its environment per request
(server/utils/dx-runtime.ts);
- GET /api/dx-runtime answers them, no-store. Every map (DoxaMapSlot via
useDoxaMap, /research, /embed-test, and the static pages under public/)
asks it first, then loads its bundle from that tree. The map's element is
added only once the tree is known, and the map bundle's preload is added
then, still while Mapbox downloads;
- every gallery link, the Research menu item, and the /regions and
/countries index rules go to this site's /research-gallery?tab=&lang=,
which 302s (no-store) to the gallery. It works without JavaScript, and a
prerendered page names no host;
- old /js/doxa-maps and /embed/doxa-maps-build links are redirected per
request by server/middleware/legacy-map-links.ts. They were build-time
route rules.
No fallback host: the maps-dev and research defaults are gone. When a
setting is unset, /research-gallery answers 503 and each map says which
setting to set. Changing an address needs a restart, not a rebuild.
A second compose profile beside "subdomain":
- dx-maps-studio: the dx-maps container with ACCESS=public on research.localhost:4616, the
PUBLIC Plugin Studio. There is no sign-in provider; publishing and PocketBase's dashboard ask
for ADMIN_PASSWORD. Its /cdn is built from main with EMBED_BASE_URL=http://research.localhost:4616/cdn.
- dxlife-studio: this site's research-gallery-plugin-studio branch on :4614. Its two settings,
NUXT_PUBLIC_RESEARCH_GALLERY_URL and NUXT_PUBLIC_DX_MAPS_BASE (names agreed with dx-base), point
at the Studio and its /cdn, and are read at run time.
The two routes use separate data volumes. .env.laptop gains a generated ADMIN_PASSWORD (never
printed). laptop-dxlife.sh takes DXLIFE_PORT (4613 subdomain, 4614 plugin-studio).
The Research Gallery now has two routes: drop-in (this site alone, no Docker, the default)
and subdomain (the dx-maps team container with PocketBase). The CDN route is retired.
compose.laptop.yaml runs the subdomain route on 127.0.0.1:
- dx-maps: the image the team's server runs, built from dx-maps' root Dockerfile. It carries
the Plugin Studio, PocketBase and the research site on research.localhost:4615, and
publishes main by itself.
- a local sign-in provider with admin, designer and plain-member users. It runs inside dx-maps'
network, so localhost:4620 is the same address for the browser and the container.
- this site on the subdomain branch, pointed at the research site.
scripts/laptop.ts makes .env.laptop (secrets, never committed), checks Docker's memory (and
names what to close or the lighter route), starts the three, waits for each and prints the
addresses. LAPTOP-6WAY.md describes the two routes.
Checked on a Docker host tunnelled to a laptop-like browser: 20/20 route checks (sign-in,
roles, PocketBase's team API, the research site, /regions) and check-embed-6way 7/7 at 6/6.
The gallery now gets its own origin on the laptop, as it does on the team's server, while the
maps stay on localhost:4610. Chrome and Firefox send any *.localhost name to this computer;
Safari and command-line tools may need `127.0.0.1 research.localhost` in /etc/hosts.
Checked: the tree server answers research.localhost:4610 (gallery 200, with ?tab= and
&lang=ar; manifest 200; the bare root 404, so the address keeps its /index.html).
NUXT_PUBLIC_DX_MAPS_BASE now defaults to https://maps-dev.nuxtbase.app/cdn/dx-maps (the Plugin Studio
container's /cdn). Set it empty to use this site's own public/dx-maps copy; set it to another tree URL to
use that.
Set, the gallery script and its tree-base come from that URL (e.g. https://maps-dev.nuxtbase.app/cdn/dx-maps).
Unset, the page uses this site's own /dx-maps/ copy exactly as before. Both modes proven on the dev
server: 0 console errors, the gallery tabs draw, and every dx-maps request goes to the chosen host.
public/dx-maps is replaced with the dx-maps build tree from doxa-maps main 9ce04ffea (28 bundles);
the gallery's manifest integrity matches the served doxa-maps-spa.js.
The Research page embeds the whole Research Gallery with the JS embed. Every embed URL is built at
runtime from the origin serving the page (tree-base = window.location.origin + /dx-maps), so the same
build works on a laptop, staging or production.
The previous Research page (the "By Region" link, the single research map and the UUPG list) is NOT
deleted: it is back in the page, switched off by SHOW_LEGACY_RESEARCH = false. The two old scripts
public/js/doxa-simple-map.js and doxa-research-map.js are restored too, unused, so nothing DX-life
relied on is removed.
The home, pray and adopt maps ran Mapbox GL, the geocoder and the map bundle one after
another, so on a cold first visit the slot stayed empty while ~1.8 MB downloaded in series.
Preload hints now fetch all three in parallel (they still run in order), and the slot shows a
quiet spinner (aria-busy) until the map element is defined.
The maps' build tree is now public/dx-maps/ (doxa-maps main 09014f8a), replacing
public/doxa-maps/. The Research gallery, the home, pray and adopt maps, /embed/map/ and
/research/doxa-research-map.html all load from it; the old /js/doxa-simple-map.js and
/js/doxa-research-map.js are removed (no aliases). Mapbox GL moves to v3.24.0, the version
the bundles are built with. With no Mapbox token configured, the home, pray and adopt maps
use the keyless MapLibre engine instead of refusing to start. See DX-MAPS-GALLERY.md.
The Research page now shows the Research Gallery (every research map, dashboard and list)
filling the page below the header, on desktop and phone. It replaces the single research
map, the UUPG list and the By Region link.
public/doxa-maps/ is the doxa-maps build tree (doxa-maps main 196ad168), so this site is
the gallery's CDN. The page loads one script and adds one element. It follows the site
language, and without a Mapbox token it uses the keyless MapLibre engine.
See DX-MAPS-GALLERY.md.
- serve the per-language terminology editions at /about/definitions
with the About sidebar; /terms redirects there
- title every edition "Definitions" to match the sidebar label
- drop the self-referencing link to the Definitions page
- add an Arabic edition built from the Arabic glossary
- point the add-language and sync-language skills at the new route
- delete the bundle loader composable and the unused slot component
- strip the site-wide embed from app.vue, leaving the layout shell
- drop the runtime config keys, custom element tag and env entries
- remove the login opt-in and the preconnect to the feedback host
- site strings, map widget locales and /terms editions for ar, de, es,
fr, hi, it, pt, ro, ru and zh
- patch the standalone map bundle in place (it has no build profile) and
rebuild the two profiled bundles from the updated source locales
- fix defects the sweep surfaced: the ru vision headline read "all
unmarried people will be married by 2033", ro used popor (nation) as
the people-group label including the homepage h1, and ar inverted
"moves from unengaged to engaged"
- correct en.ts, which claimed UUPG and WAGF stay unchanged in every
edition; es ships GENANC/FMAD, pt PNANE and de UVG/VUVG
- render the filter dropdown's empty-state through i18n, so the
no_options translation it already computed reaches the component
- a term with an acronym now yields the acronym as its own pair, so a
bare UUPG in source text takes this language's acronym instead of
whatever the model invents
- sync-language says the wording never carries the acronym, and names
the strings that hold a bare one