TNCSC_Odoo/docs/TNCSC_Handbook.html
metatroncubeswdev 35e62e8c61
Some checks failed
CI / Brand-leak check (push) Has been cancelled
CI / flake8 / pylint-odoo / manifest completeness (push) Has been cancelled
CI / Install all modules with --test-enable (push) Has been cancelled
docs: add standalone HTML version of the TNCSC handbook
Same content as TNCSC_Handbook.md, styled to match the version published
as a shareable Artifact web page. Self-contained (Google Fonts is the
only external dependency) so it works opened directly in a browser or
served from any static host, without relying on the Artifact platform.
2026-08-21 19:50:36 -04:00

847 lines
37 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="A settings and day-to-day operations guide for TNCSC board members and volunteers running their CommunityOS system.">
<title>TNCSC Handbook</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Zilla+Slab:wght@400;500;600;700&family=Inter:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Mono:wght@500;600&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; }
h1, h2, h3, h4, p, ul, ol { margin: 0; }
:root {
--ink: #0c1230;
--ink-soft: #333a5c;
--muted: #5b6280;
--paper: #f4f5fb;
--surface: #ffffff;
--surface-2: #eef0fa;
--border: #dfe2f0;
--border-soft: #ebedf7;
--accent: #0d7fd6;
--accent-ink: #ffffff;
--accent-soft: #e6f2fd;
--warn: #c2550a;
--warn-soft: #fdece0;
--code-surface: #eef0fa;
--code-ink: #2a2f52;
--shadow: 0 1px 2px rgba(12, 18, 48, 0.04), 0 8px 24px -12px rgba(12, 18, 48, 0.18);
--focus: #0d7fd6;
--font-display: "Zilla Slab", Georgia, "Times New Roman", serif;
--font-body: "Inter", -apple-system, "Segoe UI", sans-serif;
--font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--ink: #e9ebfa;
--ink-soft: #c3c7e6;
--muted: #9599c0;
--paper: #0a0e24;
--surface: #11162f;
--surface-2: #171d3d;
--border: #262c4f;
--border-soft: #1b2142;
--accent: #4fb2ff;
--accent-ink: #05121f;
--accent-soft: #12233b;
--warn: #ff9d5c;
--warn-soft: #2e1c10;
--code-surface: #171d3d;
--code-ink: #cfd3f2;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 12px 28px -14px rgba(0, 0, 0, 0.55);
}
}
:root[data-theme="dark"] {
--ink: #e9ebfa;
--ink-soft: #c3c7e6;
--muted: #9599c0;
--paper: #0a0e24;
--surface: #11162f;
--surface-2: #171d3d;
--border: #262c4f;
--border-soft: #1b2142;
--accent: #4fb2ff;
--accent-ink: #05121f;
--accent-soft: #12233b;
--warn: #ff9d5c;
--warn-soft: #2e1c10;
--code-surface: #171d3d;
--code-ink: #cfd3f2;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 12px 28px -14px rgba(0, 0, 0, 0.55);
}
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--paper);
color: var(--ink);
font-family: var(--font-body);
font-size: 16.5px;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration-thickness: 1.5px; text-underline-offset: 2px; }
a:focus-visible, button:focus-visible, summary:focus-visible {
outline: 2.5px solid var(--focus);
outline-offset: 2px;
border-radius: 3px;
}
h1, h2, h3, h4 {
font-family: var(--font-display);
font-weight: 600;
color: var(--ink);
text-wrap: balance;
line-height: 1.15;
}
p { margin: 0 0 1.05em; max-width: 66ch; }
ul, ol { max-width: 66ch; padding-left: 1.35em; }
li { margin-bottom: 0.45em; }
li:last-child { margin-bottom: 0; }
li > ul, li > ol { margin-top: 0.45em; }
/* ---------- Masthead ---------- */
.masthead {
border-bottom: 1px solid var(--border);
background:
radial-gradient(1100px 420px at 12% -20%, var(--accent-soft), transparent 60%),
var(--surface);
}
.masthead-inner {
max-width: 1180px;
margin: 0 auto;
padding: 3.4rem 2rem 2.6rem;
}
.kicker {
display: inline-flex;
align-items: baseline;
gap: 0.6em;
font-family: var(--font-mono);
font-size: 0.78rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 1rem;
}
.kicker::before {
content: "";
display: inline-block;
width: 1.6em;
height: 2px;
background: var(--accent);
transform: translateY(-3px);
}
h1.title {
font-size: clamp(2.2rem, 4.4vw, 3.15rem);
margin: 0 0 0.55em;
max-width: 16ch;
}
.dek {
font-size: 1.14rem;
color: var(--ink-soft);
max-width: 56ch;
margin: 0 0 1.6rem;
}
.login-note {
display: inline-flex;
align-items: center;
gap: 0.65em;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 10px;
padding: 0.65em 1em;
font-size: 0.92rem;
color: var(--ink-soft);
max-width: 66ch;
}
.login-note b { color: var(--ink); }
/* ---------- App grid on masthead ---------- */
.app-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.6rem;
margin-top: 2.2rem;
max-width: 900px;
}
.app-chip {
border: 1px solid var(--border);
background: var(--surface);
border-radius: 10px;
padding: 0.7em 0.85em;
font-size: 0.86rem;
font-weight: 600;
color: var(--ink-soft);
text-align: center;
}
/* ---------- Layout ---------- */
.layout {
max-width: 1180px;
margin: 0 auto;
padding: 2.6rem 2rem 6rem;
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
gap: 3.2rem;
align-items: start;
}
nav.toc {
position: sticky;
top: 1.6rem;
align-self: start;
font-size: 0.89rem;
}
nav.toc .toc-label {
font-family: var(--font-mono);
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 0.9rem;
}
nav.toc ol {
list-style: none;
margin: 0;
padding: 0;
counter-reset: toc;
border-left: 1px solid var(--border);
}
nav.toc li { margin: 0; }
nav.toc a {
counter-increment: toc;
display: flex;
gap: 0.65em;
align-items: baseline;
padding: 0.5em 0 0.5em 1em;
margin-left: -1px;
border-left: 2px solid transparent;
color: var(--ink-soft);
text-decoration: none;
}
nav.toc a::before {
content: counter(toc, decimal-leading-zero);
font-family: var(--font-mono);
font-size: 0.76rem;
color: var(--muted);
flex-shrink: 0;
}
nav.toc a:hover { color: var(--accent); border-left-color: var(--border); }
nav.toc a.active { color: var(--accent); border-left-color: var(--accent); font-weight: 600; }
main { min-width: 0; }
section.chapter {
padding-top: 0.4rem;
margin-bottom: 3.6rem;
scroll-margin-top: 1.4rem;
}
section.chapter:last-child { margin-bottom: 0; }
.chapter-head {
display: flex;
align-items: baseline;
gap: 0.85rem;
margin-bottom: 1.3rem;
padding-bottom: 1.1rem;
border-bottom: 1px solid var(--border);
}
.chapter-num {
font-family: var(--font-mono);
font-size: 1.05rem;
font-weight: 600;
color: var(--accent);
flex-shrink: 0;
}
h2.chapter-title {
font-size: clamp(1.5rem, 2.6vw, 1.9rem);
margin: 0;
}
h3.sub {
font-size: 1.12rem;
margin: 1.9rem 0 0.75rem;
}
section.chapter > h3.sub:first-of-type,
.chapter-body > h3.sub:first-child { margin-top: 0.4rem; }
h4.microhead {
font-family: var(--font-mono);
font-size: 0.76rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
margin: 1.6rem 0 0.6rem;
}
/* ---------- Menu path chips ---------- */
.path {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
gap: 0;
font-family: var(--font-mono);
font-size: 0.86em;
font-weight: 500;
background: var(--code-surface);
color: var(--code-ink);
border: 1px solid var(--border-soft);
border-radius: 7px;
padding: 0.18em 0.15em;
line-height: 1.5;
}
.path span { padding: 0.05em 0.5em; white-space: nowrap; }
.path span:not(:last-child)::after {
content: "";
margin-left: 0.55em;
color: var(--muted);
}
p .path, li .path { margin: 0.15em 0; }
p:has(> .path:only-child) { max-width: none; }
.field {
font-family: var(--font-mono);
font-size: 0.86em;
background: var(--surface-2);
border: 1px solid var(--border-soft);
border-radius: 5px;
padding: 0.08em 0.4em;
color: var(--ink-soft);
}
/* ---------- Cards / role & app tables ---------- */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
gap: 0.85rem;
margin: 1.2rem 0 1.6rem;
}
.card {
border: 1px solid var(--border);
background: var(--surface);
border-radius: 12px;
padding: 1.1rem 1.15rem;
box-shadow: var(--shadow);
}
.card b {
display: block;
font-family: var(--font-display);
font-size: 1.02rem;
margin-bottom: 0.3rem;
}
.card p { margin: 0; font-size: 0.92rem; color: var(--ink-soft); max-width: none; }
table.roles {
width: 100%;
border-collapse: collapse;
margin: 1.2rem 0 1.6rem;
font-size: 0.94rem;
}
table.roles th, table.roles td {
text-align: left;
padding: 0.75em 0.9em;
border-bottom: 1px solid var(--border);
vertical-align: top;
}
table.roles th {
font-family: var(--font-mono);
font-size: 0.74rem;
letter-spacing: 0.07em;
text-transform: uppercase;
color: var(--muted);
font-weight: 600;
border-bottom: 1px solid var(--border);
}
table.roles td:first-child, table.roles th:first-child { font-weight: 600; white-space: nowrap; }
table.roles tr:last-child td { border-bottom: none; }
.role-badge {
display: inline-block;
font-family: var(--font-mono);
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.03em;
padding: 0.22em 0.6em;
border-radius: 999px;
background: var(--accent-soft);
color: var(--accent);
white-space: nowrap;
}
/* ---------- Steps ---------- */
ol.steps {
list-style: none;
padding: 0;
margin: 1.1rem 0 1.6rem;
counter-reset: step;
display: flex;
flex-direction: column;
gap: 0.9rem;
}
ol.steps li {
counter-increment: step;
display: grid;
grid-template-columns: 2rem 1fr;
gap: 0.9rem;
margin: 0;
max-width: 66ch;
}
ol.steps li::before {
content: counter(step);
font-family: var(--font-display);
font-weight: 600;
font-size: 0.95rem;
width: 2rem;
height: 2rem;
border-radius: 50%;
background: var(--surface-2);
color: var(--accent);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
/* ---------- Callouts ---------- */
.callout {
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
background: var(--accent-soft);
border-radius: 0 10px 10px 0;
padding: 0.9em 1.15em;
margin: 1.3rem 0;
font-size: 0.94rem;
}
.callout p { margin: 0; max-width: none; color: var(--ink-soft); }
.callout p + p { margin-top: 0.6em; }
.callout b { color: var(--ink); }
.callout.warn {
border-left-color: var(--warn);
background: var(--warn-soft);
}
.callout-label {
font-family: var(--font-mono);
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.09em;
text-transform: uppercase;
color: var(--accent);
display: block;
margin-bottom: 0.4em;
}
.callout.warn .callout-label { color: var(--warn); }
/* ---------- Troubleshooting table ---------- */
table.trouble {
width: 100%;
border-collapse: collapse;
margin: 1.2rem 0 0.4rem;
font-size: 0.93rem;
}
table.trouble th {
text-align: left;
font-family: var(--font-mono);
font-size: 0.72rem;
letter-spacing: 0.07em;
text-transform: uppercase;
color: var(--muted);
font-weight: 600;
padding: 0 0.9em 0.6em 0;
border-bottom: 1px solid var(--border);
}
table.trouble td {
padding: 0.95em 0.9em 0.95em 0;
border-bottom: 1px solid var(--border-soft);
vertical-align: top;
}
table.trouble td:first-child { font-weight: 600; width: 34%; }
table.trouble tr:last-child td { border-bottom: none; }
/* ---------- Footer ---------- */
footer.colophon {
max-width: 1180px;
margin: 0 auto;
padding: 2.2rem 2rem 3.5rem;
border-top: 1px solid var(--border);
color: var(--muted);
font-size: 0.88rem;
}
/* ---------- Responsive ---------- */
@media (max-width: 880px) {
.layout { grid-template-columns: 1fr; }
nav.toc {
position: static;
border: 1px solid var(--border);
border-radius: 12px;
padding: 1rem 1.2rem;
background: var(--surface);
}
nav.toc ol { border-left: none; }
nav.toc a { padding-left: 0; margin-left: 0; border-left: none; }
.app-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
body { overflow-x: hidden; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
</style>
</head>
<body>
<header class="masthead">
<div class="masthead-inner">
<span class="kicker">Community OS · Operations Guide</span>
<h1 class="title">TNCSC Handbook</h1>
<p class="dek">How the Tamil Nadu Cultural Society of Canada configures, runs, and troubleshoots its own system — written for board members and volunteers, not developers.</p>
<div class="login-note">📍 <span><b>Where to log in:</b> your production site's <span class="field">/web/login</span> page. Ask your technical contact for the exact address if you don't have it.</span></div>
<div class="app-grid">
<div class="app-chip">Membership</div>
<div class="app-chip">Events</div>
<div class="app-chip">School</div>
<div class="app-chip">Classifieds</div>
<div class="app-chip">Benefits</div>
<div class="app-chip">Interac Payments</div>
<div class="app-chip">Website</div>
<div class="app-chip">Settings</div>
</div>
</div>
</header>
<div class="layout">
<nav class="toc" aria-label="Table of contents">
<div class="toc-label">Contents</div>
<ol>
<li><a href="#understanding">Understanding the system</a></li>
<li><a href="#roles">User roles</a></li>
<li><a href="#branding">Branding</a></li>
<li><a href="#membership">Membership</a></li>
<li><a href="#events">Events</a></li>
<li><a href="#school">Tamil Class (School)</a></li>
<li><a href="#classifieds">Classifieds</a></li>
<li><a href="#benefits">Benefits</a></li>
<li><a href="#interac">Interac Payments</a></li>
<li><a href="#website">Website content</a></li>
<li><a href="#accounting">Accounting basics</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ol>
</nav>
<main>
<section class="chapter" id="understanding">
<div class="chapter-head"><span class="chapter-num">01</span><h2 class="chapter-title">Understanding the system</h2></div>
<div class="chapter-body">
<p>Once you log in, you'll see an <b>app switcher</b> — a grid of icons, one per area of the system. Each app is where a specific part of TNCSC's work lives:</p>
<div class="card-grid">
<div class="card"><b>Membership</b><p>Members, tiers/pricing, renewals</p></div>
<div class="card"><b>Events</b><p>Creating events, ticketing, check-in</p></div>
<div class="card"><b>School</b><p>Tamil Class terms, classes, attendance</p></div>
<div class="card"><b>Classifieds</b><p>The member board and its moderation queue</p></div>
<div class="card"><b>Benefits</b><p>Benefit centres and member perks</p></div>
<div class="card"><b>Interac Payments</b><p>Confirming e-Transfer payments</p></div>
<div class="card"><b>Website</b><p>The public website — pages, menus, content</p></div>
<div class="card"><b>Settings</b><p>Branding, org configuration, user accounts</p></div>
</div>
<div class="callout">
<span class="callout-label">If an app is missing</span>
<p>It's almost always a permissions issue, not a broken install. See <a href="#roles">User roles</a> and <a href="#troubleshooting">Troubleshooting</a> below.</p>
</div>
<p>Two databases exist during development/testing (<span class="field">tncsc_migration_test</span>, <span class="field">tncsc_site</span>) — your technical contact will tell you which one is live production once you go live. Everything in this guide applies the same way regardless of which database you're in.</p>
</div>
</section>
<section class="chapter" id="roles">
<div class="chapter-head"><span class="chapter-num">02</span><h2 class="chapter-title">User roles — who can do what</h2></div>
<div class="chapter-body">
<p>Go to <span class="path"><span>Settings</span><span>Users &amp; Companies</span><span>Users</span></span>, click a person's name, and under their groups you'll find <b>TNCSC Roles</b>. Check the box for the role that matches what they do:</p>
<table class="roles">
<tr><th>Role</th><th>Grants</th></tr>
<tr><td><span class="role-badge">Board Admin</span></td><td>Everything — membership, school, classifieds, benefits, events, and Interac payments. Give this only to whoever runs the system day-to-day.</td></tr>
<tr><td><span class="role-badge">Treasurer</span></td><td>Confirms Interac payments and has invoicing access.</td></tr>
<tr><td><span class="role-badge">Events&nbsp;Officer</span></td><td>Creates/manages events and staffs check-in.</td></tr>
<tr><td><span class="role-badge">School&nbsp;Coordinator</span></td><td>Manages Tamil Class terms, classes, students, enrollment.</td></tr>
<tr><td><span class="role-badge">Teacher</span></td><td>Can only take attendance for their own classes.</td></tr>
<tr><td><span class="role-badge">Classifieds&nbsp;Moderator</span></td><td>Reviews and publishes classified listings.</td></tr>
</table>
<p>A person can hold more than one role — e.g. someone can be both <b>School Coordinator</b> and <b>Teacher</b>. Members themselves don't need a role checked here at all: once someone is a member, they get their own self-service <b>member portal</b> automatically (see <a href="#membership">Membership</a>) — separate from these backend roles, and it doesn't require a staff login.</p>
<h4 class="microhead">Adding a new staff or volunteer account</h4>
<ol class="steps">
<li>Go to <span class="path"><span>Settings</span><span>Users &amp; Companies</span><span>Users</span><span>New</span></span></li>
<li>Fill in their name and email, then save.</li>
<li>Check the role(s) above for them. They'll get an email to set their own password.</li>
</ol>
</div>
</section>
<section class="chapter" id="branding">
<div class="chapter-head"><span class="chapter-num">03</span><h2 class="chapter-title">Branding: colours, logo, fonts</h2></div>
<div class="chapter-body">
<p><span class="path"><span>Settings</span><span>General Settings</span><span>Theme</span></span> (left-hand tab list).</p>
<ul>
<li><span class="field">Primary / Secondary / Accent Colour</span> — enter a colour as a hex code (e.g. <span class="field">#05091E</span>). These apply instantly across the website, the member portal, and PDF documents like the membership card — no other setting to touch.</li>
<li><span class="field">Logo</span> — upload the image file to use in the site header and on generated PDFs. If left blank, the company logo (<span class="path"><span>Settings</span><span>General Settings</span><span>Companies</span></span>) is used instead.</li>
<li><span class="field">Heading Font / Body Font</span> — enter a font name, e.g. <span class="field">Inter, sans-serif</span>. Needs to be a font available to browsers — ask your technical contact before entering something unusual.</li>
</ul>
<p>Click <b>Save</b> at the top of the page after any change.</p>
</div>
</section>
<section class="chapter" id="membership">
<div class="chapter-head"><span class="chapter-num">04</span><h2 class="chapter-title">Membership</h2></div>
<div class="chapter-body">
<h3 class="sub">Settings</h3>
<p><span class="path"><span>Settings</span><span>General Settings</span><span>Membership</span></span></p>
<ul>
<li><span class="field">Organization Name</span> — used in renewal emails and the membership card.</li>
<li><span class="field">Member ID Format</span> — the pattern new member IDs follow, e.g. <span class="field">TNCSC-{year}-{seq}</span> produces <span class="field">TNCSC-2026-014</span>. Don't change the placeholders unless your technical contact confirms it's safe — they drive the auto-numbering.</li>
<li><span class="field">Renewal Reminder Offsets</span> — comma-separated days-before-expiry to send reminders, e.g. <span class="field">30,14,7</span>.</li>
<li><span class="field">Member Portal</span> — toggle the self-service portal on or off site-wide.</li>
</ul>
<h3 class="sub">Membership tiers and pricing</h3>
<p><span class="path"><span>Membership</span><span>Configuration</span><span>Membership Tiers</span></span></p>
<p>Each row is a plan (Individual, Family, Student, Senior, Life, or whatever TNCSC offers). To <b>change a price</b>, open the tier and edit <span class="field">Price</span> — this is the only place pricing lives. To <b>add a new tier</b>, click New and fill in:</p>
<ul>
<li><span class="field">Name</span> — shown to members, e.g. "Corporate Sponsor"</li>
<li><span class="field">Code</span> — a short internal code, e.g. <span class="field">CORP</span> (no spaces)</li>
<li><span class="field">Price</span> and <span class="field">Currency</span></li>
<li><span class="field">Period</span> — Annual, One-Time, or Monthly</li>
<li><span class="field">Sequence</span> — controls display order (lower numbers show first)</li>
</ul>
<p>Deactivating a tier (rather than deleting it) keeps historical records intact for members who already hold it — use the tier's kebab (⋮) menu → <b>Archive</b>, instead of deleting.</p>
<h3 class="sub">Day-to-day membership work</h3>
<ul>
<li><span class="path"><span>Membership</span><span>Members</span></span> — the full member list. Open a member to see their tier, status, and expiry date.</li>
<li>Renewal reminders and draft renewal invoices are generated <b>automatically</b> by a daily background job — nothing to run manually. What you do need to do periodically: check <span class="path"><span>Invoicing</span><span>Customer Invoices</span></span> for draft renewal invoices and confirm/send them once payment is expected.</li>
<li>Each member can view their status, download their QR membership card, and renew from <span class="field">/my/membership</span> once logged into the website — no need to email cards out manually.</li>
<li>The membership card's QR code links to a public verification page (<span class="field">/membership/verify/&lt;member ID&gt;</span>) — anyone scanning it sees only "valid" / "expired" / "not found," never personal details.</li>
</ul>
</div>
</section>
<section class="chapter" id="events">
<div class="chapter-head"><span class="chapter-num">05</span><h2 class="chapter-title">Events</h2></div>
<div class="chapter-body">
<p><span class="path"><span>Events</span><span>Events</span><span>New</span></span> — this is standard Odoo event creation:</p>
<ol class="steps">
<li>Name, start/end date and time, location.</li>
<li>Under <b>Website</b>, check <span class="field">Is Published</span> to make it visible on the public Events page and the homepage's "Upcoming Events" section — <b>unpublished events won't appear anywhere on the public site</b>, even though they exist in the system.</li>
<li>Add ticket types under the event's <b>Registration</b> tab if you're charging for entry (e.g. "General $0$30").</li>
</ol>
<p>Every registration automatically gets a signed QR ticket, emailed with the confirmation. At the door, staff with the <span class="role-badge">Events Officer</span> role use <span class="path"><span>Events</span><span>Registration Desk</span></span> to scan tickets (or type the ticket reference manually) — it shows valid / already checked-in / invalid, and a live count of registered vs. checked-in.</p>
<p><span class="path"><span>Events</span><span>Reporting</span><span>Attendees / Revenues</span></span> gives you numbers after the fact without any setup.</p>
</div>
</section>
<section class="chapter" id="school">
<div class="chapter-head"><span class="chapter-num">06</span><h2 class="chapter-title">Tamil Class (School)</h2></div>
<div class="chapter-body">
<h3 class="sub">Settings</h3>
<p><span class="path"><span>Settings</span><span>General Settings</span><span>School</span></span>: <span class="field">At-Risk Attendance Threshold</span> — the attendance percentage below which a student is flagged "at-risk" in the report.</p>
<h3 class="sub">Configuration — set these up before each school year</h3>
<ul>
<li><span class="path"><span>School</span><span>Configuration</span><span>Terms</span></span> — create a term (e.g. "2026-27"), set start/end dates, and open it (<span class="field">State = Open</span>) once registration should begin. Only one term should normally be open at a time.</li>
<li><span class="path"><span>School</span><span>Configuration</span><span>Levels</span></span> — define your levels however TNCSC teaches (e.g. "Beginner" through "Advanced", or "Grade 1" through "Grade 12"). Each needs a short <span class="field">Code</span> and optional min/max age.</li>
<li><b>Classes</b> aren't under Configuration — create them from <span class="path"><span>School</span><span>Classes</span><span>New</span></span>: pick the term, level, teacher, weekday, time, location, and max students. This is what shows up as an option when a parent registers online.</li>
</ul>
<h3 class="sub">Day-to-day</h3>
<ul>
<li><span class="path"><span>School</span><span>Students / Enrollments</span></span> — see who's enrolled where.</li>
<li><span class="path"><span>School</span><span>Attendance Report</span></span> — a pivot table of attendance by class.</li>
<li><span class="path"><span>School</span><span>At-Risk Students</span></span> — students below the configured threshold, so you can follow up.</li>
<li>Teachers take attendance themselves from their own portal page (<span class="field">/school/attendance</span>) — a roster with a batch Present/Absent/Late/Excused save. An absence automatically emails the parent. Teachers only see their own classes.</li>
<li>Parents register their child at <span class="field">/school/register</span> on the public website, in three steps. A full class waitlists the student automatically and notifies them when a seat frees up — no manual waitlist management needed.</li>
<li>Each class auto-creates and manages its own online course/materials channel — enrolling or withdrawing a student automatically enrols/unenrols them there too.</li>
</ul>
</div>
</section>
<section class="chapter" id="classifieds">
<div class="chapter-head"><span class="chapter-num">07</span><h2 class="chapter-title">Classifieds</h2></div>
<div class="chapter-body">
<p><span class="path"><span>Settings</span><span>General Settings</span><span>Classifieds</span></span>: <span class="field">Listing Duration</span> — how many days a published listing stays live before auto-expiring.</p>
<p><span class="path"><span>Classifieds</span><span>Moderation</span></span> is where every new submission lands first (state: Pending Review). Open one to <b>Publish</b> or <b>Reject</b> it — only published listings appear on the public <span class="field">/classifieds</span> board. Posting requires the member to be logged in with an active membership, so this queue should only ever contain genuine member submissions.</p>
</div>
</section>
<section class="chapter" id="benefits">
<div class="chapter-head"><span class="chapter-num">08</span><h2 class="chapter-title">Benefits</h2></div>
<div class="chapter-body">
<p>Two things to set up, then one thing to log ongoing:</p>
<ul>
<li><span class="path"><span>Benefits</span><span>Benefit Centres</span></span> — the businesses/organizations offering a member benefit. Add their name, category, description, and logo.</li>
<li><span class="path"><span>Benefits</span><span>Benefits</span></span> — the actual discount/perk, linked to one or more <b>Membership Tiers</b> (only members holding one of those tiers will see it). Set the discount type and validity dates.</li>
<li><span class="path"><span>Benefits</span><span>Redemptions</span></span> — a log a benefit centre (or staff) creates when a member actually uses a benefit, after confirming the member is active. Mostly for your own record-keeping, not something to set up in advance.</li>
</ul>
<p>Members see only what their own tier qualifies them for at <span class="field">/my/benefits</span>; the public directory of participating centres is at <span class="field">/benefits</span>.</p>
</div>
</section>
<section class="chapter" id="interac">
<div class="chapter-head"><span class="chapter-num">09</span><h2 class="chapter-title">Interac e-Transfer Payments</h2></div>
<div class="chapter-body">
<h3 class="sub">One-time setup</h3>
<p><span class="path"><span>Invoicing</span><span>Configuration</span><span>Online Payments</span><span>Payment Providers</span></span> → open <b>Interac e-Transfer</b>:</p>
<ul>
<li><span class="field">Interac Recipient Email</span> — the real e-transfer address payments should be sent to.</li>
<li><span class="field">Interac Deadline Hours</span> — how long an unconfirmed payment stays pending before it's auto-cancelled (defaults to 48 hours if left blank).</li>
<li>Set the provider's <span class="field">State</span> to <span class="field">Enabled</span> so it appears as a checkout option.</li>
</ul>
<h3 class="sub">Day-to-day <span style="font-weight:400;color:var(--muted);font-family:var(--font-body);font-size:0.72em;">— Treasurer role</span></h3>
<p>When someone chooses Interac at checkout, they're emailed instructions (recipient address, amount, a reference code, and the deadline) automatically — nothing for you to send.</p>
<p>Once you actually receive the e-transfer in your real bank account, go to <span class="path"><span>Interac Payments</span><span>Pending Payments</span></span>, find the matching transaction (match by amount and reference code), and click <b>Payment Received</b>. This confirms the linked invoice/registration/order. If nobody confirms it before the deadline, it auto-cancels and the payer is notified by email.</p>
</div>
</section>
<section class="chapter" id="website">
<div class="chapter-head"><span class="chapter-num">10</span><h2 class="chapter-title">Website content</h2></div>
<div class="chapter-body">
<p>The <b>Website</b> app, then click <b>Edit</b> on any page while viewing it on the public site to change text, images, and layout directly (drag-and-drop editor) — no code for routine copy changes. <span class="path"><span>Site</span><span>Menu Editor</span></span> lets you add, remove, or reorder navigation items.</p>
<div class="callout warn">
<span class="callout-label">Known placeholder content</span>
<p>The <b>Sponsors</b> page and a few header/footer text blocks (e.g. a placeholder phone number) still carry content from the original site design — safe to edit or delete through the Website editor whenever real sponsor logos or a real phone number are ready.</p>
</div>
<div class="callout warn">
<span class="callout-label">No public signup yet</span>
<p><b>"Become a Member" buttons currently point to the Contact page</b>, not a self-service signup form — TNCSC doesn't have public online membership signup yet (only renewal, for existing members). Don't redirect these to a form that doesn't exist; talk to your technical contact if/when online signup becomes a priority.</p>
</div>
<p>For anything beyond content edits — new page types, new sections with custom behaviour, structural changes — that's a developer task, not a Website-editor task.</p>
</div>
</section>
<section class="chapter" id="accounting">
<div class="chapter-head"><span class="chapter-num">11</span><h2 class="chapter-title">Accounting basics</h2></div>
<div class="chapter-body">
<p>The chart of accounts, tax setup, and journals were seeded for a Canadian non-profit when the system was set up, including dedicated revenue accounts (Membership Dues, Event Revenue, Sponsorship, School Fees, Donations) and a <b>Donations</b> journal. You generally don't need to create new accounts for normal operations — membership tiers, event tickets, and school fees are already wired to the right ones.</p>
<div class="callout warn">
<span class="callout-label">Don't, without sign-off</span>
<p>Rename or delete existing accounts, or change the company's currency/country, without your accountant <i>and</i> technical contact both signing off — several of these are load-bearing for other parts of the system (e.g. renaming the dues account could silently break where membership payments post to).</p>
</div>
<p>Day-to-day invoicing/payment work happens under the <b>Invoicing</b> app as normal.</p>
</div>
</section>
<section class="chapter" id="troubleshooting">
<div class="chapter-head"><span class="chapter-num">12</span><h2 class="chapter-title">Troubleshooting &amp; getting help</h2></div>
<div class="chapter-body">
<table class="trouble">
<tr><th>Symptom</th><th>Likely cause / fix</th></tr>
<tr><td>An app I should have access to isn't in my switcher</td><td>You're missing the matching role — see <a href="#roles">User roles</a>. Ask a Board Admin to check the box for you.</td></tr>
<tr><td>I changed a setting and nothing changed on the site</td><td>Make sure you clicked <b>Save</b>. If it still looks wrong after a minute, it may need a technical restart — contact support rather than repeating the change.</td></tr>
<tr><td>A member says their QR card doesn't work</td><td>Check their membership <b>state</b> on their member record — the verify page only shows "valid" for members currently <i>active</i>.</td></tr>
<tr><td>An event isn't showing on the website</td><td>Confirm <span class="field">Is Published</span> is checked on the event — unpublished events are invisible on the public site by design.</td></tr>
<tr><td>A parent can't register for a class</td><td>Check the term is <b>Open</b> and the class isn't already full — full classes waitlist automatically rather than blocking registration outright.</td></tr>
<tr><td>An Interac payment doesn't confirm</td><td>Double-check the reference code and amount match exactly before clicking Payment Received — mismatches usually mean it's a different transaction.</td></tr>
</table>
<p style="margin-top:1.4rem;">For anything not covered here — a genuine error message, something that looks broken rather than misconfigured, or a request for new functionality — contact your technical support contact rather than experimenting on the live site. Screenshots and the exact steps you took help them fix it faster.</p>
</div>
</section>
</main>
</div>
<footer class="colophon">
This handbook covers the CommunityOS suite as configured for TNCSC. It does not cover server maintenance, backups, or deployment — those remain your technical contact's responsibility.
</footer>
<script>
(function () {
var links = Array.prototype.slice.call(document.querySelectorAll('nav.toc a'));
var sections = links.map(function (a) {
return document.getElementById(a.getAttribute('href').slice(1));
});
function onScroll() {
var pos = window.scrollY + 140;
var activeIndex = 0;
for (var i = 0; i < sections.length; i++) {
if (sections[i] && sections[i].offsetTop <= pos) activeIndex = i;
}
links.forEach(function (a, i) {
a.classList.toggle('active', i === activeIndex);
});
}
document.addEventListener('scroll', onScroll, { passive: true });
onScroll();
})();
</script>
</body>
</html>