docs: add operating cadence and clean styling
Some checks failed
Deploy Holiday Property Booking / deploy (push) Failing after 30s
Playwright Holiday Property Booking / playwright (push) Failing after 6m57s
Test & Build Holiday Property Booking / test-build (push) Successful in 10m43s

This commit is contained in:
2026-05-25 13:16:57 +00:00
parent ea7ae9087e
commit 7b9ae307a5
6 changed files with 73 additions and 547 deletions

3
.gitignore vendored
View File

@@ -43,3 +43,6 @@ prisma/dev.db
# Misc # Misc
.cache .cache
tsconfig.tsbuildinfo
.openclaw/
.trash/

View File

@@ -0,0 +1,65 @@
# 09. Operating Cadence and Batch Plan
## Purpose
Keep the holiday-property-booking board moving in a predictable rhythm so Neo always has clear implementation work and the project does not stall between batches.
## Cadence
### Every hour: Neo takes the top Ready ticket
- Neo takes the top ticket in `Ready for Dev`.
- Neo follows the normal dev procedure for that ticket:
- move it to `In Dev`
- branch from `develop`
- implement the work
- push the branch
- report blockers or validation-ready evidence
- merge the feature branch back to `develop` when the implementation slice is done
- leave the merge-complete comment and hand the ticket forward for validation or promotion according to the playbook
- When the ticket is finished, post a Discord-ready completion summary with the ticket ID, what changed, branch/merge state, and the next step or blocker.
- Neo works one ticket at a time unless Morpheus explicitly batches related work.
### Every hour: Morpheus reviews the lanes
- Review the full board for:
- stalled `In Dev` work
- validation work waiting on `Ready for Test`, `Deploying to Dev`, or `In QA`
- release work waiting on `Ready for QA Promotion`, `Deploying to QA`, `QA Deployed`, `Ready for Production`, or `Included in Next Release`
- blockers that need triage
- queue depth in `Ready for Dev`
- If a ticket is clearly stalled, route it to the correct owner and keep the handoff explicit.
- Morpheus keeps the promotion side of the flow: wait for Neo's merge to `develop`, check the develop build, then promote `develop -> qa` when ready.
## Batch Rule
- Count the tickets that have not yet been worked on, meaning the tickets still waiting in `Backlog` or `Ready for Dev`.
- If that count is less than 5, continue the project by creating the next batch of work.
- The next batch should come from the next unresolved phase in the project plan, in dependency order.
- Keep the batch grouped so the work stays coherent and reviewable.
- Keep refilling the ready queue until there are at least 5 unworked tickets, or until the next phase is exhausted.
## Routing Rule
- For each new ready ticket, add a paste-ready comment that states:
- the current lane
- the target lane
- the next responsible agent
- the next concrete action
- Send Neo the actual handoff directly; the ticket comment is the audit trail, not the delivery channel.
- Keep the ticket comment short and actionable so it makes sense even if someone reads it later without the surrounding chat.
- Keep lane moves and comments aligned with the playbook lane model; do not skip the comment even when the move is automated or obvious.
- Do not leave the queue in a state where no ticket is clearly assigned.
## Acceptance Criteria
- Neo always has a top ready ticket to pick up on the 30-minute cadence.
- Neo always has a top ready ticket to pick up on the hourly cadence.
- Neo posts a completion summary to Discord when a ticket finishes.
- Neo still owns merge-back-to-`develop` for feature work.
- Morpheus still owns `develop -> qa` promotion after develop is green.
- Ticket moves and comments stay consistent with the playbook lane model.
- Morpheus can see the full lane state on the hourly review.
- The ready queue is replenished before it drops below 5 unworked tickets.
- New batches are created in dependency order instead of ad hoc.
- The board never stalls because the next group of tickets was not prepared.

View File

@@ -33,7 +33,9 @@ Phase 1 scaffold started from the approved planning docs, and the Vikunja board
- The first build tickets are queued on the board, with later phase work staged behind them - The first build tickets are queued on the board, with later phase work staged behind them
- Post-dev flow is documented so implementation tickets always merge to `develop`, then hand off into test/validation before QA promotion - Post-dev flow is documented so implementation tickets always merge to `develop`, then hand off into test/validation before QA promotion
- New functionality should extend the Playwright suite so browser regression coverage grows with the app - New functionality should extend the Playwright suite so browser regression coverage grows with the app
- Operating cadence is documented so Neo takes the top `Ready for Dev` ticket every hour, posts a completion summary to Discord when done, Morpheus reviews the lanes every hour, and the queue is refilled before it drops below 5 unworked tickets
## Next Build Step ## Next Build Step
- Start with `VIK-108`, then work through `VIK-109` to `VIK-112` in order before pulling from the backlog queue. - Start with `VIK-108`, then work through `VIK-109` to `VIK-112` in order before pulling from the backlog queue.
- Once fewer than 5 tickets remain unworked, create the next batch from the next unresolved phase instead of letting the queue drain.

View File

@@ -10,6 +10,7 @@ The project has been onboarded to Vikunja and the board now uses the playbook la
The next public work is queued as tickets, with `VIK-112` staged as the next active item after the current slice. The next public work is queued as tickets, with `VIK-112` staged as the next active item after the current slice.
Implementation tickets are expected to merge back to `develop` first, then hand off into `Ready for Test` / `Deploying to Dev` before Trinity validation and later QA promotion. Implementation tickets are expected to merge back to `develop` first, then hand off into `Ready for Test` / `Deploying to Dev` before Trinity validation and later QA promotion.
Any new feature work should also update the Playwright suite so the browser tests become the main regression check as coverage expands. Any new feature work should also update the Playwright suite so the browser tests become the main regression check as coverage expands.
Operating cadence is now defined in `09-operating-cadence-and-batch-plan.md`: Neo pulls the top `Ready for Dev` ticket every hour, posts a completion summary to Discord when finished, Morpheus reviews the lanes every hour, and the ready queue is replenished when fewer than 5 tickets remain unworked.
## Working Rule ## Working Rule
@@ -25,6 +26,7 @@ We will not build this in one shot. Each numbered document in this folder define
6. `06-admin-console.md` 6. `06-admin-console.md`
7. `07-seo-accessibility-performance.md` 7. `07-seo-accessibility-performance.md`
8. `08-implementation-plan-and-launch-readiness.md` 8. `08-implementation-plan-and-launch-readiness.md`
9. `09-operating-cadence-and-batch-plan.md`
## Source ## Source

View File

@@ -46,6 +46,7 @@ This board is normalized to the shared playbook lane model.
- Feature work now lives on this board and should be tracked as separate tickets. - Feature work now lives on this board and should be tracked as separate tickets.
- Use the playbook lane names exactly when routing work. - Use the playbook lane names exactly when routing work.
- When a ticket finishes `In Dev`, Neo merges the feature branch back to `develop`, leaves a merge-complete comment, and hands the ticket forward for validation rather than marking it done. - When a ticket finishes `In Dev`, Neo merges the feature branch back to `develop`, leaves a merge-complete comment, and hands the ticket forward for validation rather than marking it done.
- When Morpheus routes work, send Neo the handoff directly and leave the ticket comment as a concise record of the lane change and next action; do not rely on the bucket comment as the only delivery path.
- After the merge, move the ticket into `Ready for Test` and then `Deploying to Dev` while the dev build/deploy proves the change. - After the merge, move the ticket into `Ready for Test` and then `Deploying to Dev` while the dev build/deploy proves the change.
- Trinity handles validation once the dev environment is ready, and the ticket only moves forward after the live check passes. - Trinity handles validation once the dev environment is ready, and the ticket only moves forward after the live check passes.
- QA promotion is a separate step after dev validation, not part of the merge itself. - QA promotion is a separate step after dev validation, not part of the merge itself.

View File

@@ -1,547 +0,0 @@
$body-bg: #f4efe7;
$body-color: #1a1714;
$primary: #7a543d;
$secondary: #2e6661;
$success: #2f6b43;
$warning: #b07d24;
$danger: #a63d3d;
$border-radius: 1rem;
$font-family-sans-serif: "Avenir Next", "Segoe UI", sans-serif;
$headings-font-family: "Iowan Old Style", "Palatino Linotype", Georgia, serif;
@import "bootstrap/scss/bootstrap";
:root {
--shell-bg: #f4efe7;
--panel-bg: rgba(255, 255, 255, 0.72);
--panel-border: rgba(26, 23, 20, 0.08);
--accent: #7a543d;
--accent-2: #2e6661;
--text-muted: #63594f;
--shadow: 0 24px 80px rgba(23, 19, 14, 0.12);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
min-height: 100vh;
margin: 0;
background:
radial-gradient(circle at top left, rgba(122, 84, 61, 0.18), transparent 30%),
radial-gradient(circle at 80% 10%, rgba(46, 102, 97, 0.18), transparent 24%),
var(--shell-bg);
}
a {
color: inherit;
text-decoration: none;
}
main {
position: relative;
}
.app-shell {
min-height: 100vh;
padding: 1.25rem;
}
.surface {
max-width: 1180px;
margin: 0 auto;
border: 1px solid var(--panel-border);
border-radius: 1.75rem;
background: var(--panel-bg);
box-shadow: var(--shadow);
backdrop-filter: blur(18px);
}
.site-header,
.site-footer,
.hero,
.section-shell {
padding: 1.5rem;
}
.site-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
border-bottom: 1px solid var(--panel-border);
}
.brand-lockup {
display: flex;
align-items: center;
gap: 1rem;
}
.brand-mark {
display: inline-grid;
place-items: center;
width: 3rem;
height: 3rem;
border-radius: 999px;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
color: #fff;
font-weight: 700;
letter-spacing: 0.08em;
}
.brand-kicker,
.footer-label,
.section-eyebrow {
margin: 0 0 0.25rem;
font-size: 0.72rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--text-muted);
}
.brand-lockup h1 {
margin: 0;
font-size: 1.05rem;
}
.site-nav {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.site-nav a {
padding: 0.55rem 0.85rem;
border: 1px solid rgba(26, 23, 20, 0.12);
border-radius: 999px;
font-size: 0.92rem;
color: var(--text-muted);
transition:
transform 160ms ease,
border-color 160ms ease,
background-color 160ms ease;
}
.site-nav a:hover,
.site-nav a:focus-visible {
transform: translateY(-1px);
border-color: rgba(122, 84, 61, 0.35);
background: rgba(255, 255, 255, 0.8);
color: var(--body-color);
}
.hero {
display: grid;
grid-template-columns: 1.5fr 1fr;
gap: 1.5rem;
align-items: stretch;
}
.hero-copy,
.hero-panel,
.info-card,
.phase-card,
.data-card {
border: 1px solid var(--panel-border);
border-radius: 1.5rem;
background: rgba(255, 255, 255, 0.78);
}
.hero-copy {
padding: 2rem;
}
.hero-copy h2 {
margin: 0 0 1rem;
font-size: clamp(2.2rem, 4vw, 4.2rem);
line-height: 0.95;
letter-spacing: -0.04em;
}
.hero-copy p {
max-width: 60ch;
color: var(--text-muted);
font-size: 1.06rem;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-top: 1.5rem;
}
.hero-actions .btn {
border-radius: 999px;
padding-inline: 1.1rem;
}
.hero-points {
display: grid;
gap: 0.55rem;
margin: 1.5rem 0 0;
padding-left: 1.1rem;
color: var(--text-muted);
}
.hero-panel {
display: grid;
gap: 1rem;
padding: 1.5rem;
}
.search-panel {
display: grid;
gap: 0.85rem;
padding: 1rem;
border-radius: 1.25rem;
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(26, 23, 20, 0.08);
}
.search-field {
display: grid;
gap: 0.35rem;
color: var(--text-muted);
font-size: 0.92rem;
}
.search-field input,
.contact-form input,
.contact-form textarea {
width: 100%;
border: 1px solid rgba(26, 23, 20, 0.14);
border-radius: 0.9rem;
padding: 0.8rem 0.95rem;
background: rgba(255, 255, 255, 0.94);
color: var(--body-color);
}
.search-field input:focus,
.contact-form input:focus,
.contact-form textarea:focus {
outline: 2px solid rgba(122, 84, 61, 0.28);
outline-offset: 2px;
}
.info-card,
.phase-card,
.data-card,
.content-card,
.property-card,
.testimonial-card {
padding: 1rem;
}
.metric-grid,
.phase-grid,
.data-grid,
.property-grid,
.content-grid,
.testimonial-grid,
.card-stack,
.content-stack {
display: grid;
gap: 1rem;
}
.metric-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.metric {
padding: 1rem;
border-radius: 1rem;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(246, 240, 231, 0.9));
}
.metric strong {
display: block;
margin-bottom: 0.3rem;
font-size: 1.6rem;
}
.section-heading h2 {
margin: 0;
font-size: clamp(1.5rem, 2vw, 2.1rem);
}
.section-description {
max-width: 65ch;
margin: 0.5rem 0 0;
color: var(--text-muted);
}
.phase-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.phase-card h3,
.data-card h3 {
margin-top: 0;
font-size: 1.05rem;
}
.phase-card ul,
.data-card ul {
margin: 0.75rem 0 0;
padding-left: 1.1rem;
color: var(--text-muted);
}
.data-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.property-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.property-card {
display: grid;
gap: 0.9rem;
border: 1px solid var(--panel-border);
border-radius: 1.35rem;
background: rgba(255, 255, 255, 0.82);
}
.property-card-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
}
.property-card h3,
.content-card h3,
.testimonial-card strong {
margin: 0;
}
.property-price {
display: inline-flex;
align-items: center;
padding: 0.35rem 0.7rem;
border-radius: 999px;
background: rgba(46, 102, 97, 0.12);
color: var(--accent-2);
font-size: 0.85rem;
white-space: nowrap;
}
.property-metrics {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.75rem;
margin: 0;
}
.property-metrics div {
padding: 0.75rem;
border-radius: 0.95rem;
background: rgba(244, 239, 231, 0.88);
}
.property-metrics dt {
color: var(--text-muted);
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.14em;
}
.property-metrics dd {
margin: 0.25rem 0 0;
font-size: 1rem;
font-weight: 700;
}
.tag-list,
.link-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.tag-list li {
padding: 0.32rem 0.62rem;
border-radius: 999px;
background: rgba(122, 84, 61, 0.12);
color: var(--accent);
font-size: 0.82rem;
}
.content-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.content-grid-tight {
align-items: flex-start;
}
.content-card,
.testimonial-card {
border: 1px solid var(--panel-border);
border-radius: 1.35rem;
background: rgba(255, 255, 255, 0.82);
}
.content-card p:last-child,
.testimonial-card p:last-child {
margin-bottom: 0;
}
.inline-link {
color: var(--accent-2);
text-decoration: underline;
text-underline-offset: 0.2em;
}
.testimonial-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.testimonial-card {
display: grid;
gap: 1rem;
}
.testimonial-card footer {
display: grid;
gap: 0.15rem;
color: var(--text-muted);
}
.cta-band,
.page-hero {
border: 1px solid var(--panel-border);
border-radius: 1.5rem;
background: rgba(255, 255, 255, 0.82);
}
.cta-band {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 1.1rem 1.25rem;
}
.page-hero {
margin: 1.5rem;
padding: 1.5rem;
}
.page-hero h2 {
margin: 0 0 0.6rem;
font-size: clamp(2rem, 4vw, 3.5rem);
line-height: 0.98;
letter-spacing: -0.04em;
}
.page-layout {
display: grid;
grid-template-columns: minmax(0, 1.4fr) minmax(300px, 0.75fr);
gap: 0.5rem;
}
.page-layout .section-shell {
padding-top: 0;
}
.contact-form {
display: grid;
gap: 0.9rem;
}
.contact-form label {
display: grid;
gap: 0.35rem;
color: var(--text-muted);
}
.contact-form-message {
grid-column: 1 / -1;
}
.contact-aside {
display: grid;
gap: 1rem;
align-content: start;
padding: 1.5rem 1.5rem 1.5rem 0;
}
.content-sidebar {
display: grid;
gap: 1rem;
align-content: start;
}
.site-footer {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: 1px solid var(--panel-border);
color: var(--text-muted);
}
.site-footer p {
margin: 0;
}
@media (max-width: 900px) {
.hero,
.phase-grid,
.data-grid,
.property-grid,
.content-grid,
.testimonial-grid,
.page-layout {
grid-template-columns: 1fr;
}
.site-header,
.site-footer,
.cta-band {
flex-direction: column;
align-items: flex-start;
}
.contact-aside {
padding: 0 1.5rem 1.5rem;
}
}
@media (max-width: 640px) {
.app-shell {
padding: 0.75rem;
}
.site-header,
.hero,
.section-shell,
.site-footer {
padding: 1rem;
}
.page-hero {
margin: 0.75rem;
padding: 1rem;
}
.metric-grid {
grid-template-columns: 1fr;
}
.property-metrics {
grid-template-columns: 1fr;
}
}