Files
bmp-website-2026/docs/client-feedback-deployment-readiness.md
2026-07-31 19:33:46 +02:00

276 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Client feedback rollout: deployment readiness
Verification date: 2026-07-31
## Decision
Tasks 117 are ready for a coordinated schema-changing deployment. Local code,
CMS ownership, isolated database migrations, the full serial Vitest integration
suite, the production webpack build, generated sitemaps, and public/draft
behavior have been verified.
The rollout is not yet complete in production. Production is still serving
revision `740e302c58f8`, before Tasks 117, and the production-write gates listed
below remain intentionally blocked. No production database, media, publication
state, or deployment was changed during Task 18.
## Commit sequence
The clean root worktree and this verification worktree both started at
`07e9458aaf2796f5f48a69302acd26914032b879`. The root `main` history contains
exactly these 17 Task 117 commits after production revision `740e302c58f8`:
| Task | Commit | Subject |
| --- | --- | --- |
| 1 | `fec1bab2e521d38af9de3c7c3c315c0da91795e7` | `fix(cms): enforce public publication contract` |
| 2 | `b18bbbe36ad395cb26011d6032e06f460ded3f2a` | `fix(cms): filter unpublished relationships` |
| 3 | `8dc17c0fea9420b2854a074d3924d4341147f04b` | `fix(cms): remove unpublished content fallbacks` |
| 4 | `ab47571139a177339a002ff62336a61f7a44d4c6` | `refactor(cms): remove obsolete page fields` |
| 5 | `e3c47c4500150be0fb40caa6cb4ae2619f61789c` | `feat(cms): add network page video upload` |
| 6 | `c2dc42f243e58c7cb81e2e23e2aa2e34110ca4fc` | `feat(cms): add press contact image` |
| 7 | `ebecf66e6fcb8514d5206bfc80ad36f4c9939e4e` | `fix(participation): repair process timeline` |
| 8 | `30efb4b36ee7c0187c0274f319679846287ae3cb` | `feat(network): add responsive sponsor hierarchy` |
| 9 | `95037e99089837a64a4315f6d2a467e8e5be61f5` | `feat(cms): clarify sponsor ordering` |
| 10 | `adda9ddbd07a7bb04947c349a2117dd31879d190` | `fix(home): slow sponsor ticker` |
| 11 | `f465839af0e49fa5021272c0a85786a90a763589` | `fix(home): honor phase headline line breaks` |
| 12 | `5b62abf8d4b205d8603f3a0d34393d47d30412e8` | `fix(home): rebalance application form split` |
| 13 | `d7a720460f542fc6c34ad3bd46d2eb5be1e2be6e` | `docs(home): verify application panel color` |
| 14 | `4bb265dac1b7862db1e468d63126a07e9eaa8aec` | `fix(participation): clarify eligibility hierarchy` |
| 15 | `3c28f6ff9c53486b87c2d45ffb57e35bc5a025d7` | `fix(about): rebalance relevance section` |
| 16 | `0a19abd0b080095748f1de28dfe829da62316e96` | `fix(about): align facts and caption` |
| 17 | `07e9458aaf2796f5f48a69302acd26914032b879` | `fix(seo): correct sitemap routes` |
Task 18 is the single commit containing this report and the regression-test
cleanup described below. Its exact hash is recorded in the Task 18 handoff
because a commit cannot embed its own hash.
No Task 117 integration is missing, and no unrelated tracked changes were
present at the start of Task 18.
## Automated verification
All database-backed checks used copies of the current local `content.db`. The
source database SHA-256 was
`fb7de5d9f1fcf3a7c27494efe7f3111cba4173bc986a38ea62c9cf6d5840425e` and was
never migrated or otherwise mutated.
### Integration tests
- Focused publication, relationship, sitemap, CMS-field, media, responsive
section, timeline, sponsor, press, home, and about tests passed.
- Complete serial suite against a freshly copied and migrated database:
**21 files, 92 tests, all passed**.
- Serial command shape used to avoid SQLite parallel-write contention:
```bash
DATABASE_URL=file:/absolute/path/to/isolated.db \
PAYLOAD_SECRET=task18-isolated-verification \
PAYLOAD_MIGRATING=true \
SITE_URL=http://127.0.0.1:3100 \
./node_modules/.bin/vitest run \
--config ./vitest.config.mts \
--maxWorkers=1 \
--no-file-parallelism \
--hookTimeout=30000
```
`PAYLOAD_MIGRATING=true` is required for tests against an explicitly migrated
database so Payload does not also attempt its development schema-push path.
### Task 18 regression fix
`tests/int/publication-contract.int.spec.ts` created unique publication fixtures
but deleted only their media record. A second run against the same isolated
database therefore failed unique `slug` and `stableId` validation. Task 18 now
deletes every created document before deleting the media record. The focused
suite passed twice consecutively afterward, and the complete 92-test serial
suite remained green.
### Static and build checks
- `./node_modules/.bin/tsc --noEmit --incremental false`: passed.
- `payload generate:types`: passed; `src/payload-types.ts` was byte-for-byte
unchanged.
- `git diff --check`: passed.
- Task 18 changed-file Prettier check: passed.
- Production webpack build against the migrated database:
`next build --webpack`: passed and generated all expected application,
Payload, preview, and sitemap routes.
- Production-safe sitemap postbuild with
`NEXT_PUBLIC_SERVER_URL=https://srv1.bayerischer-mittelstandspreis.de`:
passed. Generated `robots.txt` and `sitemap.xml` contain only the canonical
HTTPS origin.
- Local generated and dynamic sitemap endpoints returned `200`; `/`, the
representative article, event, and winner URLs were present, no localhost or
placeholder origin was present, and the unpublished Task 18 fixture was
absent.
## Migration verification
Initial status on the copied current database was 5 recorded migrations and 18
pending migrations. The isolated upgrade completed all pending migrations and
ended with all 23 repository migrations recorded. `PRAGMA integrity_check`
returned `ok`.
Every migration introduced by Tasks 117 was additionally verified through its
own copied-database down/up cycle, with integrity checks after both directions:
- `20260731_143000_remove_press_record_fallbacks`
- `20260731_160000_focused_payload_cleanup`
- `20260731_170000_netzwerk_greeting_video`
- `20260731_180000_press_contact_image`
- `20260731_190000_responsive_sponsor_hierarchy`
- `20260731_200000_home_phase_headline_line_break`
All six targeted down/up cycles passed. The real `content.db` was never used as
a migration target.
## Browser verification
The production build was served locally against the isolated migrated database
and the copied local media directory. Anonymous and authenticated preview checks
used separate browser state.
### Route and viewport matrix
The following routes were checked at approximately 1440, 1024, 768, and an
exact 390 CSS pixels:
- `/`
- `/teilnahme`
- `/der-bmp`
- `/netzwerk`
- `/presse`
- `/presse/events/nominierten-auswahl-2026`
- `/presse/blog/goldene-bavaria`
- `/preistraeger/agrarquant-gmbh`
All 32 combinations rendered their expected CMS-owned heading and substantive
main content with zero broken images. There was no page-level horizontal
overflow except for the pre-existing event-detail issue below.
Specific checks also passed:
- Homepage phase heading rendered the CMS newline as two lines.
- Shared `#bewerben` section computed to `rgb(36, 54, 106)` (`#24366A`).
- `/teilnahme` timeline advanced from `01 / 04` through `04 / 04`; all four
desktop/tablet steps were reachable, the 1024px section was 667px tall, and
the next-section gap was `0`. At 390px all four mobile headings rendered in
document order, controls were hidden, and the next-section gap was `0`.
- Eligibility groups and the dates transition remained in the intended mobile
scan order.
- `/der-bmp` relevance layout was split on desktop; all three facts were
centered and the image caption had a visible dark controlled background.
- `/netzwerk` rendered tier bands with current counts 2 / 2 / 8 in authoritative
order. With no Netzwerk video selected, no video action rendered.
- `/presse` rendered the safe `copy-only` contact layout with no contact image
selected.
### Anonymous public versus authenticated preview
An isolated draft press article was created with slug
`task18-preview-fixture`.
- Anonymous direct browsing returned the 404 page and exposed neither the
fixture title nor body.
- After authenticating an isolated Payload user and entering through
`/next/preview`, the same path rendered the draft title.
- Publication and relationship integration tests independently prove this
boundary for pages, winners, jury members, partners, events, and posts.
## Read-only production smoke
No production login or write was performed. Browser and HTTP checks produced:
| Production route | Result |
| --- | --- |
| `/` | `200`, expected main content, no broken images |
| `/teilnahme` | `200`, expected main content, no broken images |
| `/der-bmp` | `200`, expected main content, no broken images |
| `/netzwerk` | `200`, expected main content, no broken images |
| `/presse` | `200`, expected main content, no broken images |
| `/presse/blog/goldene-bavaria` | `200`, expected article detail |
| `/presse/events/nominierten-auswahl-2026` | `404` before rollout |
| `/preistraeger/agrarquant-gmbh` | `404` before rollout |
| `/sitemap.xml` | `200` |
| `/pages-sitemap.xml` | `200` |
| `/posts-sitemap.xml` | `200` |
| `/robots.txt` | `200` |
The read-only VPS status script confirmed deployed revision `740e302c58f8`,
which is exactly the parent of Task 1. Further container/status output requires
interactive server `sudo` and was not attempted.
The current production sitemap is therefore expectedly stale: it still emits
`/startseite`, emits three `/posts/<slug>` URLs that each return `404`, and has
no event or winner detail entries. The corrected local sitemap cannot be judged
live until the verified commit sequence is deployed.
## Known tooling and pre-existing limitations
- Repo-wide ESLint does not reach file evaluation because the current flat
configuration throws `Cannot redefine plugin "@typescript-eslint"`.
- A rollout-wide Prettier audit reports 41 already-committed Task 117 files as
nonconforming. Task 18's changed files pass Prettier; bulk reformatting was
intentionally excluded from this release-verification commit.
- The installed global pnpm is `11.9.0`, while this repo requires pnpm `^9` or
`^10`. `pnpm vps:status` is blocked by the engine check; invoking the
read-only script directly reached production and confirmed the revision.
- The in-app browser enforces a 480px minimum CSS viewport. The exact 390px
matrix was completed through the installed Chrome browser surface instead.
- In-app navigation to local XML endpoints was blocked by the browser client;
read-only HTTP checks verified all four sitemap/robots endpoints instead.
- The representative event detail overflows horizontally at exactly 768px:
the pre-existing `EventDetail.tsx` layout combines 80px side padding, a 64px
gap, and a fixed 400px sidebar. Tasks 117 did not change this component, so
Task 18 did not expand scope to redesign it. The same route has no overflow
at 390, 1024, or 1440px.
## Required production procedure and blocked gates
These actions are intentionally not performed by Task 18. They require explicit
production-write coordination and a supported pnpm `^9` or `^10` runtime.
1. Obtain explicit production-write authorization and identify the exact commit
to deploy.
2. Create the documented server-side SQLite backup:
```bash
pnpm vps:backup-db
```
3. Deploy the committed schema-changing rollout with migrations enabled:
```bash
RUN_MIGRATIONS=1 pnpm deploy:vps
```
Per `docs/vps-deployment.md`, this mode also creates a pre-migration database
copy before `pnpm payload migrate` runs in the one-off app container.
4. Confirm the deployed revision, container health, database/media state, and
logs:
```bash
pnpm vps:status
```
5. Obtain the client-supplied Netzwerk video, upload/select it through Payload
on the Netzwerk page, and verify that changing it does not affect the
homepage video. No video asset was supplied in this task.
6. Obtain the approved press-contact image, upload/select it with useful alt
text through Payload on the Presse page, and verify the two-column desktop
and stacked mobile layouts. No image asset was supplied in this task.
7. Identify approved disposable production records before testing Unpublish and
Republish. Record IDs and `_status`, verify anonymous list/detail removal,
verify authenticated preview visibility, republish, and confirm restoration.
No disposable record was approved in this task.
8. Re-run the production route, sitemap, robots, media, responsive, and
publication smoke matrix after deployment. In particular, every URL emitted
by the corrected sitemap must return `200`.
Blocked gates at handoff are therefore: client Netzwerk video, client press
image, approved production unpublish record(s), supported deployment tooling,
interactive server privileges where required, and explicit production-write
authorization.