High-level Todo · synthesized from 5 open inboxes + compliance
HighMedLowCompliance
High priority
HIGHFO83patrimonia / incard webhook · **Add the CF Access bypass Application for `ledger.patrimonia.co.uk/api/incard/webhook`** (policy Bypass + Everyone, same recipe as the existing "FO Inbound Webhook" exception) — this is the one manual step left from the 2026-07-24 production wiring (bank-feed.md § Incard). Confirmed still missing 2026-07-25: a real £1,250 USD `ochrana LLC` credit arrived signature-valid at the tap but never reached `incard_tx_raw` because the forward hit the Access login wall; manually replayed straight to localhost as a workaround (now staged + showing in the review queue), but every future Incard event will silently sit in the tap's KV-only inspection log until this Access Application exists.2026-07-25
HIGHFO80folium / VAT · **VAT number arrived 2026-07-24: 523486976.** (1) ✅ done 2026-07-24: `vatNumber` set on folium-ltd in `entities.ts` SEED + reconciled (`estate:init`) — invoice docs now automatically render as full VAT invoices (breakdown + "VAT No. 523486976"). (2) ✅ done 2026-07-24: FS-2026-011 (Eden Brooke) + FS-2026-016 (Hoban Design) — both already emailed+paid gross during the pending window, so needed a "paid in full, no payment due" reissue rather than a fresh bill. Built `alreadyPaid` mode into `invoice-renderer.ts`/`invoice-send.ts` (write-app.md § Paid-in-full VAT reissue) and sent both via `src/dev/send-vat-reissue-2026-07-24.ts` — landed correctly (£111.60, £90.00, VAT No. printed, no payment instructions). (2b) ⚠️ **reverted 2026-07-24:** FS-2026-012 (£2,265 → £2,718) and FS-2026-013 (£275 → £330) were uplifted, then the uplift itself exposed that both were raised 8-9 months before their real due dates (2027-02-27 / 2027-03-01 — recurring-billing placeholders from FO22 that were never properly scheduled) — a premature tax point was inflating Q3 output VAT by £508 for services not due until next year. **Fully voided instead** (uplift journal reversed, then the raise itself, via `src/dev/void-fs-2026-012-013-premature-2026-07-24.ts`) — Q3 output VAT confirmed back to £33.60 (Hoban + Brooke only). See FO82 for the proper fix. FS-2026-008/009/010 are pre-reg — **stay flat, never uplift**. **Still open:** (3) first return: pre-reg reclaims — services 6 months back, goods 4 years (incl. the planned PCs, which must be bought **in Folium's name**); the 1180 balance is the running claim. (4) **FS-2026-017 raised 2026-07-24** (£4,247.00 + £849.40 VAT = £5,096.40, dated 2026-08-01, `src/dev/raise-fs-2026-017-vitacol-2026-07-24.ts`) — the first Vitacol invoice at full VAT rate. **Vitacol confirmed VAT-registered (owner, 2026-07-24)** — the recoverability concern is resolved. Still not actually emailed — send is a separate step (heads-up conversation may already be owner's job outside this system). (5) Set `vat_scheme` with the accountant — **standard/accrual, NOT Flat Rate** (limited-cost-trader 16.5% loses ~£166/mo; full analysis in compliance.md).2026-07-11
HIGHFO74inveritate-uk / tenancy · **3 Moyle Hill — set tenant fields before go-live.** `raise-rent.ts` skips this property because `detail.tenancy` is missing `tenantContactId`, `rentAccountId`, `active`, `startDate`, and `dayOfMonth`. When the new tenant moves in, update the asset via the API: add those five fields (model: 34 Brooklands — `tenantContactId: <CRM contact id>`, `rentAccountId: "acc_inveritate-uk_4000"`, `active: true`, `startDate: "YYYY-MM-DD"`, `dayOfMonth: 1`). Without them, no rent invoices will auto-generate each month. Monthly rent is £650 (`monthlyMinor: 65000`) — already in the asset.2026-07-01
HIGHFO73ledger / payroll · **When PAYE reference arrives (~2 weeks):** run first payroll for Jody (Folium) + Diana (Shinepics) covering June/July; post salary journals (Dr Wages / Cr DLA) to reverse the 2026-06-29 £500 advance each; pay HMRC PAYE/NI via bank transfer; check whether DLA net positions need any further adjustment. See write-app.md § "Pre-PAYE salary advances" for the reversal pattern + account refs (folium 1200, shinepics 1201). **Also at this checkpoint (added 2026-07-05): Miabella — a wage was paid as a DL from Wise, leaving books Wise (GBP) −£55.92 and Cash −£214.89 after the £2,000 Wise→Monzo transfer posted; reverse and re-post as wages from Monzo when registered as employer. Wise is forex-only going forward — expect these negatives to clear here, else revisit.**2026-06-29
HIGHFO72crm / invoices · when an invoice is raised for a brand-new contact, `contacts.counterparty_id` is not written back — causes the deposit-payment auto-advance to `booking` to silently skip (lookup `contacts WHERE counterparty_id = ?` returns nothing). Fix at invoice-creation time: after resolving/creating the counterparty, update the contact row. See crm-spine.md § "Gotcha — auto-advance requires contacts.counterparty_id". **2026-07-08:** two more affected contacts backfilled manually (Christine Preston, Mairead Roberts); the pipeline *value* lookup now has an email+entity fallback so display self-heals, but the deposit-payment auto-advance still needs the real back-link — root fix still open. **2026-07-15:** root fix shipped — `POST /api/invoices` now back-links any orphan contact (matched by email) when it creates a new counterparty (done alongside the invoice→booking work, crm-spine.md § import gap); verified on a scratch DB. Awaiting owner sign-off on a real raise before closing.2026-06-27
HIGHFO67shinepics-ltd / ledger · ensure raising journal + paid_minor are GL-backed on all new invoices — fix going forward, NOT a backfill of historic. Symptom found on WP-2026-005 (Luke and Ruth): invoice header carries paid_minor £50 + total £285 but `invoices.journal_id IS NULL` and no journal_lines reference the invoice (raising journal + £50 deposit both off-book in the GL). The £235 cash receipt posted 2026-06-16 is the only Luke/Ruth row in the GL; AR for that counterparty reads net Cr £235 because there's no offsetting Dr from the raise. Going-forward fix: assert invoice.journal_id NOT NULL on insert + invariant `paid_minor == SUM(journal_lines.credit_minor WHERE account_id=AR AND invoice_id=invoice.id)` at sync time. Don't patch existing rows.2026-06-16
HIGHFO42crm / clients · add edit capability to clients — currently read-only (just headings, not fully readable); need full CRUD for client contact/profile data2026-06-13
HIGHFO22CRM / billing · clients need invoices raised and recurring billing set up — 9 counterparties seeded 2026-06-12 from Customers.csv (andrew@waglandtextiles.com, bedatec, CW Make A Difference, Eden Brooke, Jackson Toms, PMC Rentals, Samantha Carbon, Staffs Council, We Are Lumina) via `src/dev/import-folium-customers.ts`. First invoices done. Remaining: test recurring billing setup + decide recurring cadence/product line per the amounts in Customers.csv.2026-06-12
HIGHFO18property / rental deposit · start process of refund against rental deposit scheme2026-06-12
Med
MEDFO82folium / crm / billing · **Build proper recurring billing — raise-at-due-date, not raise-8-months-early.** FO22 seeded 9 recurring invoices in one batch (`seed-folium-clients.ts`, 2026-06-14) including two set for 2027 renewal dates (FS-2026-012 Andrew Wagland 2027-02-27, FS-2026-013 Staffs Council 2027-03-01) — raised immediately instead of at their actual due date, which pulled a false VAT tax point into the current quarter once VAT-uplifted (found + fixed 2026-07-24, see FO80). Need an actual scheduling mechanism: each recurring product/counterparty carries its cadence + next-due-date; a job raises the invoice a sane window before that date (e.g. 30 days), not all at once at seed time. Scope: (1) design the cadence model (annual/monthly, anchor date) — probably a `recurring_billing` table keyed by counterparty+product; (2) a cron/dev-triggered job that raises due invoices in the window and skips the rest; (3) re-raise FS-2026-012 (Exchange mailboxes ×16 £1,840 + Promotional email £425, due ~2027-01-28) and FS-2026-013 (Annual web hosting £275, due ~2027-01-30) through the new mechanism once built, rather than by hand.2026-07-24
MEDFO81miabella / payroll · **When the Miabella PAYE reference arrives:** reverse the pre-PAYE salary advances to Mia and run the real payroll. Mia is the only payroll musician; until PAYE exists Jody has been paying her **from his own pocket, logged through 1010 Cash** with the director's loan (1200) as the other leg — e.g. 2026-07-01 Dr 1200 £500 / Cr 1010 £400 + Cr 1030 £100. **The Miabella cash account is therefore ~£214.89 NEGATIVE and that is EXPECTED, not a bug — do not 'tidy' it** (owner confirmed 2026-07-20); it unwinds when the advances reverse against salary. Per-gig performer fees (Colm, Aaron) are unrelated: outside PAYE, tagged person+booking, already clean. Mechanism: ledger.md § pre-PAYE salary advances. Owner will review properly once the ref is in hand.2026-07-20
MEDFO80operator-app / entity dashboard · build the entity **Inbox tab** as an OPERATIONAL work-queue, not a feed of the dev `_inbox.md` items (agreed 2026-07-09: those stay in the cross-project /today rollup). Sources, all per-entity from data we already hold: bank-feed statement lines awaiting review · open AR invoices due / AP bills payable · `compliance.json` items filtered by the existing `entity` field · period-close checklist. Stub + intent already marked in `master/app/src/views/Dashboard.jsx` header comment. Possible later: /today or the Hub shows a one-line-per-entity rollup ("Patrimonia: 4 unmatched lines, 1 bill due, VAT in 12d") linking into each entity's Inbox tab.2026-07-09
MEDFO78crm / pipeline · sibling-delete only fires on advance to `won` — leads sent to `lost` (e.g. QuoteComposer "Already booked" / unavailable-send.ts) strand their duplicate enquiry at the enquiry stage. Fix: run the same same-contact+entity sibling sweep on advance to `lost` and `booking` too (incl. inside unavailable-send). Related but probably not worth automating: mangled-email double-submits (partial form fire) create a *different* contact so contact-keyed dedup can't see them — manual cleanup per crm-spine.md § "Known gaps in the sibling-delete".2026-07-08
MEDFO79entities / compliance · **Register MIABELLA MUSIC LIMITED (Co. 17313977) in the estate** — new UK Ltd, registered office: Unit 29 Highcroft Industrial Estate, Enterprise Road, Horndean, Waterlooville, Hampshire, PO8 0BT. Add to the entities.ts SEED (registration facts live there, not DB edits) + compliance store (CT/accounts/CS deadlines once confirmation statement dates known). miabella.uk footer/terms/privacy already present the Ltd as site operator + data controller (updated 2026-07-08).2026-07-08
MEDFO77ar / selftest · `src/ar/selftest.ts` has ONE pre-existing failure: "ageing @06-30: 6000 outstanding in 31-60" gets all-zero buckets. Confirmed NOT caused by the 2026-07-07 invoice changes (fails identically on unmodified code via git stash). Suspect `arAgeing` as-of-date logic or the test's fixture dates. 21/22 pass. NOTE for FO67's future invariant: since 2026-07-07 a fully-free (£0-total) invoice legitimately has `journal_id IS NULL` — the "assert journal_id NOT NULL on insert" check must allow `total_minor = 0`.2026-07-07
MEDFO76ledger / bank feed · **"Receive payment" on money-in review lines** — the AR mirror of the Pay-bill panel: list open invoices fitting the line amount (same FX tolerance max(3%, 50p), same exact/part ranking), one click settles the invoice via the AR machinery + posts the journal FROM the line (born confirmed, nothing to match later) + optional **"send confirmation email"** tick reusing the Clients-flow send path. Why: today the Clients screen is the only place that settles+emails, so every customer receipt is marked paid there first and becomes a match-chore in the feed queue (Atmosphere MM-2026-004, 2026-07-05). Makes the feed the PRIMARY place incoming payments are processed; email timing then tracks money actually arriving. **2026-07-18:** the settle panel is live and grew a multi-invoice arm (one Stripe payout bundling several invoices — tick-to-combine, one combined journal; write-app.md § multi-invoice settle). Still outstanding from this item: the optional "send confirmation email" tick.2026-07-05
MEDFO68shinepics-ltd / ledger · record £50 cash deposit dated 2026-06-01 for WP-2026-005 (Luke and Ruth) — the deposit lives in `invoices.paid_minor` but has NO GL journal backing it (manual post needed: Dr 1010 Cash £50 / Cr 1100 Debtors £50, journal_date 2026-06-01, link `invoice_id` on the AR line). Pairs with FO67 (the going-forward fix) — this is the one historical patch we'll do for this invoice; everything else stays as-is per FO67's no-backfill stance.2026-06-16
MEDFO64published / thoughts · scaffold `/published/thoughts` in the FO published shell + Patrimonia voice — an annual "letter to the kids on why we are doing this" (ethical will / statement of intent); index holds one entry per year (e.g. "2026 — Why we began"). Doubles as a documented non-tax motive for defensibility. Architecture: patrimonia.co.uk = outward face · /published/thoughts = inward/family face · letter-of-wishes + deed = private. Claude scaffolds the page/index; the letter content stays the owner's to write.2026-06-16
MEDFO69ledger / inter-co · **METHODOLOGY SETTLED 2026-06-20** — intercompany pass-through invoicing: Miabella invoices Shinepics (not the other way; original entry had the direction wrong). Pattern: SP invoices the client for the full package (photo/video + music addon at cost); Mia invoices SP for the exact same music line-item amount — SP takes zero margin on the music booking. Only exception: evening band bookings where Mia invoices the client direct. Settled answers to original open questions: **(a) VAT** — Mia is NOT VAT-registered so her invoice to SP carries no VAT; clean, no recovery question. **(b) Transfer pricing** — no arm's-length problem: SP takes zero margin, so profit if anything flows toward Mia not away; below-market rate is legitimate (shared marketing, transport, brand — real structural cost advantage, not artificial); document once (not per-invoice) that Mia's rate reflects shared family-entity cost base; if Mia subs out a musician that is Mia's cost, SP never sees those third-party suppliers. **(c) Counterparty records** — add Miabella-uk-ltd as a supplier under `shinepics-ltd` + SP as a client under `miabella-uk-ltd`, both flagged `intercompany=1`. **(d) Journal mirror** — Mia: Dr 1100 Debtors (SP) / Cr 4000 Revenue; SP: Dr 6xxx Intercompany recharge — music / Cr 2100 Creditors (Mia); SP's client invoice: Dr 1100 Debtors (client) / Cr 4000 Revenue (full package); settlement: Dr 2100 / Cr 1010 Cash. SP CoA needs `6xxx Intercompany recharge — music` nominal adding. **(e) Elimination** — tag both legs `intercompany=1` (or `counterparty=related-entity` flag on journal_lines); consolidated view nets AR↔AP and Mia revenue↔SP expense to zero; only client-facing SP revenue survives. **Remaining implementation work:** ~~(1) add intercompany supplier/client counterparty records~~ ✅ done 2026-06-20; ~~(2) add SP nominal `6xxx Intercompany recharge — music`~~ ✅ done 2026-06-20 (nominal 6200); (3) add `intercompany` flag to counterparties + journal_lines (or a derived elimination view); (4) add one-off rate-setting note to docs/CONTEXT.md or entities.md; (5) wire up the AP bill path in SP + AR invoice path in Mia for this class of booking via UI (currently requires dev script).2026-06-16
MEDFO63ledger / banking · add inter-bank transfer UI to operator app — currently manual dev scripts only; add UI to post balanced transfers between nominals (e.g. Patrimonia Revolut → ANNA). **2026-07-26:** another manual instance — the £700 Revolut→Incard transfer (`transfer-revolut-to-incard-gbp-2026-07-22.ts`) that surfaced the Incard webhook gap now has evidence on BOTH sides (incard-feed + gocardless-feed) sitting unmatched in the review queue; posted the journal + matched both lines by script since there's still no UI path for "this staged line is one leg of a transfer I need to post the other leg of." A transfer UI would ideally do this in one step: pick two accounts + an amount, post the journal, auto-offer matching against any staged lines it satisfies.2026-06-15
MEDFO62crm / enquiries · handle enquiries where dates are taken — exclude from quote-counting metrics, auto-move to archive (date-taken status)2026-06-15
MEDFO56crm / quotes · venue reviews in quotes — capture review/testimonial data per venue so shinepics quotes pull relevant social proof (e.g. "Emma & Daniel · Belfast Castle" instead of generic "Emma & Daniel"). Default to generic testimonial if no venue-specific reviews exist. Unlock: populate a `venues` table (reference from bookings/enquiries) + optional `reviews` table (venue_id, quote, attribution) — quotes builder prefills from that data on preview. Low-friction capture: operator adds review directly in quotes UI or via admin.2026-06-14
MEDFO59miabella · email / migrations · mailchimp → Resend migration — use mail-chim-mia-import.csv to migrate contacts and send pure HTML emails2026-06-14
MEDFO38CRM / comms · cannot start a new comms thread from a client — no "New message" / compose button exists outside of invoice-send flow2026-06-13
MEDFO55crm / venues · central venue listing — first-class `venues` table (name + address + optional contact details) so booking entry picks from a canonical list instead of re-typing. Bookings reference a `venue_id`; address captured once and reused everywhere it's needed. Direct unlock for FO54 (calendar address sync) and a cleaner data source for FO53 (cross-brand calendar).2026-06-13
MEDFO53crm / calendar · cross-brand calendar view — single visual showing bookings/events across every brand. Placement TBD (portfolio tab / operator-app shell / dedicated published page). Now unblocked: the Google Calendar integration is live, so the data is there to fan out.2026-06-13
MEDFO46crm / weddings · send run sheet to bride 7 days before wedding for last-minute changes — automated email with event details/timeline2026-06-13
MEDFO41crm / bookings · "On The Day" PWA — small JSON-driven standalone site per booking, renders client wishlist as checklist so items can be marked off; prevents post-event "you didn't do this" disputes2026-06-13
MEDFO37ledger / chatbot · add a chatbot to the ledger that has access to the full corpus2026-06-13
MEDFO31CRM / operator-app · add Bookings section to daily inbox showing per-client booking workflow stages (quote → book → invoice → payment received → thank you → what to expect) as horizontal progress bars with completion status2026-06-12
MEDFO27Global / dashboard · new dashboard — visual here /home/jody/repos/family-office/docs/archive/pipeline-todo/design/master-overview-dashboard.html2026-06-12
MEDFO26Inveritate UK / payments · chase UC for payment from Ballywalter2026-06-12
MEDFO3ledger / holding-structure · **Monthly DLA sweep — holdco assumes each sub's director's loan** so subs carry no DLA, just an intercompany balance with Patrimonia; Jody's loan consolidates to one central line at `patrimonia-uk · 1200`. Per sub (credit balance B): sub posts Dr 1200 / Cr 2210, Patrimonia posts Dr 1210 / Cr 1200. Scope = UK subs only (folium, shinepics, miabella-uk, vidi); **exclude miabella-wy**. ✅ Accounts ready 2026-06-11 (2210 seeded on miabella-uk + vidi via `coa:init`; all 4 subs now have 1200 + 2210). **Remaining = build the routine:** idempotent monthly sweep keyed `dla-sweep:<sub>:<YYYY-MM>` with preview/confirm; **flag overdrawn DLAs (s.455)** rather than pooling silently (clean-up = net against the DL Patrimonia owes Jody, not cash repayment). Full design in `explainers/holding-structure.md` § "Monthly DLA sweep".2026-06-11
MEDFO15structure / vidi-systems-ltd · **J30 stock transfer Jody → Patrimonia before vidi starts billing** (part of the Web9→Vidi rename). Vidi incorporated 2026-05-25, BEFORE Patrimonia existed — legally Jody's until the J30; the seed's `parent_id` (and the Shareholders view) states the TARGET structure ahead of legal fact. On transfer: Patrimonia cost of investment = consideration → Dr 1500 (via DLA if no cash moves); vidi's own incorporation fee stays Jody's personal cost.2026-06-11
MEDFO16global · infrastructure · Sort out BackBlaze per project2026-06-11
Low
LOWFO89explainers / docs · **Recurring: re-check explainers/ monthly for oversized multi-topic files and split them.** Today's session split 4 monoliths that had grown from normal use — `write-app.md` (73KB), `bank-feed.md` (28KB), `crm-spine.md` (19KB), `operator-app.md` (19KB) — into slim 2-7KB indexes + 14 focused sub-explainers (commit `39c6fa0`), because a session working on one narrow feature was reading the whole file. Same approach next time: scan explainers/ file sizes, read the structure of any outlier, propose a cluster-to-file split (propose-then-confirm, don't just execute), apply on approval.2026-07-29
LOWFO13Global & In Veritate W, Orchrana · item =ledger; · Dashboard should see the Full Value, not just cash on hand2026-07-09
LOWFO70ledger / GL view · some SP journals still show raw `source_ref` in the Ref column after backfill + caller wiring (e.g. `pay:e8ac8425-…`, `interco:mia-sp:music:…`, `travel:sp:henry-…`). Mia entries resolved correctly. Likely the `ref` column is NULL for these rows despite the backfill reporting 127 updates — suspect the narrowed immutability trigger or a WAL snapshot issue at update time. Fix: run `SELECT id, source_ref, ref FROM journals WHERE entity_id='shinepics-ltd' AND ref IS NULL` to confirm, then re-run backfill or patch directly. Non-critical — display only; GL totals are correct.2026-06-20
LOWFO20capture/today · make today.html a PWA (manifest + service worker) — installable on phone, offline2026-06-12
High priority
HIGHWP5multi-locations · data-safety · `multilocation_install()` DROPs tables on update/reactivation (documents/DATA_MIGRATION_CRITICAL_ISSUE.md); verify `MultiLocations_DataMigrationFix` actually guards every path before the next client update2026-06-11
HIGHWP6multi-locations · security · hardcoded Google Maps API key in admin_editcounty.php:94 + LIKE queries without prepare() (counties/towns.php) — from VERSION_3.2_SUMMARY audit, unfixed2026-06-11
HIGHWP8herd · release · release v1 to WP team2026-06-11
HIGHWP14herd · security · rotate the exposed updater client token `csi-prod-10cb…` server-side (flagged in herd/todo.md 2026-06-08, still pending)2026-06-11
Med
MEDWP21speed-cache · infra · add a `sync-folium-ui.sh` script (only featherweight and sitewise have one; speed-cache requires manual file copying to vendor folium-ui updates)2026-06-14
MEDWP20sitewise · widget / design · apply new visual identity to chat widget on open (see explainers/issues/chat-widget-visual.png) — dark header, avatar row, action buttons with accent highlights2026-06-13
MEDWP19featherweight · competitor research · create a competitor folder and pull https://plugins.trac.wordpress.org/browser/disable-everything/trunk as the first plugin2026-06-13
MEDWP18sitewise · branding/licensing · powered by should not be optional unless paid2026-06-12
MEDWP2featherweight · i18n · WP 6.7+ notice on pepslogin: `_load_textdomain_just_in_time` — translations for the `wp-disable` domain load too early (move textdomain/translatable strings to `init` or later); shows on every wp-cli run2026-06-11
MEDWP4folium-ui · api · `Folium_UI::render_switcher()` is documented + called by sitewise's legacy `settings-page.php:21` but the method doesn't exist — silently renders empty (either implement it or kill the call when the legacy form is removed)2026-06-11
MEDWP7global · deployment · discuss GH commit for everything, where a repo is private and not public2026-06-11
MEDWP10multi-locations · admin/branding · bring into "by Folium" styling and fold2026-06-11
MEDWP11global · infrastructure · Sort out BackBlaze per project2026-06-11
MEDWP15herd · cleanup · dev/test cruft committed in the plugin (test-*.php, emergency-*.php, logs/debug.log, .csi-license-cache) — strip before any release2026-06-11
Low
LOWWP3global · test-site · pepslogin responds with an unexplained header `quantum-flux-capacity: Omega` on the front page — identify the source (mu-plugin? theme? nginx conf? leftover from the old compromise?); box is already flagged don't-trust2026-06-11
⚡ Quick Wins
LOWW7global · deploy · verify CF Access policies exist for folium reports portal and are scoped per client2026-06-11
High priority
HIGHW8global · email · migrate remaining SendGrid senders → Resend. Shinepics DONE 2026-07-05 (was `d=sendgrid.net`/`dmarc=fail`, Outlook "Unverified sender", sending IP PTR `o1.ptr3904.direct-peptides.com` — the shared SendGrid account u5325465 conflates us with the peptides business). Remaining: **miabella** (`contact.js`, root-domain auth so DMARC passes but same peptides PTR), **folium** (`enquire.js`, same), **taylorlally** (`contact.js`, NO SendGrid domain auth → likely dmarc=fail like shinepics was; From = env `FROM_EMAIL`). mail.miabella.uk + mail.foliumstudio.co.uk already Resend-verified (FO CRM)2026-06-11
Med
MEDW20global · deploy · `scripts/build.js` is gitignored fleet-wide (miabella, shinepics, ochrana, hosting-io, parinama all `.gitignore` scripts/* except deploy.config.sh) — contradicts `websites/CLAUDE.md`'s "One Rule" (commit build logic for redundancy). Decide: un-ignore build.js fleet-wide, or correct the stated rule. Surfaced while fixing miabella's missing Meta Pixel snippet (that fix lives only in the untracked build.js).2026-07-26
MEDW15global · workflow · Add a defined **voice** for each website (tone, vocabulary, target reader, what we sound like / don't sound like) so new content is easier to start and plan. Pairs with W14 — "voice + idea" is a much cheaper starting point than "idea + figure out tone every time."2026-06-16
MEDW14global · workflow · Build a new capture skill **"writing pipeline"** — content ideas / thoughts about content land in random places and get forgotten or never captured. Top-level `writing-pipeline/` folder with one sub-folder per project; an idea gets added as a quick capture, then after a brief discussion gets promoted to a high-level MD file in a **"confirmed post pipeline"** for full fleshing-out and publishing. Workflow: capture → brief discussion → high-level MD → confirmed-post pipeline → publish.2026-06-16
MEDW17global · chatbot · add chat analytics/logging to chatbots — capture user chats for analysis (see /home/jody/repos/family-office/explainers/issues/chat-bot-analysis.png for example)2026-06-15
MEDW12shinepics · form · convert the form to a component instead of per page embeds, so it's 1 global changed when needed2026-06-15
MEDW10shinepics · quotes · venue reviews in quotes — capture review/testimonial data per venue so shinepics quotes pull relevant social proof (e.g. "Emma & Daniel · Belfast Castle" instead of generic). Default to generic if no venue-specific reviews exist. Pairs with FO56 (same feature for family-office quotes builder).2026-06-14
MEDW9meridian · design · new visual for Meridian — sample here /home/jody/repos/meridian/docs/Dashboard peps new.html2026-06-12
MEDW2folium · content · blog post + service page: WordPress plugins philosophy (why Folium builds plugins; position as strategic vs. legacy; anchor to rebrand Featherweight/Herd/Sitewise)2026-06-11
MEDW5inveritatellc · migration · convert from WordPress to static Pages and decommission old WP2026-06-11
MEDW6nautica · migration · convert from WordPress to static Pages and decommission old WP2026-06-11
Low
LOWW19hosting-io · deploy · hosting-io deploy cards now post to campaigns entity `folium` (per its router: "folium (shared)"), but sites.json also has a separate `hosting` entity (host hosting.io) — confirm folium is right or repoint `CAMPAIGNS_SITE_ID` in hosting-io/scripts/deploy.config.sh2026-07-08
LOWW18global · email · after W8 completes, remove unused `SENDGRID_API_KEY` Pages secrets (shinepics's is already dead code) and retire the shared peptides SendGrid key from Folium sites2026-07-05
LOWW3folium · UX · thank-you page after form submit on `/api/enquire` (currently no post-submit UX; consider email link or redirect)2026-06-11
⚡ Quick Wins
LOWC2global · infrastructure · plan migration to Vidi Systems — folder rename, or bigger rebranding/restructuring?2026-06-11
Med
MEDC13global · bot-observability · build a bot-observability analysis skill, as the natural partner to Link Health — Link Health says *should* this page be reachable & authoritative; Bot Obs says *did* the bot actually come. Surface the gap between predicted-reach and actual-crawl (by bot family) as the headline metric — the most interesting number on the platform2026-06-22
MEDC11global · link-health · add red-team drop points as Lint "Knowledge Gap" items — each red-team drop turn becomes a Lint finding on the page that should answer it (input-side counterpart to the drop)2026-06-22
MEDC12global · link-health · add AI analysis of click depth + suggested fixes — interpret the depth/incoming-link map (e.g. thin+deep venue pages) and emit concrete "add a link from X, Y" recommendations2026-06-22
MEDC10global · ai-visibility · add rank change indicator over the last 6 checks per keyword — shows trend (↑/↓/→) to surface volatility2026-06-15
MEDC9global · ai-synthesis · AI Synthesis against the body corpus - a weekly run against the models - "what do you know about xyz" then, compare that to the body corpus for the brand and flag OK or needs fixing2026-06-15
MEDC8global · automation · build an automation to track and validate change to scrape to results2026-06-14
MEDC6global · SERPs · save SERP results to JSON for later AI analysis — currently single-run output; persist for comparative + temporal analysis2026-06-13
MEDC3global · deployment · discuss GH commit for everything, where a repo is private and not public2026-06-11
MEDC4global · infrastructure · Sort out BackBlaze per project2026-06-11
MEDC1global · branding · rebrand the campaigns app/product as Vidi/GetVidi2026-06-10
Low
LOWC14nautica · sites.json · nautica's registry host is `nauticaprima.com` but the live site (nautica-prima repo) deploys to nauticalandmarine.co.uk — check the `cfZoneTag`/bot data point at the right CF zone2026-07-08
High priority
HIGHPS18originsequence · **Product copy is raw/uncensored, imported verbatim from peptide-works.com** — full therapeutic-benefit language the site's own compliance brief bans (§1), sitting live on the PDP. One description also carries an embedded outbound link to peptide-works.com (BPC-157) — strip that regardless, sooner than the full rewrite. Blocking for anything beyond internal testing. Ref: [../html sites/originsequence/ROADMAP.md](../html%20sites/originsequence/ROADMAP.md) §0/§0a.2026-07-24
HIGHPS19originsequence · **Product photos are literally Peptide-Works' own branded vial photography** ("PEPTIDE WORKS" printed on the label) — fine to prove the real-data pipeline works, not fine for anything real. Needs actual OriginSequence photography or de-branded images. Ref: [../html sites/originsequence/ROADMAP.md](../html%20sites/originsequence/ROADMAP.md) §0.2026-07-24
HIGHPS17DP + PLG/PG/DS (PW has no multi-locations) · **multi-locations subdomains have no robots.txt/canonical guard against crawlers** — root cause of the 2026-07-21 ExaSearchBot 504 incident on DP: 40+ country-subdomain variants serve uncached duplicate content, so any well-behaved-but-thorough crawler hitting them at volume re-triggers PHP-FPM worker exhaustion. Stopgapped with a per-bot, subdomain-scoped CF WAF rule (patched fleet-wide same day — DP/PLG/PG/PW/DS, see [portfolio.md](portfolio.md) pattern #4), but that only covers ExaSearchBot — the next new crawler hits the same wall. **2026-07-30: hit again on PLG** — this time a diverse mix (Googlebot/Bing-Azure bots/YouBot/OAI-SearchBot/UptimeRobot/generic), no single signature or ASN to block, 389 confirmed 504s + full FPM saturation (load 20+ on 4 cores). Emergency stopgap this time was a CF managed_challenge on all subdomains (operator does NOT want this kept — upsets clients — to be disabled once PS17 itself is fixed properly). Proper fix: `robots.txt` disallow + `rel=canonical` back to the primary domain on subdomain variants, so crawlers don't attempt them in the first place.2026-07-21
HIGHPS15all 5 sites · **`pepsdata_bank_sync_config` WP-cron didn't fire on its own** — new EUR/GBP bank accounts added on pepsdata.com sat un-synced until manually forced (`Bank_Local_Selector::sync_from_dashboard()` via wp-cli, see [pepsdata-bank-transfer.md](pepsdata-bank-transfer.md)). **Recurred same day**: Gordon's `account_number`→BIC edit also sat un-synced on PLG/DP until forced again — 2nd occurrence in one session, hitting live customer emails each time. Likely same WP-cron reliability family as `PS11`. Root cause not diagnosed.2026-07-20
HIGHPS11DP (likely PG too) · **multi-locations kills all wp-cli runs → WP-cron never fires** — `clear_spin_cache_cron()` runs on any CLI load (`defined('STDIN')`), rsyncs spinner cache empty and `exit`s. With `DISABLE_WP_CRON=true`, gpsitecron's 5-min wp-cli run dies at plugin load (see gp-cron.log), so scheduled WP events never execute (Action Scheduler survives via admin-ajax loopback). Fix in multi-locations (our plugin): gate the STDIN block behind an explicit flag (e.g. `ML_CLEAR_SPINNER_CACHE=1` env or `wp ml clear-spinner-cache` command). ⚠️ When fixed, a backlog of stale cron events will fire — clean `wp cron event list` first (remember the 2026-05 wccs cron-bloat outage).2026-07-02
HIGHPS12DP · **Fena webhooks not delivering** — two `paid` payments (2026-07-02 06:09, 06:46) produced zero webhook POSTs at origin despite the URL saved in the Fena dashboard. Raise with Fena support; verify the webhook URL sits on the same integration as terminal `6a45feae…` and "Retry webhook on failure" is on. Safety-net poller (mu-plugin + root cron, 5 min) deployed meanwhile — orders complete regardless. Longer-term: fold Fena into pepsdata — **plan written: [migrate-fena.md](migrate-fena.md)** (also removes the update-reverts-patches risk on the 3 patched fena-ecommerce files). **2026-07-04: native gateway BUILT + STAGED on DP disabled (pepsdata 0.8.786) — cutover runbook in migrate-fena.md, needs operator quiet window + £-small live test.** **2026-07-04 evening: LIVE — £4.31 test payment confirmed end-to-end via native poller (webhook still not delivered by Fena, so the support complaint stands). Migration functionally complete; remaining = repoint Fena dashboard webhook URL + raise webhook issue with Fena support; close on user sign-off.** **2026-07-06: rolled out to PLG too (own terminal `6a4cad89…`, £50.34 test green via poller). Operator has contacted Fena support re webhook delivery — awaiting response.** **2026-07-08: PG live too (£4.05 test green). LIVE on 3/5 sites.** **2026-07-09 RESOLVED (root cause was OURS): our CF "bot block" rules block all of Google Cloud (`asnum eq 396982`); Fena's sender is axios on rotating GCP IPs → every webhook 403'd at the edge since 2 July. Fixed on DP/PLG/PG/DS with a `/wc-api/` exemption; verified through CF with Fena's UA. Remaining before close: (a) reply sent to Fena (correcting the record + their egress-IP info was wrong + recommend signed webhooks/distinctive UA), (b) confirm next real payment completes via webhook not poller, (c) PW/DS rollout when wanted. Full state: [migrate-fena.md](migrate-fena.md) ⭐ CURRENT STATE.**2026-07-02
HIGHPS8peps / pepsdata · plan a transition from pepsdata to new2026-06-12
Med
MEDPS23peps / reporting · **AOV + sales-by-country % per site** — one-off manual pull done + cross-verified 2026-07-24 (real numbers already sent to Joanna/Jason). Key finding: path (b) won, decisively — no new plugin/data layer needed at all, the existing hourly exporter's `orders.csv` already has everything, this is a pure local-aggregation job. Remaining: build the local `data:build-aov-country` step + a new meridian page per the plan in [aov-country-report.md](aov-country-report.md); resolve that doc's open question (completed-only vs completed+processing — may explain the PLG £108k-actual vs £150k-Jason's-quote gap) before treating it as the report of record.2026-07-24
MEDPS20originsequence · Post-payment pages (Stripe `success_url` → Woo order-received, Woo's thank-you page) still render Woo UI — same trust seam as the pre-payment checkout just fixed (Phase 3b), now sitting after payment instead. Ref: [../html sites/originsequence/ROADMAP.md](../html%20sites/originsequence/ROADMAP.md) §3b known gaps.2026-07-24
MEDPS14peps / pepsreport · **Scoped KV-write CF API token for the hourly publish** — mint in dashboard (My Profile → API Tokens → Custom: Account / Workers KV Storage / Edit, this account only), paste into `~/.config/meridian/pepsreport.env` (`CLOUDFLARE_API_TOKEN=`, keep mode 600). Until then run-server.sh falls back to the box's wrangler OAuth session (works, but broader perms than cron should hold). Also: eyeball Overview/P&L/Bank Feeds once in an Access-authenticated browser. Ref: [pepsreport.md](pepsreport.md)2026-07-17
MEDPS13peps / range · **Per-SKU contribution-margin + dead-stock/shelf-life analysis** — model per SKU: revenue − landed COGS − *real* postage − processing, × velocity × shelf life, to surface loss-making / dead stock (high-cost, slow-moving, expiring — possibly costs > sale price). **BLOCKED on supplier cost sheet** (ask for: SKU, unit landed cost, pack/case size, shelf-life or expiry/batch). Inputs already local: velocity+stock-on-hand per SKU in `meridian/src/lib/generated-slow-movers.ts` (from `peps_slow_movers.php`); revenue via `scripts/substance-revenue.sh` (extend to per-SKU). Trigger: melanotan ≈ £100k/yr gross group / ~£50k net — hypothesis it's not isolated.2026-07-13
MEDPS9DP DD · Manual review pass on RED content list — build `EXCLUDE_FROM_CONTENT_RISK` set in `classify.js` for legitimate research articles caught by dosing patterns. Ref: [direct-peptides-dd.md](direct-peptides-dd.md)2026-06-21
MEDPS7peps / dashboard · rebuild main dashboard visual2026-06-12
MEDPS1DS · Firefox POST resend / duplicate cart on currency switch for variable products — WC form POST → WC GET redirect → pepsdata currency redirect → Firefox sees URL with POST history → resend dialog → duplicate cart add. Fix in `redirectWithQuery()`: detect `single-product` body class and append `#switched` fragment, or use `history.replaceState` on arrival. Fold into next pepsdata update.2026-06-11
MEDPS3pepsdata · WP Rocket adapter for Currency_Cache — currently only GP SRCache auto-integrated; PLG/PG run WP Rocket with a mu-plugin stopgap. Real fix: detect WP Rocket in Currency_Cache, register `rocket_cache_dynamic_cookies` filter, call `rocket_generate_config_file()`, remove mu-plugins. Also prototype for wp-disable WC-cache addon.2026-06-10
MEDPS4PG/DP/DS · Exchange rate API keys missing — PG: no key, hardcoded defaults (USD 1.27/CAD 1.72); DP: key empty, rates present but drifting; DS: manual-copy stopgap. Set key via pepsdata admin → `Currency_Updater::update_rates()` as site user → clear page cache. See pepsdata.md for one-liner.2026-06-10
Low
LOWPS25peps / meridian · **Forecast tab's saved `procRate` can go stale against the canonical blended rate** — 2026-07-27 incident: saved Forecast state (`forecast-state-v1` KV) had `procRate: 0.0795` from before `PROCESSING_FEE_RATE` was recalibrated to a ~4.10% blended rails-mix rate, causing Forecast to show a ~£3.9k loss vs P&L's small profit for the same month. Fixed by resetting the saved value, but it's a plain snapshot not a live formula — will drift again if the rails mix shifts further. Ref: [pepsreport.md § The Forecast tab is a SEPARATE calculation path](pepsreport.md#the-forecast-tab-is-a-separate-calculation-path--not-what-pepsreport-shows).2026-07-27
LOWPS24peps / rails · **Ecospend (Trustly's UK entity) + Trustly itself — new candidate pay-by-bank rails** — nothing researched yet, just flagging alongside the existing TrueLayer/Wallid candidates for a future `migrate-*.md`-style evaluation. Underwriting fit looks comfortable on the same logic as the TrueLayer onboarding call: Trustly's network spans iGaming, wealth, credit, and lending — all more heavily scrutinized than RUO peptides — but that's a hypothesis, not yet checked against Trustly/Ecospend's own restricted-business list the way TrueLayer's was.2026-07-26
LOWPS21originsequence · Stripe's `cancel_url` points at Woo's cart page, not the OriginSequence storefront — a customer backing out of Stripe Checkout lands somewhere unbranded. Touches Nummaria gateway code (`class-nm-gateway-stripe.php`), not the storefront itself. Ref: [../html sites/originsequence/ROADMAP.md](../html%20sites/originsequence/ROADMAP.md) §3b known gaps.2026-07-24
LOWPS22originsequence · Catalogue is 8 of the ~100-product ambition (Blends/Reagents/Accessories nav categories exist but are empty); COA batch numbers are derived deterministically from SKU, not a real per-batch lab record; only one photo per product (no gallery/thumbnails). Bundle of low-priority polish for whenever catalogue work resumes. Ref: [../html sites/originsequence/ROADMAP.md](../html%20sites/originsequence/ROADMAP.md) §0/§0a.2026-07-24
LOWPS5docs · Structured YAML catalog block per site — add a YAML-fenced `catalog:` block at top of each `explainers/sites/<site>.md` (pepsdata_version, currency_plugin, cache_layer, php_fpm_terminate_timeout, multi_locations_count, last_recon) to enable precise cross-portfolio grep queries.2026-06-09
LOWPS6infra · Lightweight audit script — `/root/scripts/audit.sh` that SSHes each server, pulls live state for catalog fields, diffs vs docs. Auto-surfaces drift instead of relying on maintenance discipline alone.2026-06-09
Governance
GOVERNANCEBoard resolutions — 4 company actionsGroup