Per discussion: the marketing homepage looked polished but the rest of
the public site (the admission form, contact us, the backend login
screen) was still bare stock Odoo, and the site nav still showed
stock Odoo's own default logo/favicon rather than Metatroncube's real
ones. This brings the same design system (Manrope + Work Sans, the
navy/indigo palette) to all three pages and wires up the two supplied
brand assets - static/img/logo.png (the wordmark, used as
website.logo, so it renders in every page's nav automatically) and
static/img/favicon.png (the cube mark, website.favicon). Loaded via a
post_init_hook (hooks.py) rather than a plain <record>: website's two
stock demo sites (website.default_website, website.website2) are both
noupdate=True, and Python is the tool that isn't gated by that the way
a <record>/<function> tag would be on an already-installed database
(see hooks.py's own docstring for the exact mechanism and its
fresh-install-only limitation).
Admissions keeps its exact form markup/field names/model untouched -
only the surrounding hero and "what happens next" strip are new, added
via position="before"/"after" around the existing <section> so the
stock s_website_form JS widget this page depends on is never touched.
Restyling contact us and the login screen surfaced a chain of real,
separate placeholder-content bugs, each found by looking at the next
page down rather than assuming the previous fix was complete:
1. website.contactus's sidebar hardcodes "My Company" and a fake US
street address - shared/DEMO_SCRIPT.md explicitly bans placeholder
content, and it had been live here the whole time. Reading
res_company fields instead means it shows whichever school is
actually active, same as the admission form's own live program list.
2. website.footer_custom - the footer on EVERY page, not just contact
us - carries the identical yourcompany.example.com / +1
555-555-5556 placeholder, plus a "Products/Services/Legal" link
list to nowhere and dead social icons. Fixing #1 alone would have
left this sitting directly underneath it on every single page.
3. website.header_text_element, the nav bar's own phone/email widget,
carries the same fake number - a fourth, separate occurrence, this
time in the header. First pass here fixed only its "phone_mail"
variant, assumed (wrongly) to be what this site's header actually
uses; the live page still showed the fake number afterward. It
turned out both nav slots (desktop, mobile) use the plain default
branch instead - caught only by re-checking the real page rather
than trusting that assumption, and fixed every variant that carries
contact info this time, not just the one guessed at.
4. Underneath all three page-level fixes: base.main_company itself
still carried stock Odoo's own demo phone (+1 555-555-5556) and
email (info@yourcompany.com) - the page-level fixes above only
surfaced this because they read real company data for the first
time; the data itself needed fixing too. Real Indian/Canadian
contact details added to both demo companies in mc_theme_demo.xml.
5. web.login_layout hardcodes its own separate "Powered by Odoo" link
- a third distinct occurrence, different from the portal sidebar
text and the web.brand_promotion badge already fixed, reached by
the very first screen anyone doing this demo sees.
Full suite (all 9 modules + web_responsive) re-verified together after
every fix in this chain: 0 failed, 0 error(s), tests up to 93.
One correction to this session's own earlier work: mc_cast_users_demo.xml
claimed <function> "isn't subject to" the noupdate/mode guard that
blocks a plain <record> on an already-installed database - false,
odoo/tools/convert.py's _tag_function has the exact same
"if self.noupdate and self.mode != 'init': return" check. What
actually fixed that earlier bug was applying the change as a one-off
manual Python snippet, not the tag choice - the same manual-application
pattern used again here for base.main_company's contact fields on the
already-running school_demo database.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CLAUDE.md's own O9 spec says branding applies to "backend, portal,
website and every QWeb report" - the website part was never actually
built. The public side of the site was still bare stock Odoo: an
empty homepage (website.homepage ships as a literal
`<div id="wrap" class="oe_structure oe_empty"/>`) and the admission
form as the only real content anywhere a visitor could land.
Per discussion: this is Metatroncube's own product marketing page, not
the fictional school's site - it stays on a fixed brand (navy/indigo,
Manrope + Work Sans, an illustrative dashboard preview panel), not the
per-company colours the admission form and portal already read from
res.company. Swapping the demo company for the O9 closing beat
re-skins the product's own screens; it must not also repaint
Metatroncube's own marketing collateral.
Real second bug found building this, not related to the homepage
content itself: rendering it surfaced a second, separate "Powered by
Odoo" badge - web.brand_promotion, called from web.frontend_layout's
shared footer - that is completely different from the one
mc_education_theme already hid on the portal sidebar (different
template, different markup, an <img> logo rather than text). This one
sits in the footer of every website AND portal page and had been live
on the admission form this whole time; nobody had reason to scroll to
the bottom of that page and look. Neutralizing the shared, reusable
template rather than website.layout specifically means every current
and future caller of web.brand_promotion is covered by one fix.
New dependencies this actually needs and the spec's one-line
"Depends: mc_education_base" missed: `website` (to inherit
website.homepage) and `web` (to inherit web.brand_promotion) - on top
of `portal`, already added for the same reason last time. Flagging
per CLAUDE.md's closing instruction rather than working around it
quietly again.
Testing note worth recording: website.homepage resolves through a
per-website "copy-on-write" view, and Odoo auto-creates a default
website (COW'd immediately) before this module even loads. Checking
that per-website combination via _get_combined_arch() inside a
--test-enable run that installs and tests everything in one
transaction can see a stale, pre-COW empty result purely from cache
timing internal to that one transaction - confirmed NOT a real
defect by checking the same thing as a fresh request against the
actual long-running server, which renders correctly every time.
Tests here check what's actually deterministic (this module's own
authored view content) plus a live HTTP round trip proving the route
itself serves successfully, rather than chase that harness artifact.
Full suite (all 9 modules + web_responsive) re-verified together:
0 failed, 0 error(s) of 85 tests.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>