Each journey is walked by a named protagonist (BMAD pattern): a concrete persona with a job-to-be-done trigger, so the spec reads as behaviour rather than abstract requirements.
2 personas5 scenariosslugtrip-order-consistency
JTBD: When I browse balionline.hu's trips across the homepage, the menu and the collection page, I want them in one consistent, sensible order (soonest departures first, 'coming soon' last) so that I can quickly find a trip I can actually book and trust that the site is current.
JTBD: When I want to feature a particular trip, I want to set its ranking number once in the CMS and have every page of the site honor that order, so that my featured trip leads everywhere without asking the developer.
Every distinct leaf path, classified happy / edge / failure / recovery. The proposed test-IDs are the bridge that plan-techspec reads from scenario_map.json to seed acceptance checks.
| ID | Scenario | Persona | Path | Steps | Proposed test-IDs |
|---|---|---|---|---|---|
| S1 | Visitor sees ONE consistent trip order across every surface | P1 | 🟢 happy | 6 | F2, F3, F4, F5, F6, C1 |
| S2 | Client edits a trip's ranking number and it propagates to every surface | P2 | 🟢 happy | 7 | B3, F0, F1, F3, F4, F5, C1 |
| S3 | Coming-soon placeholders are always pinned last | P1 | 🟡 edge | 2 | F2 |
| S4 | A trip with no ranking value is never dropped (data-loss guard) | P2 | 🟡 edge | 2 | F1, F3 |
| S5 | Baseline & tie-break order = departure date, soonest first | P1 | 🟡 edge | 2 | F3, F4, F5, C1 |
Each row is one concrete UI interaction: who acts · the exact element clicked or seen · the copy shown · the system action · the resulting state · where it branches.
Trigger: Réka opens balionline.hu and moves between the homepage, the nav dropdown, the collection page and a single trip's related-trips block.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open balionline.hu and look at the trips block on the homepage | Bali trip cards (title + departure date per card) | server-rendered WP_Query for post_type=utazas, shared ordering | homepage_trip_list_rendered | — |
| 2 | user | Open the top-nav 'Utak' dropdown submenu | Dynamic trip links (the '<!-- Itt hívjuk be a dinamikus utakat -->' list) | dynamic menu lists utazas posts via the shared ordering | nav_dropdown_open | — |
| 3 | user | Click through to the collection page (/csoportos-utak-gyujtooldal/) and read Grid-1 | trip-card grid, h3.trip-title per card | page template WP_Query for the bookable-trips grid, shared ordering | collection_grid1_rendered | — |
| 4 | user | Scroll to the bottom of the collection page trips area | 'Tervezés alatt' placeholder cards (Thaiföld / Japán / Mexikó) | placeholder grid rendered after the active grid | placeholders_visible | — |
| 5 | user | Open a single trip (/utazas/<slug>/) and scroll to the related / other-trips block | related-trips cards | secondary WP_Query for related trips, shared ordering | related_trips_rendered | — |
| 6 | user | View the homepage, nav dropdown and collection page at 375px mobile width | same trip cards, reflowed | responsive layout, same query order | mobile_render | — |
Proposed acceptance test-IDs: F2, F3, F4, F5, F6, C1
| # | You do | You should see | Element that changes (copy · look · where) | What changes underneath | Must NOT happen |
|---|---|---|---|---|---|
| 1 | Open balionline.hu and look at the trips block on the homepage | The homepage trip block lists the active Bali trips, soonest departure first, with the same trips that appear elsewhere on the site. | Copy: Trip cards in order T1, T2, T3 … · Look: grid of trip cards, each with title + date · Where: homepage trips section | — | The homepage order must NOT differ from the nav dropdown or the collection page; a 'coming soon' placeholder must NOT appear before a bookable trip. |
| 2 | Open the top-nav 'Utak' dropdown submenu | The dropdown lists the SAME trips in the SAME order as the homepage. | Copy: Trip links in order T1, T2, T3 … · Look: vertical dropdown menu list · Where: top navigation, under 'Utak' | — | The nav order must NOT differ from the homepage / collection page (this is the original bug). |
| 3 | Click through to the collection page (/csoportos-utak-gyujtooldal/) and read Grid-1 | Grid-1 (the bookable trips) shows the same trips in the same order, soonest departure first. | Copy: trip-card titles in order T1, T2, T3 … · Look: responsive card grid (div.trips-grid > div.trip-card) · Where: main column of the collection page | — | A September-29 departure must NOT sit below an October one; the order must NOT be arbitrary or differ from the homepage/nav. |
| 4 | Scroll to the bottom of the collection page trips area | The 'Tervezés alatt' (coming-soon) cards appear LAST, after every bookable trip. | Copy: 'Tervezés alatt' cards (Thaiföld, Japán, Mexikó) · Look: muted/secondary card grid · Where: below Grid-1, end of the trips area | — | A placeholder must NOT appear among or before the bookable trips. |
| 5 | Open a single trip (/utazas/<slug>/) and scroll to the related / other-trips block | The related/other-trips block uses the SAME ordering rule as the rest of the site. | Copy: related trip cards in the shared order · Look: card row/grid · Where: lower section of the single-trip page | — | The related-trips order must NOT use a different (e.g. publish-date or random) ordering. |
| 6 | View the homepage, nav dropdown and collection page at 375px mobile width | The trip order is identical at mobile and desktop on every surface. | Copy: same order T1, T2, T3 … at 375px · Look: single-column reflow · Where: all listing surfaces, mobile | — | The order must NOT change between mobile and desktop. |
flowchart TD S1U1(["Open balionline.hu and look at the trips block on the homepage"]) S1U2(["Open the top-nav 'Utak' dropdown submenu"]) S1U3(["Click through to the collection page (/csoportos-utak-gyujtoold…"]) S1U4(["Scroll to the bottom of the collection page trips area"]) S1U5(["Open a single trip (/utazas/<slug>/) and scroll to the related…"]) S1U6(["View the homepage, nav dropdown and collection page at 375px mo…"]) S1U1 -->|server-rendered WP_Query for post_type=utazas…| S1U2 S1U2 -->|dynamic menu lists utazas posts via the share…| S1U3 S1U3 -->|page template WP_Query for the bookable-trips…| S1U4 S1U4 -->|placeholder grid rendered after the active gr…| S1U5 S1U5 -->|secondary WP_Query for related trips, shared…| S1U6
Trigger: Anna wants to push a specific trip to the top and expects the new order everywhere, without a developer. (This journey is the subject of the client SOP guide.)
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Go to balionline.hu/wp-admin and log in (from a whitelisted IP, past cPGuard) | WordPress login form → Dashboard | WP authentication | wp_admin_authenticated | — |
| 2 | user | Click 'Utazások' in the left admin menu to open the trips list | Utazások list (all utazas posts) | list table for post_type=utazas | trips_list_open | — |
| 3 | user | Click the trip to promote to open its edit screen | trip edit screen | load post editor + meta box | trip_edit_open | — |
| 4 | user | Type a new value into the ranking-number field (lower number = appears earlier) | ranking number input | field value staged for save | rank_value_entered | — |
| 5 | user | Click 'Frissítés' / 'Update' to save the trip | 'Utazás frissítve' / 'Post updated' | POST save_post → meta persisted | rank_value_persisted | — |
| 6 | user | Open the public collection page (incognito) and find the edited trip | collection Grid-1 | front-end WP_Query reads the ranking field (shared helper) | collection_reordered | — |
| 7 | user | Open the homepage and the nav dropdown and locate the same trip | homepage + nav trip lists | same shared helper feeds both | all_surfaces_reordered | — |
Proposed acceptance test-IDs: B3, F0, F1, F3, F4, F5, C1
| # | You do | You should see | Element that changes (copy · look · where) | What changes underneath | Must NOT happen |
|---|---|---|---|---|---|
| 1 | Go to balionline.hu/wp-admin and log in (from a whitelisted IP, past cPGuard) | The real WordPress login form loads (not the cPGuard/recaptcha.cloud interstitial), and after login the dashboard appears. | Copy: 'Vezérlőpult' / Dashboard · Look: standard wp-admin chrome · Where: wp-admin | — | wp-login.php must NOT be permanently exposed — the temporary IP allowance is reverted afterwards (check C2). |
| 2 | Click 'Utazások' in the left admin menu to open the trips list | The full list of utazás trips, including the trip Anna wants to promote. | Copy: trip titles list · Look: wp-admin list table · Where: Utazások admin screen | — | — |
| 3 | Click the trip to promote to open its edit screen | The trip's edit screen, including the ranking-number field Dani added. | Copy: ranking-number field (exact label resolved in B3) · Look: number input in a meta box / sidebar panel · Where: trip edit screen | — | — |
| 4 | Type a new value into the ranking-number field (lower number = appears earlier) | The ranking field accepts the new number for this trip only. | Copy: the new rank value, e.g. '1' · Look: number input field · Where: trip edit meta box / sidebar | This trip's ranking meta value is updated; the existing values on OTHER trips are kept (F0 = keep the client's values, no re-seed). | No other trip's ranking value is changed; the client's existing values are NOT mass-overwritten. |
| 5 | Click 'Frissítés' / 'Update' to save the trip | A 'trip updated' confirmation; the new ranking value is saved. | Copy: 'Utazás frissítve.' · Look: admin success notice (green bar) · Where: top of the trip edit screen | The new ranking value is persisted to the database for this trip. | The save must NOT error or silently drop the ranking value. |
| 6 | Open the public collection page (incognito) and find the edited trip | The edited trip now sits at its new position in Grid-1. | Copy: the promoted trip card at its new index · Look: trip-card in the grid · Where: collection page Grid-1 | The front-end ordering reflects the new ranking value on the next page load. | The reorder must NOT require a developer redeploy, and must NOT appear on only one surface. |
| 7 | Open the homepage and the nav dropdown and locate the same trip | The trip is at the SAME new position on the homepage, the nav dropdown and the collection page. | Copy: the promoted trip first/at its new index on all three · Look: card grid / dropdown list · Where: homepage, nav, collection | — | The new position must NOT differ between surfaces (the bug this whole feature fixes). |
flowchart TD S2U1(["Go to balionline.hu/wp-admin and log in (from a whitelisted IP,…"]) S2U2(["Click 'Utazások' in the left admin menu to open the trips list"]) S2U3(["Click the trip to promote to open its edit screen"]) S2U4(["Type a new value into the ranking-number field (lower number =…"]) S2U5(["Click 'Frissítés' / 'Update' to save the trip"]) S2U6(["Open the public collection page (incognito) and find the edited…"]) S2U7(["Open the homepage and the nav dropdown and locate the same trip"]) S2U1 -->|WP authentication| S2U2 S2U2 -->|list table for post_type=utazas| S2U3 S2U3 -->|load post editor + meta box| S2U4 S2U4 -->|field value staged for save| S2U5 S2U5 -->|POST save_post → meta persisted| S2U6 S2U6 -->|front-end WP_Query reads the ranking field (s…| S2U7
Trigger: A 'Tervezés alatt' trip exists (Thaiföld / Japán / Mexikó), possibly even with a low ranking number set by the client.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open the collection page and look at both trip grids | Grid-1 (bookable) + Grid-2 ('Tervezés alatt') | two grids rendered | two_grids_rendered | — |
| 2 | system | Apply ordering when a placeholder trip has a low ranking number | placeholder card | placeholder pinned last regardless of rank value | placeholder_pinned_last | — |
Proposed acceptance test-IDs: F2
| # | You do | You should see | Element that changes (copy · look · where) | What changes underneath | Must NOT happen |
|---|---|---|---|---|---|
| 1 | Open the collection page and look at both trip grids | Bookable trips fill Grid-1; the 'Tervezés alatt' trips sit in Grid-2 below. | Copy: 'Tervezés alatt' cards last · Look: second, muted grid · Where: below Grid-1 | — | — |
| 2 | Apply ordering when a placeholder trip has a low ranking number | Even if a 'coming soon' trip has a low ranking number, it still renders AFTER all bookable trips. | Copy: 'Tervezés alatt' card index > every active index · Look: placeholder card · Where: end of the trips area on every surface | Placeholders are pinned last by design (handoff §3), independent of the ranking field. | A placeholder must NOT jump above a bookable trip just because its rank number is low. |
flowchart TD S3U1(["Open the collection page and look at both trip grids"]) S3U2["Apply ordering when a placeholder trip has a low ranking number"] S3U1 -->|two grids rendered| S3U2
Trigger: A live bookable trip whose ranking-number field was never filled in (ADR-0002: the naive meta_value_num INNER JOIN would silently drop it).
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | system | Render every listing surface when one bookable trip has an empty ranking field | all trip listings | missing-value-safe orderby (LEFT JOIN / relation OR / NOT EXISTS) | unranked_trip_included | — |
| 2 | user | Read where the unranked trip lands in the collection grid | collection Grid-1 | rank-then-date ordering | unranked_sorted_by_date | — |
Proposed acceptance test-IDs: F1, F3
| # | You do | You should see | Element that changes (copy · look · where) | What changes underneath | Must NOT happen |
|---|---|---|---|---|---|
| 1 | Render every listing surface when one bookable trip has an empty ranking field | The unranked trip still appears in every listing surface. | Copy: the unranked trip's card · Look: normal trip card · Where: in the active grid, sorted last among active | The query keeps trips with no ranking meta (count of rendered trips == count of published bookable trips). | The unranked trip must NOT silently disappear from any surface — no INNER-JOIN drop. |
| 2 | Read where the unranked trip lands in the collection grid | The unranked trip sorts after the ranked trips, by departure date. | Copy: unranked trip after ranked block, in date order · Look: trip-card · Where: tail of the active trips | — | The total trip count must NOT drop versus the number of published bookable trips. |
flowchart TD S4U1["Render every listing surface when one bookable trip has an empt…"] S4U2(["Read where the unranked trip lands in the collection grid"]) S4U1 -->|missing-value-safe orderby (LEFT JOIN / relat…| S4U2
Trigger: Trips have no custom rank, or several share the same rank value — the order must be deterministic, not arbitrary.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | system | Order trips that have no rank or an equal rank value | trip grid | secondary sort by departure date ascending | date_baseline_applied | — |
| 2 | user | Compare the date-baseline order on the homepage, nav dropdown and collection page | three surfaces | same shared helper | baseline_consistent | — |
Proposed acceptance test-IDs: F3, F4, F5, C1
| # | You do | You should see | Element that changes (copy · look · where) | What changes underneath | Must NOT happen |
|---|---|---|---|---|---|
| 1 | Order trips that have no rank or an equal rank value | Trips with no rank or the same rank read by departure date, soonest first. | Copy: earliest departure first · Look: ordered trip cards · Where: any listing surface | Departure date ascending is the baseline / tie-break (handoff §3). | The order must NOT be arbitrary, by publish date, or random. |
| 2 | Compare the date-baseline order on the homepage, nav dropdown and collection page | All three surfaces show the identical, date-ascending baseline order. | Copy: identical order across surfaces · Look: card grids / dropdown · Where: homepage, nav, collection | — | The baseline order must NOT differ between surfaces. |
flowchart TD S5U1["Order trips that have no rank or an equal rank value"] S5U2(["Compare the date-baseline order on the homepage, nav dropdown a…"]) S5U1 -->|secondary sort by departure date ascending| S5U2
Conditions on the arrows; colours follow the path-type legend. Per-scenario sub-flows appear inside each scenario above.
No global flowchart supplied — see per-scenario sub-flows above.
| Message | Copy / subject | Source | Send / show mode | Status |
|---|---|---|---|---|
| Coming-soon placeholder label | Tervezés alatt | collection page template (placeholder grid) | in-page | live |
| Nav dynamic-trips marker (HTML comment) | <!-- Itt hívjuk be a dinamikus utakat --> | header / nav template | in-page | live |
| Trip-edit save button | Frissítés / Update | wp-admin trip editor | in-page | live |
| Ranking-number field label | (exact label resolved in checklist B3) | utazas edit screen meta box | in-page | to-confirm |
| State | Meaning | Entered by | Exits to |
|---|---|---|---|
shared_ordering | the single utazas_query_args() helper (ADR-0001) that every listing query uses: rank-then-date, missing-value-safe (ADR-0002), placeholders last | any utazas listing query on any surface | rendered list on that surface |
rank_value_persisted | a trip's ranking-number meta saved in the CMS (client-owned value, never mass re-seeded) | Anna saves the trip edit (S2.5) | front-end reorder on next page load |
unranked_trip_included | a trip with no ranking meta is still returned by the query (no INNER-JOIN drop) | missing-value-safe orderby | sorts last among active, by date |
Generated by the user-journeys skill on 2026-06-26 · hosted at https://trip-order-consistency-journeys.pages.dev. Rendering: Mermaid flowchart syntax. No screenshots — this is a behavioral spec, not a visual QA artifact.