No description
  • TypeScript 96.6%
  • CSS 1.7%
  • Shell 1%
  • Dockerfile 0.4%
  • JavaScript 0.3%
Find a file
Vincent Billey 2279513e80
feat(jdm): every public URL ends in a slash; the admin moves to /administration (#211)
* feat(jdm): every public URL ends in a slash; the admin moves to /administration

Production WordPress publishes one URL form, with a trailing slash, and
301s everything else onto it; the cutover must re-point no inbound link.
#57 did that for articles and the archives followed by hand. This makes it
the site's rule: a `trailingSlash` middleware on the public layouts
(`_main`, and a new pathless `petitions.public` around the petition pages
and the event page) 301s a slash-less GET/HEAD onto the slashed path, query
kept, before any loader runs. Resource routes sit under no such layout and
are never redirected. React Router 8's trailing-slash-aware data requests
are the default, so nothing is enabled — but the middleware sees a data
request's URL raw (`/x/_.data`), contrary to the upgrade guide, and strips
the suffix itself; a file-shaped last segment is never slashed.

`petition-url.ts` builds every petition link (sitemap, canonical, og:url,
emails, cards, the menu default, the link resolvers) in the slashed form so
nothing the app writes bounces.

The admin moves from /petitions/admin to /administration — the sibling
app's prefix — slash-less like OCF's: it was never on WordPress and nothing
indexes it. One splat route 301s every old admin URL with its query;
`administration` joins the reserved page slugs. Production nginx must route
/administration to this app before this deploys.

Fixes #81

* fix(jdm): restore the captured fixtures, test the admin redirect, finish the prefix sweep

- The three WordPress capture fixtures are back byte for byte: Prettier run
  from the app directory does not read the root ignore file, and the reformat
  had lowercased the hex colour one assertion checks for.
- tests/admin-redirect.test.ts pins the splat redirect's three shapes: the
  bare prefix, a deep path, a kept query.
- The README, the seed script's comment, the admin shell's comment and the
  reimportable report's printed instruction say /administration; the doc's
  retired « still slash-less » sentence is gone.

* fix(jdm): read the framework's normalized url in the trailing-slash middleware

The middleware read `request.url`, the raw data request, and stripped the
`.data` suffix by hand — which also copied the framework's own `_routes`
param into the redirect. Every data function, middleware included, is
handed a normalized `url` with the suffix and those params removed; the
rule now reads that and nothing else. The petition page's privacy-policy
link goes through `contentPagePath`, the last hand-written slash-less link.
2026-09-09 09:50:57 +02:00
.claude/rules feat(files): a file library — documents stored as-is, tags, usages (#207) 2026-09-07 21:22:26 +02:00
.github/workflows feat(files): a file library — documents stored as-is, tags, usages (#207) 2026-09-07 21:22:26 +02:00
.yarn/releases chore: add monorepo workspace root (yarn workspaces, mise, gitignore) 2026-07-26 16:25:36 +02:00
apps feat(jdm): every public URL ends in a slash; the admin moves to /administration (#211) 2026-09-09 09:50:57 +02:00
docs feat(jdm): every public URL ends in a slash; the admin moves to /administration (#211) 2026-09-09 09:50:57 +02:00
packages feat(jdm): every public URL ends in a slash; the admin moves to /administration (#211) 2026-09-09 09:50:57 +02:00
scripts feat(jdm): a database of the YouTube channel's videos, with sync + admin (#171) 2026-09-03 07:31:15 +02:00
.dockerignore Workspace-aware Docker image builds (#2) 2026-07-27 21:31:15 +02:00
.gitignore Blue-green zero-downtime deploy for both apps (#4) 2026-07-29 20:37:53 +02:00
.mise.toml chore: add monorepo workspace root (yarn workspaces, mise, gitignore) 2026-07-26 16:25:36 +02:00
.prettierignore feat(jdm): import WordPress articles into shared content tables (#31) 2026-08-03 21:48:52 +02:00
.prettierrc chore: add repo-wide prettier config, gate, and reformat (#10) 2026-07-31 23:28:39 +02:00
.yarnrc.yml chore: add monorepo workspace root (yarn workspaces, mise, gitignore) 2026-07-26 16:25:36 +02:00
CLAUDE.md feat(files): a file library — documents stored as-is, tags, usages (#207) 2026-09-07 21:22:26 +02:00
docker-compose.yml Consolidate dev infrastructure: unified compose, root CI, port convention (#1) 2026-07-26 21:18:30 +02:00
package.json docs: give the architecture and feature essays one home under docs/ (#132) 2026-08-28 11:10:58 +02:00
README.md docs: give the architecture and feature essays one home under docs/ (#132) 2026-08-28 11:10:58 +02:00
yarn.lock feat(files): a file library — documents stored as-is, tags, usages (#207) 2026-09-07 21:22:26 +02:00

Platform

Monorepo for two sites sharing one platform — a media library, a rich-text editor, admin UI, navigation menus, and one MariaDB:

  • organisation-communiste — the OCF site: editorial pages, events and payments, media admin.
  • jeunessedumonde — the JDM site: petitions, newsletters, and the articles being taken over from WordPress.

Shared code lives under packages/ (@ocf/db-migrate, @ocf/media, @ocf/editor, @ocf/components, @ocf/menus), consumed as raw TS by both apps' builds.

Documentation

Start at docs/README.md — the index of the architecture write-ups (one per shared package) and the feature docs, each mapped to its code entry points. The CLAUDE.md files carry operating instructions; each app's README.md covers its own setup in detail.

Prerequisites

  • Mise — manages the Node version (mise trust && mise install)
  • Docker — runs the shared infra (MariaDB, Redis, Mailpit, MinIO)

Setup

mise trust && mise install   # Node (Yarn 4 rides on it via Corepack)
corepack enable
yarn install

docker compose up -d         # shared infra for BOTH apps
yarn db:migrate              # both apps' migrations, one coordinated pass
yarn db:seed                 # interactive: first admin account (works on both apps)

Each app needs its own .env — see the app READMEs for the variables.

Run

yarn jdm   # jeunessedumonde          → http://localhost:5173
yarn ocf   # organisation-communiste  → http://localhost:5183

Checks

yarn format:check                              # Prettier, whole repo (yarn format to fix)
yarn docs:check                                # every internal doc link/anchor resolves
yarn workspace <app> typecheck                 # per app: jeunessedumonde / organisation-communiste
yarn workspace <app> test                      # integration/unit suite
yarn workspace <app> test:e2e                  # Playwright journeys

CI runs all of these plus per-package typechecks/tests, Docker-manifest and production-install guards (.github/workflows/).