← District 67 Dashboard

District 67 Dashboard — 建置規格 · Build Spec

雙語文件:第一部分為繁體中文,第二部分為 English;兩版內容一致。 Bilingual document: Part 1 is Traditional Chinese, Part 2 is English — both parts are equivalent.



第一部分 · 繁體中文

我們在做什麼: 一個獨立、唯讀的網頁應用,為**教育卓越總監(PQD)**與地區領導者呈現 國際演講會第 67 地區(District 67)的營運表現,並補上官方儀表板所缺少的俱樂部中文名稱

取代/整合: project-highlight/ai001.md(功能構想)與 project-highlight/ai002.md(中文名稱補充)。本檔為權威規格; 凡與 ai001/ai002 衝突之處,以本檔為準(尤其是比對鍵 — 見 §3.4)。

範圍: 僅限第 67 地區(id=67)。無地區切換器。唯讀鏡像,絕不回寫 TI。

設計理念 — 以完整性為先的預覽版。 我們尚未確定 PQD 想用哪些資料來決策,因此本應用的任務是 讓第 67 地區的所有資訊都可取得、可探索,而非預先替使用者決定什麼重要。原則:

  1. 忠實鏡像、毫不隱藏 — 官方報表對 id=67 顯示的每一項指標與層級,全部重現。
  2. 可探索、不強加觀點 — 提供排序/篩選/搜尋/切換;帶觀點的視圖(如 watchlist)只是選用輔助, 而非應用的主張。
  3. 只補上缺少的 — 中文名稱、雙語搜尋、資料截止日可視化、行動裝置存取。
  4. 定義要透明 — 把 183 已授證/178 運作中/174 已繳費並列呈現;標示「繳費筆數 ≠ 不重複人數」。 我們讓區別清楚可讀,由 PQD 自行詮釋。
  5. 漸進式揭露 — 總覽 → 下鑽 → 完整表格 → 匯出,讓深度可得但不致一眼資訊過載。這是我們呈給 PQD、 用以蒐集後續指示的 v1。

第 67 地區基準(2026-06-15 驗證,年度 2025-2026,資料截至 2026-06-12)

指標 數值
區(Divisions) 9(A–I)
分會區(Areas) 38
名冊上的俱樂部 183(178 運作中 · 174 已繳費 · 173 基準)
暫停的俱樂部 5(FHK, NTUST, Critical Thinkers, MIRDC, Scien Tech)
會員實際人數(目前 To Date) 2,660(基準 2,838 · 淨 −178)— 真正的會員數
會籍繳費筆數(本年度累計) 5,472(基準 5,377)— 繳費交易數,約為會員數 2 倍;非人數

各區(分會區數/俱樂部數/會員目前人數/淨): A 4/20/225/−11 · B 4/20/280/−21 · C 4/21/365/+10 · D 4/23/324/−3 · E 4/17/275/−8 · F 5/23/291/−81 · G 5/23/367/+9 · H 4/18/277/−17 · I 4/18/256/−56。

會員數=實際人數,非繳費筆數。 District Performance 報表只揭露會籍繳費數(5,472)— 每位會員每年可繳費兩次(十月與四月續會),故繳費 ≈ 2× 會員數,絕不可標為會員數。真正的人數來自 Club Performance 報表Club.aspx?id=67):每間俱樂部的 基準/目前/淨成長(例如 Taipei 31 → 26,淨 −5)。 地區總計 目前 To Date = 2,660。本應用以 目前(To Date)作為「會員數」;繳費筆數另行呈現並明確標為交易數。

俱樂部計數詞彙(雙語 — 必須顯示於應用內)

這些區別是「定義要透明」的核心。請在應用內(如資訊面板/各計數的提示)以中英雙語顯示:

名稱 意義
名冊上的俱樂部(Clubs on Roster) 名冊上的俱樂部總數(含暫停)
已繳費俱樂部(Paid Clubs) 已完成本期會籍繳費的俱樂部
良好標準俱樂部(Good Standing Clubs) 符合 TI 規定、會員數達標完成繳費的俱樂部
運作中俱樂部(Active Clubs) 仍在運作中的俱樂部
暫停的俱樂部(Suspended Clubs) 暫停或未達要求的俱樂部

階段劃分(範圍紀律)

第一階段 — 立即建置並呈現(在 PQD 回饋前唯一要做的): 俱樂部計數+會員數 — 整份摘要的基礎。 一個總覽畫面:D67 一覽 (區 9/分會區 38/名冊俱樂部 183/運作中 178/已繳費 174/暫停 5),加上各區的 分會區/俱樂部/**會員(目前實際人數)表。會員數=目前 To Date = 2,660(取自 Club Performance 的真實人數), 含基準+淨成長;會籍繳費(5,472)**另行呈現並標為交易數(≈2×)。中英雙語並顯示俱樂部計數詞彙。 每間俱樂部連結至其 TI Club Report(ClubReport.aspx?id=<補零>)。

第二階段以後 — 在此規劃備妥,但僅在需求者(PQD)回應後才建置/發布: 完整雙語俱樂部表、 區/分會區與 Club-Report 區段各自深連到官方 TI 報表(以區段呈現,分頁)、中文名稱補充 (clubId 比對,§3.4)、DCP 目標與傑出俱樂部狀態、趨勢、輔助/watchlist 視圖、匯出。本規格其餘部分定義這些, 以便一經要求即可快速推進。


1. 主要資料來源(2026-06-15 驗證)

基底: https://dashboards.toastmasters.org/2025-2026/district.aspx?id=67&hideclub=1 此為 District Performance 報表,列出 D67 每一間俱樂部,依 區 → 分會區 → 俱樂部 分組。 亦提供 Export → CSV 控制項與 資料截止日/年度/月份 選擇器(約近一週可取每日快照;年度可回溯至 2008-2009)。

1.1 地區 KPI 摘要(頁面頂端)

三個標題區塊,各含 基準(Base)目前(To Date),與四個表彰目標門檻

1.2 各俱樂部資料列(全俱樂部表)

每列提供:

欄位 範例 說明
俱樂部編號 0000189028679758 8 位、前置補零。TI 俱樂部編號=主鍵。
俱樂部名稱(英文) Taipei ClubDALI Bilingual Toastmasters Club
狀態標記 Susp 03/31/26Charter 02/02/26 選用;僅暫停/新授證俱樂部才有
Late/Oct/Apr 0 / 24 / 20 各時段續會繳費
Total(續會) 44 Late+Oct+Apr
New 8 新會員繳費
Charter 0 授證繳費
Total(繳費) 52 續會+新會+授證(本年度累計)

區與分會區的小計列另帶 俱樂部數 欄。

1.3 Club Performance 報表 — Club.aspx?id=67(已納入)

真實會員人數 在此,而非 District Performance。每間俱樂部:Mem. 基準/目前/淨達成目標數(滿 10), 以及 10 項 DCP 個別目標。第一階段納入 基準/目前/淨+達成目標數data/raw/club-performance-67.json,以 clubId 與俱樂部比對);完整 10 目標格與傑出狀態屬後續階段。 目前人數亦可於 Division.aspx?id=67(各俱樂部「Mem. To Date」)核對。


2. 補充來源 — 中文名稱(2026-06-15 驗證)


3. 資料管線

3.1 擷取基底(TI)— 每週快照

3.1a UI 模式 — 關鍵資訊卡 → 明細

儀表板以關鍵資訊卡呈現;每張卡連到該報表的明細區段(以區段呈現、非分頁 — §5),明細再深連至官方 TI 頁面。 總覽 → 卡片 → 明細 → 官方來源。

3.2 擷取補充資料(台灣)

3.3 名稱解析

3.4 基底 × 補充比對 — clubId(長整數)為主,名稱+分會區為後備

更正(取代先前 ai002 的說法)。 台灣官網的 id 就是 TI 俱樂部編號,只是未補零 — 故雙方轉為整數後即可比對。 已用清單實際連結 id 對 12 間俱樂部驗證:376=新竹(TI 00000376)、1890=台北(00001890)、1904=高雄、 2304=YMIC … 全部相符。DALI 為唯一例外 — 全新授證,儀表板顯示 TI 新會編號(28679758),本地則為其 永久編號(1460763)。故 id 比對為通則,新授證為後備案例。

標準鍵: clubId = parseInt(tiClubNumber, 10)(見 §4 — 同時保存補零顯示形式)。

比對演算法:

  1. 主要: dashboard.clubId === taiwan.id → 整數精確比對。涵蓋絕大多數。
  2. 後備(新授證/未連結俱樂部): 正規化英文名(轉小寫;去標點;正規化 ToastmastersClubInt'l&; 去除尾端括號),並在同一 區+分會區 內比對(儀表板 Division X / Area NN ↔ 清單 AreaCodeF3)。
  3. 未比中 → 中文名留空並列入對帳報告。(TW 連結 160 間 vs TI 名冊 183 間 → 初期約 23 間落在此。)
  4. overrides.jsonclubId → chineseName)處理人工殘餘 — 永久保存,可在重新匯入後存活。

TI 俱樂部編號仍為應用主鍵chineseName 為經比對解析而附加的屬性。


4. 資料模型

ClubSnapshot {
  asOf: date
  district: {
    paidClubs:{base,toDate,goals{distinguished,select,presidents,smedley}}
    payments:{base,toDate,goals{...}, breakdown{late,oct,apr,renewTotal,new,charter,total}}
    distinguishedClubs:{base,toDate,goals{...}}
    activeClubs: number
  }
  divisions: [{ code, clubCount, payments{...},
    areas: [{ code, clubCount, payments{...},
      clubs: [Club] }] }]
}

Club {
  clubNumber          // TI, PRIMARY KEY (e.g. "28679758")
  englishName
  division, area      // e.g. "F","03"
  status              // active | suspended | chartering ; statusDate
  payments {late, oct, apr, renewTotal, new, charter, total}
  membership {base, toDate, net, goalsMet}   // 真實人數,取自 Club Performance
  // --- 補充(以 clubId 比對)---
  chineseName | null
  language | null     // 英語/雙語/...
  city | null
  detailUrl | null
  meeting | null      // {format,time,venue,fee,contact,charterDate}  (第二階段)
  match {method: clubId | exact | fuzzy | override | unmatched, confidence}
  // --- 第二階段:DCP ---
  dcp | null          // {goalsMet, goals[10], recognition}
}

5. 功能(v1)

第二階段


6. 頁面/路由

路由 內容 狀態
/ F1 總覽+各區摘要表+俱樂部計數卡 已建置
/divisions F2 區 → 分會區 → 俱樂部 下鑽樹(每間俱樂部含 ClubReport 連結+狀態) 已建置
/spec 本規格(雙語) 已建置
/clubs F3 全俱樂部可排序/篩選表(雙語) 第二階段
/clubs/[clubNumber] 單一俱樂部明細(繳費、狀態、中文名、例會資訊) 第二階段
/watchlist F4 完整關注清單 第二階段
/admin/reconcile 未比中俱樂部視圖+override 編輯器(§3.4) 第二階段

7. 技術堆疊


8. 非功能需求


9. 範圍外


10. 風險與待決問題


11. 里程碑

  1. M1 — 擷取+模型: TI 基底(CSV/HTML)→ 快照;驗證所有俱樂部可解析。
  2. M2 — 核心 UI: F1 總覽、F3 全俱樂部表、F2 下鑽。
  3. M3 — 補充: 台灣爬取 → 名稱+分會區比對 → 雙語呈現+ /admin/reconcile
  4. M4 — F4 watchlist +行動裝置打磨 → 發布 v1。
  5. 第二階段: DCP 報表、趨勢、匯出、明細頁資料。


Part 2 · English

What we're building: a standalone, read-only web app that presents Toastmasters District 67 performance for the Program Quality Director (PQD) and district leaders, with Chinese club names that the official dashboard lacks.

Supersedes/consolidates: project-highlight/ai001.md (feature ideas) and project-highlight/ai002.md (Chinese-name enrichment). This file is the authoritative spec; where it disagrees with ai001/ai002, this wins (notably the join key — see §3.4).

Scope: District 67 only (id=67). No district picker. Read-only mirror; we never write back to TI.

Design philosophy — completeness-first preview. We don't yet know which decisions the PQD wants to drive, so the app's job is to make all of District 67's information available and explorable, not to pre-decide what matters. Principles:

  1. Mirror faithfully, hide nothing — every metric and level the official report shows for id=67, reproduced.
  2. Explorable, not prescriptive — give sort/filter/search/toggles; opinionated views (e.g. a watchlist) are optional helpers, never the app's thesis.
  3. Add only what's missing — Chinese names, bilingual search, as-of-date visibility, mobile access.
  4. Be transparent about definitions — show 183 chartered / 178 active / 174 paid side by side; label "payments ≠ unique headcount." We make distinctions legible; the PQD interprets.
  5. Progressive disclosure — overview → drilldown → full table → export, so depth is available but not overwhelming on first glance. This is the v1 we present to the PQD to gather further instructions.

District 67 baseline (verified 2026-06-15, PY 2025-2026, as-of 12-Jun-2026)

Metric Value
Divisions 9 (A–I)
Areas 38
Clubs on roster 183 (178 active · 174 paid · 173 base)
Suspended clubs 5 (FHK, NTUST, Critical Thinkers, MIRDC, Scien Tech)
Member head count (To Date) 2,660 (base 2,838 · net −178) — the real member count
Membership payments YTD 5,472 (base 5,377) — payment transactions, ≈2× members; NOT a head count

Per division (Areas / Clubs / members To Date / net): A 4/20/225/−11 · B 4/20/280/−21 · C 4/21/365/+10 · D 4/23/324/−3 · E 4/17/275/−8 · F 5/23/291/−81 · G 5/23/367/+9 · H 4/18/277/−17 · I 4/18/256/−56.

Member count = head count, not payments. The District Performance report only exposes membership payments (5,472) — each member can pay twice a year (Oct + Apr renewals), so payments ≈ 2× members and must never be labelled as a member count. The real head count comes from the Club Performance report (Club.aspx?id=67): per club Base / To Date / Net Growth (e.g. Taipei 31 → 26, net −5). District total To Date = 2,660. The app uses To Date as 會員數 (member count); payments are shown separately and clearly labelled as transactions.

Club-count glossary (bilingual — must render in the app)

These distinctions are central to "be transparent about definitions." Show this glossary in-app (e.g. an info panel / tooltips on each count), in both English and 繁體中文:

Name 名稱 Meaning 意義
Clubs on Roster 名冊上的俱樂部總數 (all clubs on the roster, incl. suspended)
Paid Clubs 已完成本期會籍繳費的俱樂部 (clubs that have completed this period's membership dues)
Good Standing Clubs 符合 TI 規定、會員數達標且完成繳費的俱樂部 (meet TI rules — membership minimum met and dues paid)
Active Clubs 仍在運作中的俱樂部 (clubs still operating)
Suspended Clubs 暫停或未達要求的俱樂部 (suspended / not meeting requirements)

Phasing (scope discipline)

Phase 1 — build & present NOW (this is the only thing we build before PQD feedback): Club count + member count — the base for the whole summary. One overview screen: the D67 at-a-glance (Divisions 9 / Areas 38 / Clubs-on-roster 183 / Active 178 / Paid 174 / Suspended 5) plus the per-division Areas / Clubs / Members (To Date head count) table. Member count = To Date = 2,660 (real head count from Club Performance), with Base + Net Growth; membership payments (5,472) shown separately and labelled as transactions (≈2×). Bilingual (EN / 繁中) with the club-count glossary visible. Each club links to its TI Club Report (ClubReport.aspx?id=<padded>).

Phase 2+ — planned & prepared here, but built/released only on the requestor's (PQD's) response: full bilingual club table, Division/Area & Club-Report sections each deep-linking to the official TI report (sections, not tabs), Chinese-name enrichment (clubId join, §3.4), DCP goals & Distinguished status, trends, helper/watchlist views, exports. The rest of this spec defines these so we can move fast once asked.


1. Primary data source (verified 2026-06-15)

Base: https://dashboards.toastmasters.org/2025-2026/district.aspx?id=67&hideclub=1 This is the District Performance report and it lists every club in D67, grouped Division → Area → Club. It also exposes an Export → CSV control and as-of date / program-year / month selectors (daily snapshots available for ~the last week; program years back to 2008-2009).

1.1 District KPI summary (top of page)

Three headline blocks, each with Base, To Date, and the four recognition goal thresholds:

1.2 Per-club row (the all-clubs table)

Each club row provides:

Field Example Notes
Club Number 00001890, 28679758 8-digit, zero-padded. TI club number = our primary key.
Club Name (English) Taipei Club, DALI Bilingual Toastmasters Club
Status flag Susp 03/31/26, Charter 02/02/26 Optional; present only for suspended / newly chartered clubs
Late / Oct / Apr 0 / 24 / 20 Renewal payments by window
Total (renewals) 44 Late+Oct+Apr
New 8 New-member payments
Charter 0 Charter payments
Total (payments) 52 renewals + new + charter (YTD)

Division and Area subtotal rows additionally carry a Club Count column.

1.3 Club Performance report — Club.aspx?id=67 (now ingested)

The real member head count lives here, not on District Performance. Per club: Mem. Base / To Date / Net, Goals Met (of 10), and the 10 individual DCP goals. Phase 1 ingests Base / To Date / Net + Goals Met (data/raw/club-performance-67.json, joined to clubs by clubId); the full 10-goal grid + Distinguished status are a later phase. To Date is also confirmable on Division.aspx?id=67 (per-club "Mem. To Date").


2. Enrichment source — Chinese names (verified 2026-06-15)


3. Data pipeline

3.1 Ingest base (TI) — weekly snapshot

3.1a UI pattern — key-info cards → detail

The dashboard surfaces key info as cards; each card links to that report's detail section (sections, not tabs — §5), which in turn deep-links to the official TI page. Overview → card → detail → official source.

3.2 Ingest enrichment (Taiwan)

3.3 Name parsing

3.4 Join base × enrichment — by clubId (long int), with name+area fallback

Correction (supersedes the earlier ai002 claim). The Taiwan site's id is the TI club number, just unpadded — so the join works once both sides are converted to integer. Verified across 12 clubs from the listing's actual link ids: 376=Hsinchu (TI 00000376), 1890=Taipei (00001890), 1904=Kaohsiung, 2304=YMIC, … all match. DALI is the lone exception — a brand-new charter showing TI's new-club number (28679758) on the dashboard but its permanent number (1460763) locally. So the id join is the rule; new charters are the fallback case.

Canonical key: clubId = parseInt(tiClubNumber, 10) (see §4 — store padded display form too).

Join algorithm:

  1. Primary: dashboard.clubId === taiwan.id → exact integer match. Handles the large majority.
  2. Fallback (new charters / unlinked clubs): normalize English names (lowercase; strip punctuation; normalize Toastmasters/Club/Int'l/&; drop trailing parens) and match within the same Division+Area (dashboard Division X / Area NN ↔ list AreaCode like F3).
  3. Unmatched → Chinese name blank + added to a reconciliation report. (160 clubs linked on TW vs 183 on TI roster → expect ~23 here initially.)
  4. overrides.json (clubId → chineseName) for the manual residue — permanent, survives re-imports.

The TI club number remains the app's primary key; chineseName is an appended attribute resolved via the join.


4. Data model

ClubSnapshot {
  asOf: date
  district: {
    paidClubs:{base,toDate,goals{distinguished,select,presidents,smedley}}
    payments:{base,toDate,goals{...}, breakdown{late,oct,apr,renewTotal,new,charter,total}}
    distinguishedClubs:{base,toDate,goals{...}}
    activeClubs: number
  }
  divisions: [{ code, clubCount, payments{...},
    areas: [{ code, clubCount, payments{...},
      clubs: [Club] }] }]
}

Club {
  clubNumber          // TI, PRIMARY KEY (e.g. "28679758")
  englishName
  division, area      // e.g. "F","03"
  status              // active | suspended | chartering ; statusDate
  payments {late, oct, apr, renewTotal, new, charter, total}
  membership {base, toDate, net, goalsMet}   // real head count from Club Performance
  // --- enrichment (joined by clubId) ---
  chineseName | null
  language | null     // 英語/雙語/...
  city | null
  detailUrl | null
  meeting | null      // {format,time,venue,fee,contact,charterDate}  (Phase 2)
  match {method: clubId | exact | fuzzy | override | unmatched, confidence}
  // --- Phase 2: DCP ---
  dcp | null          // {goalsMet, goals[10], recognition}
}

5. Features (v1)

Phase 2


6. Pages / routes

Route Content Status
/ F1 overview + per-division summary table + count cards Built
/divisions F2 Division → Area → Club drilldown tree (per-club ClubReport links + status) Built
/spec This spec (bilingual) Built
/clubs F3 all-clubs sortable/filterable table (bilingual) Phase 2
/clubs/[clubNumber] Single-club detail (payments, status, Chinese name, meeting info) Phase 2
/watchlist F4 full at-risk lists Phase 2
/admin/reconcile Unmatched-clubs view + override editor (§3.4) Phase 2

7. Tech stack


8. Non-functional


9. Out of scope


10. Risks & open questions


11. Milestones

  1. M1 — Ingest + model: TI base (CSV/HTML) → snapshot; verify all clubs parse.
  2. M2 — Core UI: F1 overview, F3 all-clubs table, F2 drilldown.
  3. M3 — Enrichment: Taiwan crawl → name+area join → bilingual rendering + /admin/reconcile.
  4. M4 — F4 watchlist + mobile polish → ship v1.
  5. Phase 2: DCP report, trends, exports, detail-page data.

Data structures verified live 2026-06-15 against district.aspx (id=67) and toastmasters.org.tw. Base report is program year 2025-2026, as-of 12-Jun-2026.