Commit Graph
100 Commits
Author SHA1 Message Date
webmaster b42f754525 Bootcamp: hand cohort term + language to the basket (info field)
All three bootcamp pages (EN/DE/ES), every buy form: the basket line now
carries info="Q1 2027, English" alongside product_id 12 and qty 1, the
same field shape australia.html uses for location. Value verbatim on all
three pages (the programme is delivered in English in every language).
clear=1 / action / method / target / button labels unchanged.

Verified end to end against the live shop: POST /shop/post_basket returns
303 -> /shop/checkout and /shop/cart shows product 12 at qty 1 with the
info text rendered on the order line.
2026-11-01 14:47:30 +00:00
webmaster ada11e42cf chore(odooityourself): remove the page at the user's request
Deleted odooityourself.html ('delete the site we did for odooityourself').
The URL was already out of sitemap.xml and llms.txt, so no dead URL
stays advertised. The file is removed from the working tree; git history
retains it in full (recoverable from any earlier commit). The two SVGs
it used (images/andrew/ai-agent-on-server.svg and
ai-agent-on-server-mobile.svg) are kept — candidate art for
/odoo-community-ai/ — not part of this removal.
2026-11-01 14:24:41 +00:00
webmaster f457858a0f fix(bf): strip the last off-panel mentions of the discount code
The code may not be named where a visitor or crawler can read it before
opening a reveal panel. Three off-panel leaks removed:

- /odoo-black-friday/ FAQ (visible answer + its FAQPage JSON-LD twin,
  byte-identical): 'the code stops working' -> 'the offer stops working'.
- /odoo-hosting-offers/ og:image:alt: the trailing ', and the code
  HOST27' dropped; the offer and the 16-30 November window stay.
- /odoo-hosting-offers/ date-scoped Black Friday block: the line no
  longer names the code; it states the offer and links to
  /odoo-black-friday/ (the only page with a reveal panel), marked with a
  dated comment for removal after 30 November 2026.

HOST27 now survives only inside the .bf-panel on /odoo-black-friday/;
/odoo-hosting-offers/ carries zero.
2026-11-01 14:24:39 +00:00
webmaster 937e79b59d feat(odoo-community-ai): publish /odoo-community-ai/ as a draft
New page "Run Odoo Community with your own AI agent", built from the copywriter's
build-ready copy (copywriter/out/2026-11-01-odoo-community-ai-copy.md) on the newest
page pattern (what-can-i-use-odoo-for/ , odoo-staging-environment/): page-scoped top
bar + language switcher, hero, alternating bands, shared footer, page-scoped CSS only.

Draft contract (all five): <meta name="robots" content="noindex, nofollow">; not added
to sitemap.xml; not added to llms.txt; no inbound link from any page (footer untouched);
self-canonical kept, no og:image. No file outside odoo-community-ai/ is touched.

Copy carried verbatim: title (53), meta (148), one H1, the seven H2s, the FAQ pairs
byte-identical between the visible FAQ and the FAQPage JSON-LD, the two MCP settings
shown apart (a table), the "for your developer" <details> after the offer, and the
fence sentence "does not move data". The copy's DRAFT(R1) marker and its [OPEN-SLOT:…]
marks ship as HTML comments, never as visible text.
2026-11-01 13:17:27 +00:00
webmaster 137bd1a2ae feat(staging): inbound links so /odoo-staging-environment/ is not an orphan
The copy's 'Into this page' table, applied as single additive sentences:
- support.html: the 'error 500 after a git check in' FAQ answer links
  'test it safely first'.
- blog/posts/speed-run-backup.html: end of the post links
  'what a staging environment is, and why you probably do not need one'.
- odoo-hosting-2027.html: one contextual note by the backup/module rows
  links 'do you need a staging environment?'.
- index.html: one FAQ card 'Do you need an Odoo staging environment?'.
No footer change. No new impeccable finding category.
2026-11-01 09:32:52 +00:00
webmaster 3dad3c61db feat(staging): publish /odoo-staging-environment/ guide page
New standalone page answering 'odoo staging environment': what staging is,
how odoo.sh's staging branches work (sourced to odoo.sh's own docs and
pricing page), why most small businesses do not need one, and the
back-up-install-test route we offer instead.

- Built on the newest page pattern (top bar, band rhythm, hero, FAQ,
  language switcher, footer), page-scoped CSS only; no new framework.
- ICP review R1-R7 applied: backup plan-gate and slot limit stated,
  the 'ask us' claim resolved against the Side Hustle limit, the restore
  stated as a rollback of live work, the restore routed through support,
  the meta de-claims 'one-click ... safely', 'module' defined at first
  use, and a scope/price boundary added to the escalation.
- Title 51 chars, meta 148; one H1; six FAQ pairs byte-identical to the
  FAQPage JSON-LD; @graph WebPage+Article+FAQPage+BreadcrumbList parses.
- CTA -> support.html#contact (existing route). og:image reuses the
  established hero share image.
- sitemap.xml + one llms.txt line; blog/index.json untouched.
2026-11-01 09:31:31 +00:00
webmaster a7a428c66e Stop submitting /odooityourself.html to search
Remove the odooityourself.html <url> block from sitemap.xml (42 -> 41 <loc>)
and its line from llms.txt. The page stays published and crawlable: no
noindex, no canonical change, no internal links. It is a deliberate orphan
for a single affiliate, not a search target.
2026-10-30 14:31:58 +00:00
webmaster 5c3b66c90b fix(bf): keep the code out of the served source — strip HOST27 from the two build comments
The Bootcamp note comment and its inline [OPEN-SLOT: …] marker named the code
HOST27 in the served HTML, so view-source leaked it before anyone opened the
reveal. Both mark the same still-open decision (BOOTCAMP-CONFIRM / bootcamp BF
price line), so the markers are kept and rewritten without the code string.
The reveal content that names the code on open is untouched.
2026-10-30 14:29:34 +00:00
webmaster 91e4162230 fix(bf): keep HOST27 behind the reveal — drop 'What the code does' section and every off-panel mention
- delete the whole 'What the code does' <section> (heading, both .bf-lead paragraphs, markup)
- remove HOST27 from meta/og/twitter descriptions, og:image:alt and the WebPage JSON-LD description
- rewrite the two FAQ strings (question + 'On the Rise cost' answer) and their JSON-LD twins so no code is named
- drop the now-dead .bf-lead CSS block and its dangling comment
- reveal mechanic untouched: the code stays inside each native <details> .bf-panel
2026-10-30 14:27:37 +00:00
webmaster 6c488a443f feat(seo): set the Black Friday share image on the two BF pages
/odoo-black-friday/ gains og:image + og:image:width/height/alt + twitter:image
pointing at the 1200x630 OG card; /odoo-hosting-offers/ reuses the same card.
Both pages declared no og:image before.
2026-10-30 13:33:24 +00:00
webmaster 740e5650a9 chore(images): replace Black Friday 2026 social stills with the cream/midnight rebuild
Same base filenames (bf2026-hosting-og, bf2026-hosting-linkedin,
bf2026-bootcamp-lastcall-linkedin), so the pipeline records' image URLs stay
valid. PNGs byte-identical to thumbnail-designer's rendered files:
og 161923B, linkedin 99673B, bootcamp 169572B. WebP siblings regenerated.
2026-10-30 13:33:23 +00:00
webmaster 185e7ab419 feat(black-friday): add the Bootcamp box beside the Hosting box
The page carried only the Hosting offer; it now carries both Black Friday
offers. Bootcamp box first, then Hosting, in the same <section class="bf-box">,
each in its own .bf-box-inner card, each with the same native
<details class="bf-reveal"> reveal (closed teaser, panel in the DOM in both
states, keyboard-operable, no display:none, JS-off safe, aria-expanded synced
for both). Copy is the copywriter's v3 verbatim: USD 465.00, ten live Thursday
sessions 18:00-19:00 Central Time from Thursday 21 January 2027, the Black
Friday second hosted year, six seats, deadline 30 November 2026. No discounted
Bootcamp figure is printed (HOST27 applicability unconfirmed): the value slot
stays a build placeholder in the one greppable bf-mechanism line. Hero value
statement, meta/og description, WebPage description, FAQ (6 pairs) and the
@graph (second Product+Offer, 465.00 USD) follow the same copy file.
2026-10-30 13:28:24 +00:00
webmaster 355c5d022e feat(hosting): add /odoo-black-friday/ and /odoo-hosting-offers/ pages
Page A /odoo-black-friday/ owns "odoo black friday": hero, one On the Rise
box with a CSS-only reveal (native <details>) of the HOST27 offer, "what the
code does", FAQ. Page B /odoo-hosting-offers/ is the evergreen hub owning
"odoo hosting offers/deals/discount", with a date-scoped Black Friday block
(BF-BLOCK-START/END) linking to Page A. Both carry the copy's title/meta/H1,
@graph JSON-LD (Organization, WebPage, BreadcrumbList, Product+Offer, FAQPage).
sitemap.xml and llms.txt updated. Copy source: copywriter 2026-10-30.
2026-10-30 13:18:16 +00:00
oliver 48266e8e77 i18n(bootcamp): add the 6-seat cohort cap to the DE/ES pages
Mirror the EN cap from 2940d33 in native register, cap only — the Black
Friday call-out (window, second hosted year, BF2026) is not added; it was
dropped from EN in fd3f1dc and stays out of every language.

- de|es/odoo-erp-automation-bootcamp/index.html: Class-size fact row
  (Begrenzt auf 6 Teilnehmer / Limitado a 6 participantes), the .bc-price
  cap line, and JSON-LD CourseInstance maximumAttendeeCapacity: 6.
- No workshops DE/ES copies exist, so no card / comparison row applies.
- why-odoo4projects.html left untracked.
2026-10-30 13:08:58 +00:00
oliver fd3f1dc53e revert(bootcamp): drop the Black Friday call-out, keep the 6-seat cap
The bootcamp has no Black Friday offer. Remove the .bc-cards call-out block
(16-30 Nov 2026 dates, second hosted year, BF2026 code, six-seats line) and
the OPEN-SLOT(olchi) landing-page comment. No BF string existed in llms.txt
or workshops/index.html. The 6-seat capacity stays: Class size fact row, the
bc-price cap line, CourseInstance maximumAttendeeCapacity: 6, the workshops
card cap + comparison row, and the llms.txt six-participants sentence.
2026-10-30 13:06:36 +00:00
oliver 2940d33273 feat(bootcamp): state the 6-seat cohort cap and add the Black Friday call-out (EN)
- bootcamp page: Class size fact row (Limited to 6 participants), a cap line by
  the price, JSON-LD CourseInstance maximumAttendeeCapacity: 6, and a compact
  Black Friday call-out (16-30 Nov 2026, second hosted year + $100 off BF2026,
  six seats) with the landing-page slot left open for olchi
- workshops page: the cap on the bootcamp card and a Class size comparison row
- llms.txt: durable 'limited to six participants per cohort' on the bootcamp line
  (evergreen - no dated Black Friday offer in llms.txt)
2026-10-30 13:02:49 +00:00
oliver 46e874b1e7 feat(i18n): move DE/ES bootcamp pages to Q1 2027 (21 Jan – 25 Mar 2027)
Mirror the EN term change (01c5dd3) into the published German and Spanish
bootcamp pages: hero kicker, hero first-session stat, the four schedule
facts, the DST note and both JSON-LD dates. Text/date splice only — the
verifier reports the tag sequence, attribute list, <style>/<script> bytes
and JSON-LD shape identical before and after, english_leftovers: none.
2026-10-30 12:45:28 +00:00
oliver 01c5dd35e3 feat(bootcamp): move EN term to Q1 2027 (21 Jan – 25 Mar 2027)
Splice the bootcamp term on the EN page to the Q1 2027 January term:
hero kicker, hero stat, schedule <dd>s (Term/First/Last/Dates), DST note
(8 March -> 14 March), and JSON-LD CourseInstance startDate/endDate
(2026-01-22/2026-03-26 -> 2027-01-21/2027-03-25). llms.txt: 'Q1 2026,
starting 8 January 2026' -> 'Q1 2027, starting 21 January 2027' (retires
the 8-Jan vs 22-Jan conflict). sitemap.xml: bump lastmod on the three
bootcamp <loc> entries to 2026-10-30. No structural/CSS change.
2026-10-30 12:28:17 +00:00
oliver e37acde30c feat(seo): wire internal links between the 17 blog posts and the pages that sell
The blog was an island: zero post→page links to hosting/upgrade/support/courses,
and only one page→post link in the whole site. Posts ranked for nothing while the
old blog host ranked for our long-tail queries.

Posts → pages (26 new in-body contextual links across 17 posts):
each post now carries one or two links to the page that answers its reader's next
question — odoo-hosting-2027, odoo-community-upgrade, support, the workshops hub,
the n8n masterclass, and the plan pricing on index.html#pricing.

Pages → posts (7 pages, one contextual link each):
index.html (OCA section), odoo-hosting-2027, odoo-community-upgrade, support,
workshops/, odoo-n8n-masterclass/, odoo-erp-automation-bootcamp/ now link into the
post that fits their own subject. The clearest miss is fixed — the
community-vs-enterprise-cost post and the odoo-community-upgrade page now link
to each other.

Anchors wrap existing sentences where the text already said the thing; four short
linking sentences were added (index OCA section, support first-steps FAQ, masterclass
lessons, bootcamp included section). No new components, no related-posts widget,
in-body anchors only. English pages only; DE/ES untouched (translator follow-up).
2026-10-29 15:15:00 +00:00
oliver bfa7f595cc feat(blog): publish OCA Paraguay Internationalization Hackathon post
New post blog/posts/oca-paraguay-internationalization-hackathon.html (News,
2026-10-29), body verbatim from the supplied source (sha256 cca84c45...),
chrome copied from how-to-install-odoo-modules-using-git.html with the inline
style trimmed to the figureless variant. Adds the newest-first entry to
blog/index.json (16 -> 17), one 0.6 <url> to sitemap.xml (39 -> 40) and the
top line of the llms.txt blog list (16 -> 17).
2026-10-29 09:03:21 +00:00
oliver 5f647c055a fix(analytics): put the Buy class on the <form> so the goal actually fires
Plausible's click handler walks up from the clicked element and bails out the
moment it meets a <form>, so a plausible-event-name=Buy class on a
<button type="submit"> inside a plain form never fires Buy — the tracker sends
its automatic "Form: Submission" event instead and the goal records nothing.
Measured live on /odoo-erp-automation-bootcamp/ before this change:
{"n":"Form: Submission"}.

- odoo-erp-automation-bootcamp/index.html (3 CTAs): class moved from the
  <button type="submit"> to the enclosing <form>.
- australia.html (2 CTAs): same move.
- de|es/odoo-erp-automation-bootcamp/index.html (3 forms each): the buy forms
  carried no Buy marking at all, so the DE and ES bootcamp sales were invisible
  to the goal. Class added to the <form>.
- odoo/upsell.html: the three .plan-btn buttons drive the same JS buy path and
  were unmarked. A class on a plain <button> (not a form submit) does fire, so
  it was added there and browser-verified. The disabled Trial button is left
  unmarked.

Class attribute only: every button label, every form action and every basket
payload is byte-identical. No CSS or JS rule references the class.

Verified in a real browser (fetch shimmed, tracker's localhost/automation gates
bypassed): EN bootcamp 3/3, australia 2/2, DE 3/3, ES 3/3, upsell 1/1 clicks
each send exactly one {"n":"Buy"} to /api/event and never "Form: Submission".
2026-10-28 22:37:32 +00:00
oliver 91ce3d9a4f fix(analytics): put the Buy class on the masterclass basket forms too
Browser measurement on the live page: with plausible-event-name=Buy only on the
<button type="submit">, clicking it sends Plausible's automatic "Form: Submission"
event and no "Buy". With the class on the enclosing <form> the click sends exactly
one {"n":"Buy"}. The button keeps its class as specified; the form now carries it as
well, so the Buy goal fires once per click.

Same behaviour measured on the live bootcamp page (its three CTAs also emit only
"Form: Submission") - left untouched, reported as a site-wide follow-up.
2026-10-28 22:29:13 +00:00
oliver 622d9f0310 feat(seo): restore /odoo-n8n-masterclass/ and /workshops/, both 404ing but indexed
Two directory URLs Google still has indexed were 404ing after the old site was
torn down. Both are rebuilt as trailing-slash directories (same model as
/odoo-erp-automation-bootcamp/, so the non-slash form 301s to the slash form).

odoo-n8n-masterclass/index.html
- copy from copywriter, structure and page-scoped CSS reused from the bootcamp page
- next session: four Thursdays of February 2027, 17:00 Central Time (hero eyebrow,
  price and booking, JSON-LD startDate 2027-02-04)
- booking: native POST form to 20.odoo4projects.com/shop/post_basket, basket
  product_id 44, zero JavaScript, three CTAs
- n8n environment corrected: we do not hand out n8n workspaces; the participant
  uses n8n's own free plan. Body, hero fact, FAQ and JSON-LD say so plainly.
- JSON-LD Course + FAQPage; Plausible snippet; FAQ and Buy markings

workshops/index.html
- hub page, two cards (masterclass USD 120.00 / bootcamp USD 465.00), pull quote,
  routing section, FAQ, comparison table
- the bootcamp card carries no term or date; the "ERP Automation Quick Wins" free
  offer is gone entirely (no card, no 1-hour format, no /free-webinar link)
- JSON-LD ItemList; Plausible snippet; FAQ markings

SEO: canonical to the slash URL, OG tags, the bootcamp's font/style.css loading
pattern, sitemap.xml (+2 urls, lastmod 2026-10-28, bootcamp lastmod bumped for the
two links added there), llms.txt (+2 lines). Cross-linked both ways and both to the
bootcamp; the bootcamp page gains the inbound links.

English only. No DE/ES twins yet - translator follow-up.

Checks: verify-html.py 0 problems, check-links.py clean, check-links-2026-10-28.py
56 PASS / 0 FAIL, verify-plausible-events 71 PASS / 0 FAIL, JSON-LD parses.
2026-10-28 22:26:35 +00:00
oliver 0cd0fa1af1 feat(analytics): Plausible snippet on every page, FAQ marked on the bootcamp
The snippet was on 10 of 40 pages, so the Trial / FAQ / Buy / Custom Quote /
search posts / Project Plan goals were inert everywhere else. It now sits
verbatim, in the same <head> position as index.html, on all 39 visitor-facing
pages. email/trial-confirmation.html is deliberately left out (email template).

FAQ: the five <details class="bc-faq"> <summary> elements on the bootcamp page
and its DE/ES twins now carry plausible-event-name=FAQ, and the 15
.faq-question buttons on de/es/support.html get the marking they were believed
to already have. No goal renamed: one FAQ goal across all languages.

No markup, copy or behaviour change, and no third-party request beyond the
snippet itself. verify-html.py PROBLEMS 0; check-links.py OK; event checker
59 PASS / 0 FAIL; impeccable detector +0/-0 findings on the changed files.
2026-10-28 21:50:53 +00:00
oliver ea97e65416 feat(blog): publish "How to Install Odoo Modules Using Git"
New post at blog/posts/how-to-install-odoo-modules-using-git.html
(2026-10-28, area "deep dive"), body pasted verbatim from the boss's
supplied block (7 h2, two figures in place). Chrome copied from the
newest post (odoo-community-is-going-online-on-odoo4projects.html:
main.blog-post / span.badge / div.post-meta / img.post-image /
div.post-body / a.back-link), style block trimmed to the rules this
page uses plus the ol/figure/figcaption rules its body needs.

Additive wiring: og:image + twitter:card, post-image after post-meta
(alt = h1), BlogPosting JSON-LD with dateModified.

blog/index.json gets the entry first (newest-first, key order
id,date,area,headline,teaser,link,image) by text splice - 15 -> 16
posts; sitemap.xml one new 0.6 blog url - 35 -> 36 <loc>; llms.txt one
new line at the top of the post list.
2026-10-28 10:21:32 +00:00
oliver 972453747b Merge fix/en-faq-version-chain-parity: EN JSON-LD FAQ version-chain parity 2026-10-27 19:16:50 +00:00
oliver 141bf20c03 fix(seo): mirror the visible version chain (14 → 15 → … → 20) into the EN FAQPage JSON-LD
The visible FAQ answer used arrows while the structured-data copy spelled the
chain out with 'to', so acceptedAnswer.text was not verbatim-present on the
page. FAQ parity check now reports 8/8 on EN/DE/ES.
2026-10-27 19:16:50 +00:00
oliver b9a730942f Merge feat/i18n-localise-dir-links: localise extensionless directory links in DE/ES 2026-10-27 19:12:50 +00:00
oliver 12704a5618 fix(i18n): localise extensionless directory links in the DE/ES pages
build-i18n.py's rebase_paths() only re-pointed a root-absolute page link when it
contained ".html", so extensionless directory links stayed on the EN route even
when the language had its own copy (`/odoo-erp-automation-bootcamp/` on all four
DE and ES pages, and `/` on the DE/ES bootcamp pages). Same guard as the .html
branch: localise only when <lang>/<path>/index.html exists.

Re-applied the rebasing to the 8 already-built DE/ES pages (work/i18n/
relocalise-links.py) - a full re-transform is not safe for them because the
switcher-slot/hero rework means repo pages are not raw transform output. 18 refs
in 8 files. The DE/ES homepages were the stale case: their body links were built
before support.html/odoo-hosting-2027.html existed in that language and were
never revisited.

check-links.py now flags an EN-route page link whose language has its own copy:
0 such links on all 10 DE/ES pages after the rebuild. test-build.py 107 passed;
verify-html.py 0 problems.
2026-10-27 19:12:47 +00:00
oliver 268b2645e2 Merge feat/i18n-upgrade-de-es: publish DE + ES Community Upgrade pages 2026-10-27 19:07:29 +00:00
oliver a84ee5e983 i18n(upgrade): publish DE + ES ODOO Community Upgrade pages (/de/, /es/), sitemap + llms.txt
Copy-only mirrors of odoo-community-upgrade.html built by translator against the
post-R1-R5 English (EN af27098a, commit 2fe0c31), rendered through work/i18n/build-i18n.py:
<html lang>, canonical, 4-way hreflang cluster (en-US/de/es/x-default), og:url,
/static/lang.js and 15 rebased refs. No EN page change.

- sitemap.xml: 33 -> 35 <loc>, both new pages at priority 0.9
- llms.txt ## Languages: DE + ES lists now name /<lang>/odoo-community-upgrade.html
- checks: check-links.py 0 broken, verify-html.py 0 problems (tag balance, JSON-LD,
  sitemap XML), JSON-LD FAQPage answers verbatim in the visible FAQ 8/8 per page
2026-10-27 19:07:29 +00:00
oliver 68c26e9725 Merge feat/icp-upgrade-changes: ICP review R1-R5 on the Community Upgrade page 2026-10-27 19:03:06 +00:00
oliver 2fe0c31e2b copy(upgrade): apply the 5 ICP-required changes to /odoo-community-upgrade.html
Retrospective ICP 1 review (kanban t_03b62410) found the EN page made a
non-technical owner-operator hesitate: the offer sat behind four blocks of
shell commands, the hero ended on "a developer", one hero line carried an
untraced claim, there was no route to a number, the FAQ printed the
OpenUpgrade data-loss warning against our own fresh-database service, and
the "restaurant meal" simile was unitless.

R1 move "The ODOO4projects way" above the process and the commands; swap the
   two band classes so the page still alternates; keep the offer's code cards
   legible on the dark band; reword the §5 intro and §6 opening sentence.
R2 hero subhead reworded, dropping the untraced "costs you your history".
R3 "See the plans" route added inside §6, with the honest "not priced on that
   page" clause. No price, no plan hero, no Offer node.
R4 FAQ "What happens to my history…" answer rewritten (JSON-LD acceptedAnswer
   kept verbatim-equal to the visible text).
R5 "restaurant meal" clause deleted.

Band-aware text colours added for the elements the class swap re-parented
(process list on light, technical section and its notes on dark, the §6 link).
No other content changed: H1, CTAs, code blocks (all 4 byte-identical),
Sweat Equity, the 8 FAQs and the JSON-LD shape are untouched.
2026-10-27 19:03:06 +00:00
oliver 3c602d97be fix(seo): legal.html canonical, host-case normalisation, BlogPosting x15, blog body domain typo
Four follow-up defects found beyond the 2026-10-27 SEO audit (no copy changes):

1. legal.html canonical was https://ODOO4projects.com/legal — uppercase host AND a
   path that 404s. Now https://odoo4projects.com/legal.html. The file's og:url keeps
   its path /legal but its host is lowercased (path fix awaiting a decision).
2. The no-"4" domain typo in reader-visible <pre><code> body text of
   blog/posts/{guide-migrate-enterprise,speed-run-deploy,my-first-post}.html:
   odooprojects.com -> odoo4projects.com. Domain string only, no other wording.
3. Lowercase host in every machine-read value: the robots.txt Sitemap line, the
   homepage + de/ + es/ Organization JSON-LD url / contactPoint.url / offers[].url,
   legal.html og:url, and the four absolute self-URL hrefs in blog posts,
   odoo/support.html and email/trial-confirmation.html. Display text untouched
   (support@ODOO4projects.com stays as written).
4. One BlogPosting per blog post (15), every value taken from the page itself:
   headline = its <h1>, datePublished = its visible post-meta date, url = its own
   canonical, author/publisher = the Organization the site already publishes,
   image = its og:image where one exists (omitted on the 10 posts that have none).

Empire ">950.00", FAQPage on support.html, the blog-chrome change and the bootcamp
date conflict are untouched — decisions pending with the user.
2026-10-27 18:54:28 +00:00
oliver 0715b59c34 feat(site): publish /australia.html — managed Odoo hosting in Australia (Sydney)
New flat landing page for Australian buyers, built from the approved Phase 2
copy with the five buyer-lens changes (R1-R5) applied. English only, no hreflang.

- australia.html: hero, five sections, four-plan pricing table (On the Rise
  heroed), 7-question FAQ, final CTA band; house CI (midnight/brass/cream,
  Marcellus + Inter), page-scoped CSS only.
- Buy CTAs are native POST forms to the live checkout with Australia (Sydney)
  pre-selected (basket product_id 4, verified against the homepage card).
- images/city-sydney.webp: city-sydney.jpg resized 6720x2240 -> 1920x640,
  9.8 MB -> 131 KB.
- index.html: the Sydney server card now links to the new page.
- sitemap.xml + llms.txt: page registered.

Evidence: verify-html.py PROBLEMS 0, verify-australia-page.py PROBLEMS 0,
JSON-LD parses, impeccable detect run (findings recorded).
2026-10-27 18:21:31 +00:00
oliver 0195038bd7 Update the ODOO Community blog post to the live copy
The post carried the planned/September copy ("scheduled to go online on the
06.10.2026"). Body replaced verbatim with the supplied live copy (1379 bytes,
2 h2, 221 words), post-meta -> October 27, 2026 · News, meta/og description
refreshed, title/canonical/chrome/og:image unchanged.

- blog/index.json: the existing entry moved to first, date 2026-10-27,
  teaser = first 120 chars of the new first paragraph (text splice).
- sitemap.xml: one new <url> as the first 0.6 blog entry (24 -> 25 <loc>).
- work/verify-html.py: page added to FILES (in webmaster/work, not in repo).
2026-10-27 09:03:49 +00:00
oliver 3e913d68cc Remove the trial MCP endpoint line from /odooityourself.html
The user reversed the earlier 'publish it' decision: the trial endpoint
paragraph (and its now-dead .ai-endpoint CSS rules) come off the AI
section. The 30-day trial line in 'Some other information' stays.

- HTML: <p class="ai-endpoint"> removed (was the AI section's last para)
- CSS: .ai-endpoint, .ai-endpoint a, .ai-endpoint a:focus-visible deleted
  (the focus-visible selector dropped from its group; group otherwise intact)
- grep ai-endpoint 0, mcp/trial 0, competitor grep 0
- verify-html.py PROBLEMS: 0; impeccable detect 10 (no new finding)
2026-10-26 19:03:58 +00:00
oliver 4da2f1c435 Remove the hero CTA from /odooityourself.html
The user asked to drop the 'Start a free trial' button from the hero.
The hero now ends with the supporting paragraph; the now-dead
.andrew-actions rule (its only consumer) goes with it. The 30-day trial
line in 'Some other information' is untouched.

Diff: 8 deletions, one file. verify-html.py PROBLEMS: 0; competitor
grep 0; impeccable detect 11 -> 10 (the removed finding was the CTA
button's low-contrast), no new findings.
2026-10-26 18:59:38 +00:00
oliver 6658f3e0a7 Move the Andrew briefing page to /odooityourself.html
git mv for-andrew/index.html odooityourself.html (history kept) and drop the
now-empty for-andrew/ directory, so the page serves at the flat root URL
https://odoo4projects.com/odooityourself.html with no directory redirect.

Update every reference to the old path: canonical, og:url and the WebPage
JSON-LD url in the page; the sitemap.xml <loc> (replaced, lastmod 2026-10-25,
still 24 entries); and the llms.txt key-page line. Copy, CSS, assets and all
other pages are untouched.

/for-andrew/ was never announced or indexed, so it is deliberately left as a
404 — no redirect added.
2026-10-26 18:40:56 +00:00
oliver 6f4a6a46b6 Landing page: partner briefing for Andrew at /for-andrew/
Six-section briefing page (hero vision, 2x3 feature grid, AI/MCP section
with art-director's CI SVG + mobile variant, management console with the
real screenshot, pricing with Empire quoted and no number, some other
information with the demo checklist). Zero competitor mentions.

Reuses the existing bootcamp hero assets; adds /images/andrew/ SVGs,
sitemap + llms.txt entries.
2026-10-26 18:36:34 +00:00
oliver 66ed209632 Footer "Useful Links": four items on the six DE/ES pages (DE/ES follow-up to 31c02b1)
The translated pages now carry the same four footer items as the three English pages:
ODOO Bootcamp -> /odoo-erp-automation-bootcamp/, ODOO Hosting in 2027 (DE) / ODOO Hosting en
2027 (ES), Support/Soporte, Rechtliches/Aviso legal. Deleted: Startseite/Inicio,
Datenschutz/Privacidad, AGB/Terminos, Kontakt/Contactenos.

Rebuilt with work/i18n/build-i18n.py from the translator's six files (work/i18n/I18N-BUILD-PLAN.md
section 5), then: place-hero-slot.py for de|es/index.html, place-slot.py for the two 2027 pages,
insert-hero-i18n.py for the two bootcamp pages (the hero CSS is language-neutral chrome held
outside the translated source). Nothing else changed: git diff 31c02b1 over these six files is
the footer list and nothing else - bootcamp hero, three buy forms (product_id 12), 465.00,
selector and hreflang clusters untouched.

Checked: verify-html.py PROBLEMS: 0; node --check static/lang.js OK; verify-footer-useful-links-de-es.py
PROBLEMS: 0; test-build.py 88/88; test-lang.js 31/31; check-links.py BROKEN/MISPLACED: 0;
impeccable detector identical finding set on all six pages (0 changed lines).
2026-10-26 15:55:12 +00:00
oliver 31c02b1a06 Footer "Useful Links": Bootcamp + ODOO Hosting in 2027, drop the four
The list becomes the same four items in all three English pages:
ODOO Bootcamp -> /odoo-erp-automation-bootcamp/ (new, first),
ODOO Hosting in 2027 -> the existing comparison page (renamed from
"Odoo hosting 2027", added to the homepage which lacked it),
Support, Legal. Home / Privacy / Terms / Contact us removed.

Content-only edit inside the existing <ul>; each page keeps its own
href style. No CSS, no markup pattern change, no other footer column
touched. de/ and es/ untouched (translator owns those in parallel).

Checks: verify-html.py PROBLEMS 0; work/verify-footer-useful-links.py
PROBLEMS 0; impeccable detect finding set identical to HEAD (87
anti-patterns / 100 advisories, all pre-existing); browser check at
1280px and 375px on all three pages: 4 items, no overlap, no
horizontal overflow.
2026-10-26 15:47:14 +00:00
oliver 0bc4dc05d7 Bootcamp hero: two-zone scrim so the photo actually reads (EN/DE/ES)
The uniform .72 -> .55 scrim composited the whole hero band to luma ~37 and the
right zone to ~35, against a flat midnight of 25.4: a dark photo made darker.
The scrim is now two zones on the same photo:

  .78  0%-88%   (copy zone: kicker, H1, value line, the four facts, the CTA)
  ramp 88%-94%
  .25  94%-100% (the lit skyline, no copy over it)

.78 is the smallest flat alpha that holds every text block over its floor
(body 4.5:1, large 3.0:1) at 1920/1440/1024/390 in EN, DE and ES - measured on
the rendered page, not modelled. 88% is where the ramp has to start: the longest
translated fact line (DE, 1024px) reaches 89.3% of the hero.

Measured before -> after (full-range mean luma of the rendered band):
  whole band     37.3 / 36.8 / 37.6 / 37.3  ->  33.8 / 33.6 / 34.1 / 34.0
  right 88-100%  34.8 / 35.9 / 35.5 / 38.4  ->  38.7 / 40.2 / 39.4 / 43.4
  plateau 94-100%                          ->  41.4 / 44.2 / 42.7 / 46.9
  (= 1.63x-1.91x the flat-midnight 25.4, was 1.37x-1.51x)
Worst text block: 4.87:1 (was 3.13:1). No copy, buy form, JSON-LD, selector,
hreflang or price touched: de/ and es/ differ ONLY by this inserted hero block.
2026-10-25 11:39:40 +00:00
oliver 718059c7e1 Bootcamp hero: London night aerial behind the header copy
The user asked for a photo in the header of /odoo-erp-automation-bootcamp/.
Adds our own London night aerial (art-director's chosen cut, measured) as the
page-scoped .bc-hero background, under a midnight gradient scrim
(rgba(13,27,46,.72) -> .55, inside CI §5's band) and over the --midnight base.

- desktop: bootcamp-hero-desktop-1920.webp, cover, background-position 50% 25%
- <=640px: bootcamp-hero-mobile-900.webp, background-position 50% 50%
- the global .hero::after 50% wash is switched off on this page only, so the
  scrim above is the one that was measured

No copy, buy form, JSON-LD, language selector or hreflang change. One CSS block,
two images, nothing else. verify-html.py PROBLEMS: 0; impeccable detect finding
set identical to HEAD; check-links 0. Worst p05 over rendered type 5.64:1.
2026-10-25 10:42:46 +00:00
oliver 36c629852f Bootcamp DE/ES: instructor reads 'Oliver - The OC Guy - Arnold' (+ alternateName)
Rebuilt de|es/odoo-erp-automation-bootcamp/index.html from the translator's
updated files with work/i18n/build-i18n.py (same recipe as 89bb7b7: lang,
canonical, the four hreflang links, og:url, the top-bar selector kept as-is).

- 2 occurrences per file: the facts-list <dd> and the "Your instructor"
  <strong> now read "Oliver - The OC Guy - Arnold, Technical Lead bei/de
  ODOO4projects" (the user's alter ego, typed hyphen form).
- Both JSON-LD instructor Person nodes gain alternateName "The OC Guy"
  (the translator mirrored the EN page e5e4f5b; name stays Oliver Arnold).
- Buy forms untouched: three POST forms, product_id 12, clear=1, price 465.00
  in five places per page.
- git diff --stat e5e4f5b = these two files only (+10/-6).
2026-10-25 10:23:20 +00:00
oliver e5e4f5b016 Bootcamp: instructor reads 'Oliver - The OC Guy - Arnold' (facts list + section lead)
The user's instruction: use 'Oliver - The OC Guy - Arnold' (his alter ego
'The OC Guy'). Rendered with the typed hyphen form in the two places the name
is shown - the facts-list <dd> and the 'Your instructor' <strong>. Bio
paragraphs, <title>, meta description and FAQ text untouched.

JSON-LD: both Course/CourseInstance instructor Person nodes keep
name 'Oliver Arnold' (legal name) and gain alternateName 'The OC Guy'.
2026-10-25 10:16:24 +00:00
oliver 89bb7b7cba i18n: publish the bootcamp page in DE + ES, cluster the EN page, price 465.00
- add de|es/odoo-erp-automation-bootcamp/index.html (build-i18n.py from the
  translator's files; canonical + hreflang cluster + top-bar selector)
- EN bootcamp page gains the four hreflang alternates (was asymmetric)
- price 790 -> 465.00 across all three pages (JSON-LD offers.price, the three
  buy-button labels, the bc-price sentence); the three buy forms stay
  byte-identical apart from the label language
- sitemap.xml: +/de/ and /es/odoo-erp-automation-bootcamp/; llms.txt: Languages
  section names the new pages
2026-10-24 22:38:21 +00:00
oliver ca9a5b47cf Bootcamp page: instructor dd carries the full title (Oliver Arnold, Technical Lead at ODOO4projects) 2026-10-24 22:33:09 +00:00
oliver 7784a46b7d Bootcamp page: instructor dd says 'Oliver Arnold' (drop ', sole instructor') 2026-10-24 22:30:20 +00:00
oliver 24e542f4ab Bootcamp page: CTAs say 'Buy for 790 USD' and post the basket natively
The three CTAs (hero, mid-page, §7) were <a class="btn-buy"> that only worked
through JavaScript. They are now native <form method="post" target="_blank">
elements posting basket=[{"product_id":12,"qty":1}] + clear=1 to
https://20.odoo4projects.com/shop/post_basket, so the buy works with JavaScript
disabled; the button keeps the brass styling and the same size classes.

static/buy.js no longer builds a form on click. It is now pure progressive
enhancement: a capture-phase submit listener appends the utm_source/medium/
campaign hidden inputs from the cookies and lets the native submit proceed.

One page-scoped declaration keeps the button height at 55px: a <button> takes
line-height:normal from the UA font shorthand where the <a>s inherited the body
line-height (measured 49.19px vs 54.78px without it).
2026-10-24 22:26:40 +00:00
oliver f0c6284bda i18n DE: republish odoo-hosting-2027.html and support.html with the trimmed em-dashes
Rebuild the two German phase-2 pages from translator/out/de/ with the standard
build recipe (lang, canonical, four hreflang links, top-bar language selector):
em-dashes cut in the German copy (odoo-hosting-2027 30 -> 5 body em-dashes,
support 8 -> 6 body) so the DE pages no longer exceed the EN source. Punctuation
only, no re-translation. ES and EN pages unchanged.

impeccable detect: finding profile unchanged except the [em-dash-overuse]
advisory on de/odoo-hosting-2027.html, which is resolved.
2026-10-24 22:08:49 +00:00
oliver 45a3cc5398 Bootcamp page: Reserve your seat now buys the bootcamp (product_id 12)
The three Reserve-your-seat CTAs posted to /support.html#contact. They now
run the same checkout path as the main page's Buy Now: a new page-local
static/buy.js mirrors script.js buyNow() (POST basket to
20.odoo4projects.com/shop/post_basket, clear=1, UTM cookies appended) and
binds .btn-buy via one delegated click handler. CTAs become
.btn-buy[data-id=12]; label unchanged. script.js and the homepage untouched.

The Price-and-booking section keeps a second, smaller link to
/support.html#contact so readers who have questions still have a fallback.
2026-10-24 22:03:38 +00:00
oliver b69e4ceaed i18n phase 2: publish DE + ES for odoo-hosting-2027.html and support.html
Four new pages, built from the verified translator output with work/i18n/build-i18n.py,
plus the same hreflang cluster and top-bar language selector on the two English pages.
Same recipe as the homepage pilot (main 937dbd4 / 06beab4); nothing else touched.

- de|es/odoo-hosting-2027.html, de|es/support.html: per-language canonical, the full
  hreflang cluster (en-US, de, es, x-default -> EN), /static/lang.js, and the switcher
  slot placed in the page's own top bar (.cmp-topbar on the 2027 page, .blog-header on
  support.html) with the per-shape CSS hook from I18N-BUILD-PLAN.md §3.
- odoo-hosting-2027.html, support.html: same cluster, same selector, so the cluster is
  symmetric (asymmetric hreflang is discarded by Google). support.html's canonical and
  og:url were still on the capitalised ODOO4projects.com host; the build normalises them
  to the lowercase form the rest of the site and sitemap.xml use.
- Internal links: the build's rebase step now also localises a root-absolute page link
  (/support.html#contact in the translator's 2027 pages) once that page exists in the
  language. /de/support.html, /de/odoo-hosting-2027.html, /de/, /de/#pricing and
  /de/#trialCard are local; /legal.html stays on the EN route because the legal pages
  are not translated (lawyer review pending).
- sitemap.xml: +4 URLs, lastmod 2026-10-24, priority reused from the EN entry (2027 -> 0.9,
  support.html -> 0.6 fallback, it has no EN entry). 17 -> 21 <loc>, no duplicates.
- llms.txt: the ## Languages section now names the mirrored pages.

Checks: verify-html.py PROBLEMS: 0; node --check static/lang.js OK; test-lang.js 31/31;
test-build.py 64/64 (was 43; +21 for the four built pages and the root-absolute rule);
check-links.py on the four new pages BROKEN/MISPLACED: 0.
2026-10-24 21:56:08 +00:00
oliver 0721804aab Language selector: move it into the visible top bar on every page that loads lang.js
The EN | DE | ES switcher existed but rendered into the footer slot, so a
visitor had to scroll to the bottom of the page to find it (measured live:
y=5582 on /, y=5498 on /odoo-erp-automation-bootcamp/). The user asked for a
selector a visitor can actually see.

- index.html, de/index.html, es/index.html: the slot is now the first child of
  .hero .container, right-aligned in flow above the kicker. In flow, not a
  fixed pill, so it cannot collide with the absolute .hero-notice.
- odoo-erp-automation-bootcamp/index.html: the slot is now the last child of
  .bc-topbar .container, right of the nav links, behind a hairline brass
  divider; .bc-topbar-links gets margin-left:auto so the brand stays left.
- One [data-lang-switcher] per page; the footer slot is removed everywhere.
- Styling follows the CI: Inter 12px / .06em / uppercase codes (the existing
  .lang-switch rules), active language in --brass on these midnight surfaces,
  the other two in the surrounding text colour. CSS-only, in each page's
  inline <style>; lang.js is untouched, so its redirect behaviour is unchanged.
- The rules are recorded in work/i18n/I18N-BUILD-PLAN.md §3 for the phase-2
  pages (de|es/odoo-hosting-2027.html, de|es/support.html).
2026-10-24 21:51:08 +00:00
oliver 7b2d241330 Bootcamp page: remove the internal 'Note on the count' paragraph
The paragraph explained the 12-to-10 lesson merge — internal reasoning
about the old page, with no place on a sales page. The ten-lesson <ol>
and the section layout are unchanged.
2026-10-24 21:45:37 +00:00
oliver acae3bdbd9 Bootcamp: correct the session schedule (first 22 Jan 2026, last 26 Mar 2026, 18:00-19:00 Central Time) 2026-10-24 21:42:57 +00:00
oliver fa654dc8d7 Bootcamp page: publish the price, USD 790
The user confirmed the price (USD 790) and the term (Q1 2026, already
correct). Replaces the 'Price and booking' placeholder sentence with the
price statement and drops the TODO(olchi) comment that marked it. Adds an
Offer (price 790, USD, Paid) to the Course node so the price is
machine-readable; the FAQPage node is unchanged.
2026-10-24 21:36:52 +00:00
oliver 0f5fb95b12 Publish the Odoo Bootcamp page at /odoo-erp-automation-bootcamp/ (fixes the ranking 404)
New directory page built from the copywriter's reviewed copy (webmaster/out copy:
/root/workspace/copywriter/out/2026-10-24-bootcamp-page-copy.md), with the four
placeholders resolved: Thursdays 16:00-17:00 (UTC-3), first session Thursday
8 January 2026 (ten sessions, last 12 March 2026), no price printed (price is
confirmed on registration, offers omitted from JSON-LD), booking CTA is
/support.html#contact.

- odoo-erp-automation-bootcamp/index.html: standalone landing page in the CI
  (midnight/brass/cream, Marcellus+Inter, page-scoped CSS, non-blocking
  style.css, no third-party JS), 8 H2 sections from the copy, Course + FAQPage
  JSON-LD, footer from index.html with the language-switcher slot.
- sitemap.xml: 16 -> 17 <loc> entries (lastmod 2026-10-24, priority 0.9).
- llms.txt: one line for the bootcamp under Key pages.

Verified: verify-html.py PROBLEMS 0 (FILES extended with the new page),
node --check script.js OK, no console errors at 1280/375, no horizontal
overflow at 375.
2026-10-24 21:33:25 +00:00
oliver 06beab403d lang.js: remember the language a switcher click picked
The switcher links were plain anchors: clicking one navigated but stored nothing, so
the auto-detect on the EN homepage bounced the visitor straight back. A de-DE browser
on /de/ that clicked EN landed on / and was replaced back to /de/ — the 'an explicit
choice always wins' promise in the plan and in llms.txt was only true for ?lang=.

A click now calls remember() with the link's own hreflang, so the choice is stored in
localStorage + the o4p_lang cookie and survives the next session. Selector tests
27 -> 31 (switcher click stores EN, sets the cookie, stores DE, chosen EN survives a
new session).
2026-10-24 21:25:33 +00:00
oliver 937dbd4dbf Publish German and Spanish homepage (/de/, /es/) with hreflang cluster and language switcher
Homepage pilot of the website i18n project. Adds the translated homepage for DE and
ES, the shared selector at /static/lang.js, and the hreflang cluster on all three
language versions (EN included, or the cluster is asymmetric and ignored).

- de/index.html, es/index.html: translator output plus the i18n build (html lang,
  self-referencing canonical, hreflang cluster, lang.js tag, switcher slot in the footer).
- index.html: same cluster + lang.js tag + switcher slot; canonical and og:url
  normalised to the lowercase host.
- static/lang.js: the tested selector (client-side language choice, auto-detect on the
  EN homepage only, once per session; a stored choice or ?lang= always wins).
- sitemap.xml: /de/ and /es/ (priority 1.0, lastmod 2026-10-24).
- llms.txt: new '## Languages' section.

Two gaps in the build recipe were closed while building: a mirrored page cannot use
root-relative source paths (style.css, images/* would resolve to /de/style.css -> 404),
so the build now re-points assets at the site root and keeps page links on the EN route
until the language page exists; and og:url is now this page's own URL instead of the
EN one inherited from the source. Not built yet: support.html, odoo-hosting-2027.html,
the blog, the bootcamp page, the legal pages.
2026-10-24 21:22:13 +00:00
oliver 2c7d9a393e Add Plausible analytics snippet to odoo-hosting-2027.html <head>
Reuses the exact snippet shipped on index.html in 6bb529a, inserted
verbatim as the last thing in <head> (before </head>). Diff is this
file only; the ld+json @graph block is byte-identical.
2026-10-24 16:39:51 +00:00
oliver 6bb529a06a Add Plausible analytics snippet to homepage <head>
User-supplied, private self-hosted Plausible instance. Snippet inserted verbatim (unmodified,
byte-for-byte) as the last thing in <head> of index.html only, immediately before </head>.
No other page touched; no CSP exists on the site so no policy change needed.

Checks: verify-html.py PROBLEMS 0; node --check script.js OK; tracker script HTTP 200
application/javascript.
2026-10-24 13:29:28 +00:00
oliver 62d9d76bde Add supplied post images to two posts and to the blog overview cards
- blog/posts/odoo-19-to-20-invoice-migration-with-n8n-and-mcp.html: in-post image
  much.png + og:image
- blog/posts/track-the-oca-modules-you-actually-use.html: in-post image
  oca_module_status.png + og:image
- blog/index.json: optional "image" key on those two entries only (text splice)
- script.js: renderBlog() draws .blog-thumb only when the entry carries an image
- style.css: .blog-thumb rule
- sitemap.xml: lastmod 2026-10-24 for the invoice-migration post

Built by profile webmaster (run 20261024_094206_5c4f28, verified PROBLEMS: 0 /
node --check OK); committed by olchi after that run died on an OpenRouter 402.
2026-10-24 09:46:13 +00:00
oliver 7b9db81e82 Publish blog post: Track the OCA Modules You Actually Use — Without Refreshing GitHub Every Day 2026-10-24 08:57:30 +00:00
oliver 76e5645585 Publish blog post: This is how i updated my Invoices from Odoo 19 to Odoo 20 with n8n and much MCP 2026-10-23 09:25:02 +00:00
oliver 61a9dd96d0 feat(legal): add Video Credits block with 10 Pixabay attributions
Add a Video Credits legal-card after Image Credits and before Trademark
Notice, carrying the 10 user-supplied Pixabay video attributions verbatim
(hrefs, utm params and the intentional /de// double slash preserved).
Rows use the existing .credit-row pattern; .video-credits mirrors
.image-credits in the page's inline <style>. Links carry target=_blank
rel=noopener to match the Image Credits convention. Meta description now
lists image and video credits.
2026-10-22 19:06:55 +00:00
oliver 488419155b fix(pricing): state the same domain count per plan on the homepage
The homepage cards gave no domain count to Side Hustle or On the Rise and
gave three to Powerhouse, while the in-app plan page (odoo/upsell.html) and
the published terms.html both say one domain for Side Hustle and three for
On the Rise and Powerhouse. Cards now read 1 / 3 / 3; PRODUCT.md and
llms.txt carry the same counts so no future page has to guess.
2026-10-22 16:12:40 +00:00
oliver 55d1ffd800 chore(site): drop dead coupon code and stale product-spec facts
script.js: delete applyCoupon(). Its only caller was the coupon button deleted above,
so the function was unreachable dead code that still carried the removed 'Coupon FREE
TRIAL applied - 1 month free' promise in a publicly served file. It would also have
thrown on the two DOM ids that no longer exist.

PRODUCT.md: this file is served publicly and still advertised $19.40/mo, $36.25/mo,
$49.60/mo, the FREE TRIAL coupon, 'yearly billing saves roughly 8-10%', a 'Satisfied
or reimbursed' guarantee and 'redundant slots'. Corrected to the yearly list prices
the site publishes and to the decisions above.
2026-10-21 23:05:23 +00:00
oliver dd27e820f5 feat(legal): add Privacy Policy and Terms of Service pages
Two new root-level pages, assembled from legal.html so they inherit the existing
head, fonts, style block and .legal-* cards. The trial email's /legal/privacy and
/legal/terms links 404 on the live site and are repointed here.

Both are factual drafts built from product facts (data held, the six regions, Stripe,
cancel-anytime, backup slots) and are NOT lawyer-authored. Decision 12 marks them for
legal review; they must not be treated as final before that review.
2026-10-21 23:05:23 +00:00
oliver 93511e893d fix(site): correct prices, drop every discount claim and repair trial copy
Applies the 16 findings the user answered in projects/active/odoo-hosting-2027-landing/
decisions-2026-10-21-user.md, using the wording from
copywriter/out/site-fix-wording-2026-10-21.md.

index.html: Powerhouse 535 -> 595 in the card and in the JSON-LD Offer; delete the
three Save 8%/9%/10% badges and the empty badge div on the Empire card; replace the
'Save 15% with yearly billing' line and the coupon message text (ids kept - script.js
reads them); delete the FREE TRIAL coupon input block; qualify the checkout line as
'Card required to buy, not to start'; fix 'redundant slots' to the real rotating-slot
model; drop the 'coupon codes for startups and NGOs' promise; add Privacy and Terms to
the footer.

email/trial-confirmation.html: stop promising backups, domain mapping and SSL on the
trial (the trial has none); state what the trial is not; copyright 2024 -> 2026;
repoint Privacy/Terms from the 404 /legal/privacy and /legal/terms to the new pages.

support.html: state that custom and OCA modules install from On the Rise up and that
Side Hustle has no module installation.

odoo/upsell.html: '4 weeks free' -> '30 days free'.

blog: the backup speed-run no longer sends readers to a non-existent hosting
dashboard; my-first-post loses the 30-day refund promise and the dashboard domain
step; community-vs-enterprise-cost quotes $214/year instead of $19.40/month;
odoocommunity-agents drops 'per-seat licensing' from the body and both meta
descriptions.

sitemap.xml: add /privacy.html and /terms.html.
llms.txt: publish the Powerhouse price and list the two new pages.

Evidence: every old string verified gone and every new string present in the working
tree; 12 HTML files tag-balanced; JSON-LD and sitemap XML valid.
2026-10-21 23:05:22 +00:00
oliver e25e4c64fa a11y(landing): lift the 'not supported' / flag chips above the 11px legibility floor
The cmp-not-us and cmp-flag pills rendered at 0.62rem (9.92px), below the
11px floor for functional text. 0.69rem = 11.04px. Detector finding cleared.
2026-10-21 22:23:15 +00:00
oliver 0f7da0b68b perf(landing): load style.css non-blocking on odoo-hosting-2027
Match the pattern index.html already uses (media=print + onload swap,
noscript fallback) so the new page adds no render-blocking stylesheet.
Page-scoped critical CSS stays inline.
2026-10-21 22:22:27 +00:00
oliver db919fc8c2 feat(landing): add Odoo Hosting 2027 comparison page
New page odoo-hosting-2027.html (feature + lifetime-cost comparison tables,
Odoo Online exclusion, Enterprise growth path, JSON-LD). Links it from the
homepage pricing CTA, adds it to sitemap.xml, adds llms.txt for AI-SEO.
2026-10-21 22:20:45 +00:00
oliver a54dc22bd1 copy(footer): say "AI Agents and N8N automations" in the About-us blurb
Updates the homepage footer tagline to name AI Agents and N8N
automations explicitly. Markup-preserving: existing <strong> emphasis
on "stability" and "power" is unchanged; no structural, style or
layout changes.
2026-10-20 13:09:31 +00:00
oliver ca89d8e7b7 confirm 2026-10-17 17:10:09 -03:00
oliver 29127d4025 chat fixes 2026-10-17 10:50:45 -03:00
oliver b4e0faa62e UTM 2026-10-17 10:40:05 -03:00
oliver 575e3efece Update upsell.html 2026-10-17 09:39:08 -03:00
oliver 62f92769a1 Update upsell.html 2026-10-17 09:30:55 -03:00
oliver 3637094896 url 2026-10-16 08:42:42 -03:00
oliver 609f9d64bf new produt id 2026-10-16 08:39:01 -03:00
oliver 1ab6c47df6 Update index.html 2026-10-16 08:29:29 -03:00
oliver 04d39157b8 Buy Area 2026-10-08 17:28:26 -03:00
oliver 5cc0c06a11 Fix modal close + color 2026-10-08 16:29:57 -03:00
oliver 7245e47cac static sites for ODOO 2026-08-22 09:37:27 -03:00
oliver ad03edb0ee new images in images/hero/ 2026-08-20 06:37:51 -03:00
oliver 7e93e0f099 Update 2026-06-24 12:23:31 -03:00
oliver 634dc77983 Update index.html 2026-06-24 10:45:38 -03:00
oliver 3a623278fd h 2026-06-24 10:28:30 -03:00
oliver c9182795aa Update index.html 2026-06-24 09:17:49 -03:00
oliver a392451cc6 nice 2026-06-24 08:56:31 -03:00
oliver feaa5e6f62 update 2026-06-24 08:27:22 -03:00
oliver a24d094bf1 h 2026-06-24 07:27:14 -03:00
oliver 7631d0b462 top 2026-06-24 07:00:33 -03:00
oliver fa3694bd58 blog 2026-06-24 06:55:38 -03:00
oliver 84d8513db1 Nice 2026-06-24 05:49:03 -03:00
oliver abb5eff2a9 Update index.html 2026-06-23 18:27:45 -03:00
oliver 5755a5de4a Working 2026-06-23 18:15:16 -03:00
oliver b58468556c h 2026-06-23 14:29:43 -03:00
oliver 996414dbfe bye 2026-06-23 13:35:07 -03:00