TNCSC_Odoo/CommunityOS_Implementation_Plan_for_Claude_Code.md
metatroncubeswdev a848373429 feat(scaffold): Phase 0 - repo scaffold, Docker dev stack, CI guardrails
Scaffolds the CommunityOS monorepo per the implementation plan: 8
brand-neutral product modules (community_theme_base, community_membership,
event_qr_ticketing, community_school, community_classifieds,
community_benefits, community_interac, community_portal) plus the
tncsc_deployment client layer, each with an App-Store-ready manifest,
LGPL-3 license, and empty security/data/demo/tests/views scaffolding.

Adds deploy/docker-compose.yml (Odoo 19 CE + Postgres 16), CI workflow
that installs all modules with --test-enable, and scripts/check_brand_leak.py
+ check_manifests.py enforcing the no-client-identity-in-product-code and
manifest-completeness rules. Verified locally: all 9 modules install clean
on a fresh Odoo 19 database, and the brand-leak check correctly fails when
a client term is added to a product module and passes once removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 18:48:01 -04:00

37 KiB
Raw Blame History

CommunityOS — Odoo 19 Product Suite: Implementation Plan for Claude Code

A brand‑neutral, resellable set of Odoo Community modules for community / cultural organizations First deployment: Tamil Nadu Cultural Society of Canada (TNCSC) Vendor: Metatroncube Software Solutions LLP · Waterloo, Ontario Target platform: Odoo 19 Community Edition (LGPL‑3) · PostgreSQL 16 · Python 3.12

Working product name: "CommunityOS" and the module prefix community_ used throughout this document are placeholders. Before you publish anything, replace them with your real product brand and a unique vendor prefix (e.g. mtc_community_membership) so your module technical names never collide with anything on the Odoo App Store. Do a global find‑replace at the very end, not mid‑build.


0. How to use this document (read this first)

This plan is written to be executed by Claude Code + an Odoo MCP server, one session per sub‑phase. It is deliberately different from a single‑client build plan in one important way:

Everything is built twice‑over in structure, once in effort. Each capability is built as a generic, brand‑neutral module that you can sell to any community organization, and TNCSC's specific names, colours, prices, and accounts live in a separate deployment layer that carries no reusable logic — only configuration data. You do the work once; the second sale costs you almost nothing.

Each session below has:

  • Objective — what exists when the session is done.
  • Module(s) — which package you are working in.
  • Prompt for Claude Code — a copy‑paste starting instruction.
  • Deliverables — what gets committed before you move on.
  • Validation gate — how you prove it works (via the Odoo MCP) before the next session.
  • Resellability check — the product‑hygiene rules specific to that module.

Do not skip the gates, and do not skip the resellability checks — a single hardcoded client name or a single Enterprise dependency is what turns a sellable product back into a one‑off project.


1. Why this architecture (the layered model)

┌─────────────────────────────────────────────────────────────┐
│  DEPLOYMENT LAYER  (per client — data only, no logic)        │
│  tncsc_deployment:  branding, tiers & prices, chart of        │
│  accounts, email copy, website pages, user groups             │
└───────────────▲─────────────────────────────────────────────┘
                │ depends on
┌───────────────┴─────────────────────────────────────────────┐
│  PRODUCT LAYER  (brand‑neutral, resellable, LGPL‑3)          │
│  community_membership   event_qr_ticketing   community_school │
│  community_classifieds  community_benefits    community_interac│
│  community_theme_base   community_portal                      │
└───────────────▲─────────────────────────────────────────────┘
                │ depends only on
┌───────────────┴─────────────────────────────────────────────┐
│  ODOO 19 COMMUNITY CORE  (never Enterprise)                  │
│  base contacts account website website_sale event event_sale │
│  website_slides crm purchase mass_mailing portal payment      │
└─────────────────────────────────────────────────────────────┘

The rule that keeps it sellable: product‑layer modules never mention "TNCSC," never hardcode a price, a colour, an account code, or an email address. Anything client‑specific is a configuration record (in res.config.settings, a data file, or a database record the admin edits), and the TNCSC values live only in tncsc_deployment. When you land client #2, you write a new clientname_deployment and ship — you touch no product code.


2. Version decision — Odoo 19 Community Edition

Target Odoo 19 CE. Reasoning, so you can defend it to a client or a co‑founder:

  • It is the current stable release, giving the longest support runway of any released version. Odoo actively supports roughly the latest three majors, so a build on 17 is the closest to falling out of support.
  • The usual reason to stay one version back — waiting for third‑party add‑ons to be ported — does not apply to you, because you are building your own modules and depend only on Odoo core.
  • The payment framework, website asset pipeline, and portal all changed across 17→18→19; building on 19 means you write against the current APIs once instead of writing against 17 and re‑porting.
  • Trade‑off to accept: public tutorials and StackOverflow answers lag the release. Mitigation: point Claude Code at the actual v19 source (https://github.com/odoo/odoo/tree/19.0) whenever it is unsure of an API, rather than trusting older examples.

Forward‑portability rule: avoid private/underscore‑prefixed core methods where a public API exists, keep custom JS in OWL components (not legacy widgets), and keep every module's depends list minimal. This makes the eventual jump to Odoo 20 a small, well‑scoped task rather than a rewrite.


3. Licensing & resellability guardrails (non‑negotiable)

These are the rules that keep every module something you can legally brand and sell.

  1. License each product module LGPL-3 in its manifest. LGPL lets your customers install and use it freely, lets you sell it, and (unlike a proprietary license) is fully compatible with building on Odoo Community. If you later want a paid‑but‑closed module for the App Store, use OPL-1 (Odoo Proprietary License) — but only for modules that depend on Community‑only code.
  2. Never depend on an Odoo Enterprise module. The moment a depends entry points at an Enterprise app, you inherit Enterprise licensing constraints and lose the right to sell freely. The allowed dependency allowlist is in the Appendix — do not add to it without checking the license.
  3. No client identity in product code. No "TNCSC", no client email, no client colour hex, no client price, no client account code anywhere under a community_* module. Enforce this with a grep in CI (see Phase 0).
  4. Configuration over hardcoding. Tiers, fees, branding, accounts, and copy are records/settings, seeded by the deployment layer — never literals in Python.
  5. App‑Store‑ready manifests. Every product module carries author, website, license, category, version (semantic, 19.0.1.0.0), summary, description, price, currency, and an images/ banner from day one. Filling these at the end is a scramble; fill them as you go.
  6. Each module is independently installable and independently sellable. No product module may hard‑ depend on another product module unless that dependency is itself a saleable bundle you intend. Prefer optional glue (e.g. community_school enhances event_qr_ticketing if present, via a soft check, rather than hard‑depending on it).
  7. Tests ship with the product. Each module has an Odoo tests/ package with at least smoke tests (install, create core record, run the key compute). A product without tests is not a product.
  8. Demo data ≠ config data. Demo records go under demo/ and load only in demo mode. Real client config goes in the deployment layer. Never ship TNCSC data inside a product module's demo/.

4. Module map

Product layer (brand‑neutral, sellable)

Module Purpose Core deps (CE only)
community_theme_base Configurable brand tokens (colours, logo, fonts) via settings; base website layout hooks website
community_membership Member profiles, configurable tiers, family grouping, renewal automation, portal, QR membership card contacts, account, portal, website
event_qr_ticketing Extends CE events: QR ticket per registration, check‑in/verification screen, scan endpoint event, event_sale, website_event
community_school Programs/levels, classes & schedules, students, enrollment, attendance, LMS link, parent portal contacts, portal, website_slides, account
community_classifieds Member‑gated classifieds board with moderation queue and auto‑expiry website, portal
community_benefits Benefit centres / partner vendors offering member benefits; per‑tier benefit entitlements; redemption log contacts, community_membership
community_interac Interac e‑Transfer semi‑automated payment provider (Canada) payment, account
community_portal Unified member portal dashboard aggregating the above (soft‑detects installed modules) portal

Deployment layer (per client — data only)

Module Purpose
tncsc_deployment Depends on the product modules TNCSC uses; seeds TNCSC branding, tiers/prices, chart of accounts, email copy (EN + Tamil), website pages, user groups, and demo/import glue. No models, no business logic.

5. Repo & naming conventions

communityos/                          # one git repo, all modules
├── .github/workflows/ci.yml          # lint + brand‑leak grep + module install test
├── addons/
│   ├── community_theme_base/
│   ├── community_membership/
│   ├── event_qr_ticketing/
│   ├── community_school/
│   ├── community_classifieds/
│   ├── community_benefits/
│   ├── community_interac/
│   ├── community_portal/
│   └── tncsc_deployment/
├── deploy/
│   ├── docker-compose.yml            # Odoo 19 + Postgres 16 for local dev
│   ├── odoo.conf
│   └── nginx-communityos.conf
├── scripts/
│   ├── migrate_members.py
│   ├── migrate_students.py
│   └── migrate_classroom.py
├── .claude/mcp_servers.json          # Odoo MCP config
├── LICENSE                           # LGPL‑3 text
└── README.md

Conventions to give Claude Code once, at the top of every session:

  • Odoo 19.0; Python 3.12; models use type‑annotated fields where practical.
  • Every model _name uses the module's own namespace (community.membership.tier, not tncsc.*).
  • Every module: __manifest__.py, models/, views/, security/ir.model.access.csv, data/, demo/, tests/, README.rst, static/description/index.html.
  • Commit per module‑deliverable: feat(community_membership): tier model + renewal cron.

Phase 0 — Dev environment, repo, and CI guardrails

Effort: ~3 hrs · Modules: repo scaffolding

Objective

A running Odoo 19 dev stack in Docker, an empty but fully‑scaffolded monorepo, and a CI check that fails the build if a product module leaks a client name or an Enterprise dependency.

Prompt for Claude Code — Session 0‑A (stack + scaffold)

We are building "CommunityOS", a suite of brand‑neutral Odoo 19 Community modules.
Target: Odoo 19.0 CE, Postgres 16, Python 3.12.

Tasks:
1. Create deploy/docker-compose.yml running Odoo 19 CE + Postgres 16, mounting ./addons
   as a custom addons path, with a dev odoo.conf (addons_path, admin_passwd, dev=reload).
2. Create the repo structure exactly as in section 5 of the plan (empty module folders with
   placeholder __init__.py and __manifest__.py where noted).
3. For EACH product module, generate a complete __manifest__.py with App‑Store‑ready metadata:
   name, version '19.0.1.0.0', category, summary, author 'Metatroncube', website, license 'LGPL-3',
   depends (from the module map), and empty data/assets lists.
4. Add LICENSE (LGPL‑3) and a README.md describing the suite and the layered architecture.
Do not write business logic yet. Confirm `docker compose up` starts Odoo and the modules list appears.

Prompt for Claude Code — Session 0‑B (CI guardrails)

Add .github/workflows/ci.yml that, on every push:
1. Spins up Odoo 19 + Postgres 16 and installs every module in addons/ with --test-enable, failing on
   any install or test error.
2. Runs a "brand leak" check: grep the community_* modules (code, data, views) for a banned‑words list
   (tncsc, tamil nadu, and any client email/domain). If found in a product module, fail the build.
   The deployment modules (*_deployment) are exempt.
3. Runs flake8/pylint‑odoo and validates each manifest has license, version, author, summary.
Write the workflow and a scripts/check_brand_leak.py it calls.

Deliverables

docker compose up serves Odoo 19; all modules appear in Apps; CI is green on the empty scaffold.

Validation gate

  • Odoo 19 login loads locally.
  • Every module installs clean (empty).
  • CI brand‑leak check fails when you temporarily add the word "TNCSC" to a product module, and passes when it's only in tncsc_deployment. (Prove the guardrail actually works.)

Phase 1 — community_membership (the foundation)

Effort: ~8–10 hrs

Objective

A fully generic membership engine: configurable tiers, family grouping, member IDs, renewal automation, self‑service portal, and a QR membership card — with zero client specifics in code.

Prompt for Claude Code — Session 1‑A (models & configuration)

Build the community_membership module for Odoo 19 CE. Brand‑neutral — no client names anywhere.

Models:
- community.membership.tier: name, code, price (Monetary), period (Selection: annual, one_time,
  monthly), member_state_logic, sequence, product_id (auto‑created membership product), active.
  Tiers are DATA the admin manages — never hardcode tier names or prices.
- Extend res.partner with membership fields, all namespaced:
  membership_member_id (Char, auto‑format configurable via settings, default 'MEM-{year}-{seq}'),
  membership_tier_id (M2o community.membership.tier), membership_state (Selection: none, invoiced,
  active, renewal_due, expired), membership_start, membership_expiry,
  family_head_id (M2o res.partner), is_volunteer (Bool), volunteer_hours (Float).
- community.membership.settings via res.config.settings: organization display name, member‑ID format
  string, renewal reminder offsets (days), portal feature toggles.

Requirements:
- Member‑ID auto‑generates on transition to 'active' using the configurable format string (ir.sequence).
- ir.model.access.csv + record rules (a member reads only their own partner in portal).
- Basic list/form/kanban views + a Membership settings page.
- tests/: install, create tier, create member, assert member_id generated on activation.
Write complete, working code following Odoo 19 conventions.

Prompt for Claude Code — Session 1‑B (renewal automation)

Add to community_membership:
- ir.cron (daily) that flags members to 'renewal_due' at the configured offsets and 'expired' on expiry.
- Configurable email templates (reference by XML id, content overridable by the deployment layer):
  renewal_upcoming, renewal_due, membership_expired. Templates use ${object...} placeholders only —
  no hardcoded org name; pull org name from settings.
- Auto‑create a draft renewal invoice for the member's tier product on expiry (state=draft for review).
- tests/: set expiry within an offset, run cron, assert state change + mail.mail queued + draft invoice.

Prompt for Claude Code — Session 1‑C (QR membership card + portal)

Add to community_membership:
1. A QWeb PDF report "Membership Card" (85mm×54mm landscape): org logo (from theme settings), member
   name, member ID (monospace), tier badge, valid‑until, and a QR code encoding a verification URL
   '/membership/verify/<member_id>'. Generate the QR with the python 'qrcode' library, embedded base64.
2. A public verification controller GET /membership/verify/<member_id> that returns a minimal page
   showing valid / expired / not‑found (no personal data beyond name + status).
3. Portal: /my/membership showing status, tier, expiry, a Renew button (opens the draft invoice),
   and a "Download card" button. Use Odoo 19 portal mixins; no custom login.
Write report, controller, portal templates, and tests for the verify endpoint (valid + expired + unknown).

Deliverables

Installable membership module: tiers as data, auto member IDs, renewal crons + emails, draft renewal invoices, QR card PDF, portal page, public verify endpoint, passing tests.

Validation gate (via Odoo MCP)

  • Create 3 tiers and 3 members; confirm member IDs generate on activation.
  • Force one member's expiry near an offset; run the cron; confirm state + queued email + draft invoice.
  • Render a card PDF; scan the QR; confirm the verify page shows the right status.

Resellability check

  • Grep: no client name, email, colour, price literal, or account code in the module.
  • Org name, member‑ID format, reminder offsets all come from settings.
  • Manifest App‑Store‑complete; tests pass under --test-enable.

Phase 2 — event_qr_ticketing

Effort: ~6–8 hrs

Objective

Extend Odoo 19 CE events with a scannable QR ticket per registration and a staff check‑in / verification screen — self‑contained and sellable on its own.

Prompt for Claude Code — Session 2‑A (ticket + QR)

Build event_qr_ticketing (depends: event, event_sale, website_event). Brand‑neutral.
Extend event.registration:
- ticket_ref (Char, unique, auto e.g. 'TIX-{event}-{seq}'), ticket_qr (Binary, computed QR PNG),
  checked_in (Bool), check_in_time (Datetime), check_in_user_id (M2o res.users).
QR encodes a signed token (event_id + registration_id + ticket_ref) — use a per‑db secret so tickets
can't be forged. Add the QR + ticket ref to the CE registration confirmation email as an attachment.
Add a "Ticket" QWeb PDF. tests/: create registration, assert ticket_ref + qr + valid token.

Prompt for Claude Code — Session 2‑B (check‑in / verification)

Add to event_qr_ticketing a staff check‑in flow:
- Backend action + a mobile‑friendly portal/website page /event/checkin (group: event user) that
  accepts a scanned token (camera via html5 QR lib from CDN, or manual ticket_ref entry) and returns:
  valid + not‑yet‑checked‑in (mark checked_in, stamp time/user), already‑checked‑in (warn), or invalid.
- Guard against double check‑in and forged/edited tokens (verify the signature).
- A simple per‑event dashboard: registered vs checked‑in count.
Write controller, OWL/JS for the scanner page, and tests for valid / duplicate / forged token.

Deliverables + gate

Installable ticketing module; email carries QR; /event/checkin validates, prevents double/forged check‑ins; tests pass. MCP gate: register an attendee, scan the token → checked in; scan again → "already checked in"; tamper with the token → "invalid".

Resellability check

  • Works with a stock CE event, no other product module required.
  • Signing secret is per‑database (not a constant in code). No client specifics. Manifest complete.

Phase 3 — community_school

Effort: ~10–12 hrs

Objective

A generic education module (programs, levels, classes, students, enrollment, attendance, LMS link, parent portal) suitable for any weekend/community/language school — not just Tamil school.

Prompt for Claude Code — Session 3‑A (core models)

Build community_school (depends: contacts, portal, website_slides, account). Brand‑neutral —
"levels" and "grades" are configurable data, never hardcoded to any curriculum.
Models:
- community.school.term: name, start_date, end_date, registration_open, registration_deadline, state.
- community.school.level: name, code, sequence, min_age, max_age (configurable — e.g. Beginner..Advanced
  OR Grade 1..12; the admin defines them).
- community.school.class: name (computed level+term), level_id, term_id, teacher_id (res.partner with
  is_teacher), max_students, enrolled_count (computed), weekday, start_time, end_time, location,
  slide_channel_id (website_slides course), state.
- community.school.student: partner_id (child), parent_partner_id, date_of_birth, age (computed),
  proficiency (Selection, configurable), grade_ref (Char/Selection configurable), health_notes,
  emergency_contact_name/phone, enrollment_ids.
- community.school.enrollment: student_id, class_id, term_id (related), enrollment_date, state
  (waitlist/enrolled/completed/withdrawn), payment_state, invoice_id, attendance_rate (computed).
- community.school.attendance: enrollment_id, class_id, date, state (present/absent/late/excused), notes.
Add is_teacher Bool to res.partner. Full security + basic views + tests (create term→level→class→student
→enroll, assert enrolled_count + attendance_rate compute).

Prompt for Claude Code — Session 3‑B (teacher attendance, portal)

Add to community_school:
- Portal page /school/attendance (teacher login) listing the teacher's classes for today/this week,
  a roster with Present/Absent/Late/Excused per student, and a batch save.
- On 'absent', queue a configurable email to the parent (org name from settings, not hardcoded).
- Admin: attendance report (pivot) + an "at‑risk" flag below a configurable attendance threshold.
Write controller, QWeb, email template, and tests (batch save creates records; absence queues mail).

Prompt for Claude Code — Session 3‑C (registration + LMS)

Add to community_school:
1. A multi‑step website registration at /school/register (parent → student → class+payment) using
   session state, creating child res.partner + student + enrollment + a fee invoice. On a full class,
   set state=waitlist and notify the first waitlisted when a seat frees (hourly cron).
2. LMS glue: auto‑create a website_slides channel when a class is created; auto‑enrol the student in
   the channel when their enrollment confirms; unenrol on withdrawal.
3. A standalone scripts/migrate_classroom.py: input CSV (assignment title + Drive/YouTube URL) → create
   slide records (YouTube → embed, docs → note to re‑upload as PDF). This replaces Google Classroom.
Write controllers, templates, the LMS hooks, and the migration script with tests where feasible.

Deliverables + gate

Installable school module; parent completes 3‑step registration → invoice; teacher marks attendance from portal → absence email; slide channels auto‑create/enrol. MCP gate: run one full parent‑registration end‑to‑end and one teacher attendance batch; confirm invoice, enrollment, channel enrolment, and the absence email.

Resellability check

  • Levels/grades/proficiency are admin‑defined data, so the module fits a Grade 1–12 school or a Beginner–Advanced language school with no code change. No client names. Manifest complete.

Phase 4 — community_classifieds + community_benefits

Effort: ~7–9 hrs

Objective

Two more sellable modules: a member‑gated classifieds board, and a member‑benefits / benefit‑centres engine (your "benefit centers per membership" requirement, done generically).

Prompt for Claude Code — Session 4‑A (classifieds)

Build community_classifieds (depends: website, portal). Brand‑neutral.
Model community.classified: title, category (configurable Selection), description (Html), image_ids
(One2many, up to 3), contact_method, contact_email/phone, poster_partner_id (auto), post_date,
expiry_date (auto = post_date + configurable days), state (pending_review/published/expired/rejected),
admin_notes, view_count.
Routes: /classifieds (public list + filter/search), /classifieds/<id> (detail, increments views),
/classifieds/new (POST — requires portal login AND active membership if community_membership is
installed; soft‑detect it), /classifieds/my, /classifieds/<id>/renew.
Admin moderation queue with Publish/Reject. Crons: expire past‑date listings; 7‑day expiry warning;
notify admin on new submission. Access rules: public reads published only; members create/edit own.
Write full module + tests (post → pending; publish → visible; expiry cron archives).

Prompt for Claude Code — Session 4‑B (benefits / benefit centres)

Build community_benefits (depends: contacts, community_membership). Brand‑neutral.
Models:
- community.benefit.partner: a benefit centre / vendor (res.partner link, category, description, logo,
  locations, active). These are businesses that give members a benefit.
- community.benefit: name, benefit_partner_id, description, tier_ids (M2m community.membership.tier —
  which tiers get it), discount_type (percent/amount/perk), value, valid_from/valid_to, active.
- community.benefit.redemption: member_id, benefit_id, date, verified_by, notes — a log so a benefit
  centre can verify + record a member using a benefit (reuse the membership QR verify endpoint to
  confirm the member is active before redemption).
Portal: /my/benefits lists the benefits the member's tier entitles them to. Public directory
/benefits lists participating centres. tests/: entitlement resolves by tier; redemption logs.

Deliverables + gate

Both modules installable; classifieds gated to active members; benefits resolve by tier and a redemption can be logged against a QR‑verified member. MCP gate: post+publish a classified; entitle a tier to a benefit and log one redemption for an active member; confirm a non‑member is blocked from posting.

Resellability check

  • community_benefits soft‑degrades if community_membership is absent (or hard‑depends by design — decide and document). Categories configurable. No client specifics. Manifests complete.

Phase 5 — community_interac (optional payment provider)

Effort: ~5–7 hrs · Highest‑risk module — do it in isolation

Objective

A generic Interac e‑Transfer semi‑automated payment provider for the Odoo 19 payment framework — sellable to any Canadian org.

Prompt for Claude Code — Session 5‑A

Build community_interac (depends: payment, account) as a proper Odoo 19 payment provider.
IMPORTANT: read the Odoo 19 source for an existing provider (addons/payment_* on the 19.0 branch)
before coding, because the provider/transaction API is strict. Implement:
- A payment.provider of a new custom code; a payment.method; the required _get_specific_* hooks.
- Flow: user picks Interac at checkout → transaction state 'pending' → auto‑email configurable
  instructions (recipient e‑transfer address, amount, reference code 'REF-{tx}', deadline). Org name +
  e‑transfer address come from provider config, NOT hardcoded.
- Admin: a filtered "Pending Interac" view with a one‑click "Payment received" that sets the tx 'done'
  (which confirms the linked order/registration/invoice).
- Cron: auto‑cancel + email if not confirmed within a configurable window.
Write the provider, templates, admin action, cron, and tests (pending on select; done on confirm;
auto‑cancel after window). Verify against the v19 payment API, not older tutorials.

Deliverables + gate

Interac appears as a checkout option; instructions email fires; treasurer one‑click confirms; unconfirmed auto‑cancels. MCP gate: run a pending→confirmed cycle and a pending→auto‑cancel cycle.

Resellability check

  • Recipient address, org name, deadline, and copy are provider config, not literals. No client names. Registers cleanly without patching core payment code. Manifest complete.

Phase 6 — community_portal + community_theme_base

Effort: ~5–6 hrs

Objective

The brand‑neutral presentation layer: a configurable theme (colours/logo/fonts as settings) and a unified member portal dashboard that soft‑detects whichever product modules are installed.

Prompt for Claude Code — Session 6‑A (theme base)

Build community_theme_base (depends: website). Brand‑neutral.
Expose brand tokens via res.config.settings: primary colour, secondary colour, accent colour, logo,
heading font, body font. Inject them as CSS variables into the website + portal + PDF reports so a
deployment can rebrand with data only — no SCSS edits. Provide a clean default navbar/footer layout
that reads these tokens. No client colours in code; ship neutral defaults.

Prompt for Claude Code — Session 6‑B (unified portal)

Build community_portal (depends: portal). It renders a member dashboard at /my that aggregates cards
from whichever modules are installed, using SOFT detection (check the registry / try/except import),
so it works if only some products are installed:
- Membership card (if community_membership), Upcoming registered events + tickets (if event_qr_ticketing),
  School: child schedule/attendance (if community_school), My benefits (if community_benefits),
  My classifieds (if community_classifieds).
Write the controller with soft‑detection and the QWeb dashboard. tests/: dashboard renders with any
subset of modules installed.

Deliverables + gate

Rebranding is data‑only; the portal shows exactly the cards for installed modules. MCP gate: change theme colours in settings → site + card PDF reflect them; uninstall one product module → its portal card disappears without error.

Resellability check

  • Neutral default palette; all brand values are settings. Portal never hard‑crashes on a missing module. Manifests complete.

Phase 7 — tncsc_deployment (the client layer)

Effort: ~5–6 hrs · This is where ALL TNCSC specifics finally live

Objective

A single data‑only module that turns the generic suite into TNCSC's system: branding, tiers, prices, chart of accounts, email copy (English + Tamil), website pages, and user groups. No models, no logic.

Prompt for Claude Code — Session 7‑A

Build tncsc_deployment. It depends on the product modules TNCSC uses and contains DATA ONLY
(no Python models, no business logic — data/ XML and CSV, plus assets for branding).
Seed:
- Branding (community_theme_base settings): navy #05091E, electric blue #0EA5FF, orange #F97316; TNCSC
  logo; Inter font.
- Membership tiers/prices: Individual $50, Family $80, Student $20, Senior $30, Life $500 (CAD).
- Member‑ID format 'TNCSC-{year}-{seq}'.
- Chart of accounts + journals for a Canadian non‑profit (membership dues, event revenue, sponsorship,
  school fees, donations; deferred event revenue liability; HST codes; the bank/Stripe/AR accounts).
- Email template overrides with TNCSC voice, bilingual EN/Tamil subject+body.
- Website pages: Home, About, Tamil School, Sponsors, Contact (using the theme + dynamic blocks).
- User groups: Board Admin, Treasurer, Events Officer, School Coordinator, Teacher (portal), Classifieds
  Moderator, Member (portal), with ir.model.access + record rules.
Confirm installing ONLY tncsc_deployment (which pulls the product modules as deps) yields a fully
branded, TNCSC‑configured system. Verify no business logic crept into this module.

Deliverables + gate

Installing tncsc_deployment on a clean DB produces a complete, branded TNCSC deployment. Gate: the brand‑leak CI still passes (client data is confined to this module); a fresh DB + tncsc_deployment boots into TNCSC's configured system.


Phase 8 — TNCSC data migration

Effort: ~4–5 hrs

Objective

Import TNCSC's existing members, students, and history into the deployed system.

Prompt for Claude Code — Session 8‑A

Write idempotent migration scripts (standalone, using Odoo JSON‑RPC — not MCP) against the deployed DB:
- scripts/migrate_members.py: clean (phone/email/date normalise, dedupe by email), upsert res.partner +
  membership tier/state, output a migration report CSV (processed/created/updated/failed + reasons).
- scripts/migrate_students.py: upsert child + parent partners, community.school.student + current‑term
  enrollment where the class exists.
- scripts/migrate_opening_balances.py: one posted journal entry dated the last fiscal year‑end.
Inputs live in data/raw/ (gitignored). Each script re‑runnable safely. Include a dry‑run flag.

Deliverables + gate

Members and students imported with a report; opening balances posted. Gate: re‑running a script makes no duplicate records (idempotency proven).


Phase 9 — Packaging for resale + go‑live

Effort: ~6–8 hrs

Objective

Two outcomes at once: TNCSC goes live, and the product layer is packaged so you can sell it.

Prompt for Claude Code — Session 9‑A (productize)

Prepare the product layer for sale:
1. For each community_* module: write static/description/index.html (App‑Store listing page), a
   README.rst (features, install, configuration, screenshots), a CHANGELOG, and confirm the manifest
   price/currency/images/license are set.
2. Generate a one‑page "CommunityOS" suite overview (features + which modules are independent vs bundled).
3. Run the full test suite and the brand‑leak check across the whole repo; produce a release report.
4. Tag a release v1.0.0 and document the exact steps to install the suite on a fresh Odoo 19.

Prompt for Claude Code — Session 9‑B (TNCSC go‑live)

Production hardening + go‑live for TNCSC (deploy/ configs):
- odoo.conf: workers, proxy_mode, list_db=False, admin password; nginx TLS + gzip + static caching;
  UFW (22/80/443), fail2ban; daily pg_dump + off‑site sync; log rotation; uptime check.
- DNS cutover checklist and a post‑cutover smoke test of the 4 critical flows (membership+pay, event
  register+checkin, school register, portal login). Output as a runnable, commented script.
Also write short role guides (admin, treasurer, teacher, parent) as Markdown.

Deliverables — final gate

  • TNCSC live on production, SSL + backups verified, 4 critical flows tested by a board member.
  • Product layer: every community_* module has a listing page, README, passing tests, complete manifest, and a tagged v1.0.0 release — i.e. it is ready to list/sell independently of TNCSC.

Per‑module resellability checklist (apply to every community_* module)

  • License LGPL-3 (or OPL-1 if intentionally paid‑closed, Community deps only).
  • Manifest complete: name, version 19.0.x.y.z, author, website, category, summary, description, price, currency, images, license, depends (CE‑only).
  • No client name / email / colour / price / account literal anywhere (CI grep passes).
  • All client‑variable behaviour is settings/data, not code.
  • security/ir.model.access.csv + record rules present and correct.
  • tests/ present; passes under --test-enable.
  • demo/ data is generic and demo‑only; no real client data.
  • static/description/index.html + README.rst written.
  • Installs standalone on a clean Odoo 19 with only its declared deps.

Appendix A — Allowed dependency allowlist (Odoo 19 Community only)

base, web, mail, contacts, portal, website, website_sale, event, event_sale, website_event, website_slides, account, crm, purchase, mass_mailing, payment, payment_stripe. If a depends entry is not on this list, verify it is Community (not Enterprise) before adding it. Never depend on: sale_subscription, documents, helpdesk, planning, appointment, marketing_automation, social, voip, web_studio, or anything else Enterprise‑only.

Appendix B — Dependency graph (product layer)

community_theme_base  ─────────────┐
community_membership  ──┬──────────┤
event_qr_ticketing    ──┤          │
community_school      ──┤          ├──►  community_portal (soft‑detects all)
community_classifieds ──┤          │
community_benefits ──► community_membership
community_interac  (independent; enhances checkout wherever payment is used)
tncsc_deployment  ──►  (depends on whichever of the above TNCSC ships)

Appendix C — Session context to paste at the top of every Claude Code session

We are building CommunityOS: brand‑neutral, resellable Odoo 19 Community modules.
Repo: monorepo under addons/. Target Odoo 19.0 CE, Python 3.12, Postgres 16. Odoo MCP is connected.
RULES: (1) product modules (community_*) contain NO client names/prices/colours/accounts — those are
settings/data only; (2) depend on Community core only (see allowlist), never Enterprise; (3) every
module keeps an App‑Store‑ready manifest and a tests/ package; (4) read the Odoo 19 source when unsure
of an API instead of trusting older tutorials. Read existing module files before editing. Commit per
deliverable.

Plan version 1.0 · Target Odoo 19 CE · Metatroncube Software Solutions LLP Built for execution by Claude Code + Odoo MCP · TNCSC = first deployment of a resellable product suite.