Nội bộ — tài liệu vận hành. Sơ đồ end-to-end từng luồng dưới Management Hub, để duyệt, không phải bản phân phối. Bản nháp, có thể thay đổi. Một số định danh hạ tầng đã được lược bỏ. noindex.

_system / notes · companion to kế hoạch tích hợp

Management Hub — sơ đồ vận hành end-to-end từng luồng

Tám bảng, bốn hệ thống, một vòng vận hành. Bản nháp 2026-05-31 · cập nhật hai luồng vận hành 2026-06-02 (xem §0) · thêm luồng Khảo sát & xét chọn 2026-06-02 (§1b).

Status: reference, for Editor · 2026-05-31 · author: Claude session Companion to: _system/plans/management-hub-integration-plan-v1.md (the build plan), _system/notes/management-hub-mockup-handoff-2026-05-31.md, memory project_management-hub-integration-plan.

This is the operating view the plan does not spell out: for each hub panel, who triggers it, every step, which real tool / agent / cloud service / app route does the work, where the data lives, and exactly where the one human gate sits. Grounded in the actual code (not the mockup). Phase A throughout: the hub reads and routes; the only thing the system never does on its own is post.

Legend — maturity: 🟢 deployed-live · 🟡 deployed · 🟠 built-not-deployed · 🔵 new read-view (unbuilt) · 🟣 new surface + new data (unbuilt) · ⚪ placeholder (nothing built)


The one-paragraph picture

There are four real subsystems (Media&Story, Care, Donor/Finance, Community) behind eight hub panels, sitting on three privacy-separated SQLites that are never SQL-joined (registry.sqlite = bundles, so-dang-ky.sqlite = care, so-tai-chinh.sqlite = finance). The hub is a new parent app (app/hub.py, not built yet) that puts one login in front of all of them, mounts the three dashboards, adds three native read-views, and aggregates a daily action strip by reading all three DBs in Python. The operating loop is FIELD → EDITORIAL → AUDIENCE → RESOURCES, and "everything closes the transparency loop." Today the left half is live (field intake, the media pipeline, the care subsystem, finance recording); the editorial-intelligence top edge (content-plan, trips, presence) and the audience-feedback return edge (community) are unbuilt, and the connective tissue (app/hub.py + the Overview) is still only mock HTML.

        FIELD                 EDITORIAL              AUDIENCE             RESOURCES
  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────┐  ┌──────────────────┐
  │ brief-form +     │  │ Kế hoạch nội dung│  │ Hiện diện XH │  │ Tài trợ & Tài chính│
  │ photos → Drive   │  │  (🟣 plan)       │  │  (🔵 presence)│  │  (🟠 donor/finance)│
  │  → ingest        │  │   ↑ pulls trips, │  │              │  │   → thank-you +   │
  │  → pipeline      │──┼──▶ holidays,     │  │ Cộng đồng    │◀─┤     receipt →     │
  │  → Hàng đợi duyệt│  │   journey miles  │  │  (⚪ Op1)    │  │   transparency    │
  │  🟢 review queue │  │                  │  │              │  │                   │
  └────────┬─────────┘  └────────┬─────────┘  └──────┬───────┘  └────────┬──────────┘
   CARE (parallel, 🟢):          │                   │                    │
   intake→promote→profile        │  Hoạt động &      │                    │
   +benefits+watchlist ──miles──▶│  Chuyến đi (🔵)──▶│ (orphan-trip flag) │
   🌱 Thụ hưởng                  │  trip ledger      │                    │
                                 ▼                   ▼                    ▼
                       🌻 Tổng quan (Overview, 🟣) = one login, action strip,
                          three independent DB reads stitched in Python

0. Hai luồng vận hành (hướng mục tiêu — cập nhật 2026-06-02)

Cập nhật từ comments của administrator (2026-06-02). Hai quyết định định hình lại phần FIELD→EDITORIAL: (a) tách hẳn việc đưa hoạt động về Hub khỏi việc viết bài; (b) viết bài là theo yêu cầu, có hộp chỉ đạochọn ảnh. Mục này mô tả hướng mục tiêu; các mục 1–8 bên dưới vẫn ghi đúng trạng thái build hiện tại để đối chiếu. Hai điểm chưa khớp code được nêu rõ ở cuối mục.

Luồng 1 — Hoạt động & Chuyến đi (chỉ ingest, kết thúc ở Hub)

  1. Người dùng điền Phiếu hoạt động với các thông tin liên quan.
  2. Khi gửi: hệ thống tạo một thư mục riêng cho hoạt động, kèm các thư mục con (photos/, videos/), và lưu phiếu đã điền vào thư mục đó (brief.yaml).
  3. Gửi email kèm link thư mục tới địa chỉ của người đã điền phiếu.
  4. Người dùng tải ảnh/video lên các thư mục con tương ứng.
  5. Một watch job rà và cập nhật chi tiết hoạt động lên Management Hub, bao gồm link tới thư mục của hoạt động đó.
  6. Luồng kết thúc ở đây. Đưa ảnh về Hub không tự sinh ra câu chuyện.

Luồng 2 — Mạng xã hội

2a · Câu chuyện từ một hoạt động (theo yêu cầu).

  1. Người dùng bấm “Yêu cầu viết bài” từ một hoạt động.
  2. Luồng bắt đầu bằng việc đọc phiếu + ảnh trong thư mục của hoạt động đó và chuẩn bị câu chuyện cho FacebookWebsite theo bộ quy tắc thương hiệu.
  3. Có một hộp chỉ đạo (comment box) để người dùng nhập hướng cho câu chuyện trước khi công cụ chọn ảnh và viết. Người dùng có thể tự chọn ảnh (hoặc để hệ thống tự chọn), rồi bản nháp được soạn theo hướng đó.
  4. Có bản nháp → đẩy lên Management Hub để người dùng xem, sửa, hoặc duyệt.
  5. Nếu duyệt (hoặc có chỉnh sửa rồi duyệt), hệ thống lấy đó làm bản cuốilưu vào một thư mục riêng trong kho câu chuyện (10_Cau-chuyen/ — dùng lại kho hiện có; band mới 09_Mang-xa-hoi/ đã bị hủy 2026-06-02, phân biệt bản đăng vs bản ghi bằng thẻ registry.post).
  6. Một công cụ tự cải thiện định kỳ rà các chỉnh sửa của người dùng để phân tích và học; gửi một bản tóm tắt tới người dùng để duyệt trước khi áp dụng (không tự đổi prompt/few-shot).

2b · Các nguồn nội dung khác ngoài hoạt động thực địa (gương em, tin trường, ngày lễ, cột mốc Quỹ, thường kỳ/theo mùa, minh bạch tài trợ) — xem §6 Kế hoạch nội dung.

Chi tiết end-to-end: §1 luồng thu nhận hoạt động · §2 media & story workflow (viết bài theo yêu cầu).

Hai điểm chưa khớp code hiện tại (việc cần làm):


1. 🟢 Hoạt động & Chuyến đi — luồng thu nhận (intake only)

One line. A coordinator submits the Activity Form; a Service creates the activity's own folder (photos/videos subfolders), saves the filled form inside it, and emails the folder link back to the submitter; the coordinator uploads media; a watch Job ingests + sanitises it and updates the activity (with its folder link) onto the Management Hub. The workflow ends here — no story is drafted. (This is Workflow 1 from the 2026-06-02 comments; §0.)

Triggers. Activity-Form submit (webhook) · photos land in Drive · ingest-watch Job (every 3 min) · daily pipeline Job — target: ingest + sanitise only.

Walkthrough.

Cloud: event-folder · ingest-watch · status-reconcile (all deployed-live). Feeds: Trips read-view (§7) · Content-plan orphan/petal flags (§6) · the story-request entry point (§2). Gaps: email-link-back not built (🟣); decoupling not done — today the daily pipeline Job continues straight on into cull→caption (the old coupled chain, now §2) instead of stopping at sanitise; petal_anchor in brief.yaml is free-text, not validated against the 8 petals.


1b. 🟣 Khảo sát & xét chọn học sinh — luồng thu nhận ứng viên (Candidate survey & selection)

Một luồng thu nhận thực địa thứ ba, song song với §1 (Hoạt động): cùng khuôn form → thư mục → watch job → Hub, nhưng dữ liệu là ứng viên chương trình (hồ sơ gia đình, nhạy cảm, nội bộ — không bao giờ đăng) và đầu ra là một học sinh mới ở §3 (Quản lý học sinh), không phải một bài đăng.

One line. A coordinator submits the Survey Form (candidate / family details for the Foundation's programmes); a Service creates the candidate's own folder under a new restricted band 11_Khao-sat/ (with an anh/ photo subfolder), saves the filled form inside it, and emails the folder link back; the coordinator uploads home-visit photos; a watch Job sanitises them and updates the candidate (with its folder link) onto the Hub and a candidate register for later review; after an internal human promotion (the "admit" button on the Hub), an admitted candidate is minted as a new journey-NNNN with its own folder in the care band and moves to the Quản lý học sinh workflow (§3). Sensitive, internal-only — nothing here ever becomes a published post.

Triggers. Survey-Form submit (webhook) · photos land in a candidate anh/ folder · a survey watch Job (sanitise + Hub/register upsert) · the administrator's promotion decision on the Hub Khảo sát panel.

Walkthrough.

Cloud: a new survey-folder Service (the §1 event-folder pattern re-pointed at 11_Khao-sat/) · a survey watch/sanitise Job · the §3 care subsystem on admission · a new candidate register (markdown-canonical + SQLite projection, mirroring care; its own store in the new band, separate from so-dang-ky.sqlite until admission). Feeds: the Care subsystem (§3) — admitted candidates become journey-NNNN · the Quản lý học sinh ledger · the Overview action strip ("khảo sát chờ xét chọn"). Does not feed the media/story streams (internal-only). Gaps: everything here is unbuilt (🟣) — the Phiếu khảo sát Form + onSurveySubmit.gs, the 11_Khao-sat/ restricted band + its permissions (chosen 2026-06-02: a new band, kept separate from the beneficiary store until admission), the survey-folder Service path, the candidate register, the watch-job Hub/register upsert, the email-link-back (the same gap as §1), and the admission → journey-NNNN handoff (no candidate→care promote exists). The mockup #survey panel already exists (a read/write-light UI in the Hub), but nothing backs it with data or services yet. Naming: a candidate id scheme (ung-vien-NNNN) must be reserved alongside journey-NNNN so the two never collide.


2. 🟢 Media & Story workflow — viết bài theo yêu cầu → duyệt → đóng gói (Stream A)

One line. On a story-request for an activity, the system reads its form + photos, takes an optional direction box and a chosen-photo set (or auto-culls), and drafts FB + Website copy into a post-bundle at awaiting-approval; the administrator approves with a required dignity_ok (gate-8 folded in); a Stage-1 manual pack is emitted and the approved final is archived to the 10_Cau-chuyen/ story archive. Nothing auto-publishes. (Workflow 2a; §0.)

Triggers. 🔵 “Yêu cầu viết bài” button on a Hub activity (target primary path) · today: the daily 09:00 ICT pipeline still auto-drafts every bundle with photos (to be narrowed — §1) · administrator opens the queue.

Walkthrough.

Cloud: pipeline · decisions · review (all deployed-live) · Anthropic Opus. Feeds: Presence (§7) · Community (§8) · quality ratchet · the 10_Cau-chuyen/ finals archive. Gaps: the on-demand trigger + direction box + user photo-pick are unbuilt (🔵); the finals → 10_Cau-chuyen/ write on approval is unbuilt (🟣) (no new 09_ band — decision revised 2026-06-02); the human-gated self-improve summary cadence is unbuilt (🟣)auto-optimize exists but proposes on its own cadence, not a per-edit summary for review; not yet mounted under /review (P4); the headless pipeline runs only gate 1 + records gate-8-pending (agent gates 3–7 are not invoked in the cloud path, so human approval is the real substantive check); the daily chain processes photos only (video_edit is invoked separately).


3. 🟢 Thụ hưởng (Care / Beneficiary) — Area 1

One line. Raw coordinator drops about a child (prose notes or school PDFs) are auto-converted into structured Block-3 progress notes + a benefits ledger + a safeguarding watchlist, all projected into so-dang-ky.sqlite and browsed through the private care-dashboard. The canonical record is the markdown under Ho-so/; the SQLite is a rebuildable projection. Humans own escalation + gate-8.

Triggers. A new child enters via the §1b survey-selection intake (admission → journey-NNNN) · coordinator uploads a drop to Tai-lieu-vao/<week>/<journey-id>/ · hourly intake-convert Job · manual dashboard add · daily 07:00 keyword + monthly full watchlist sweep · 28th transparency-CSV emit.

Walkthrough.

__hoc-ba/__so-diem/__chuyen-can/__hop-phu-huynh, or image) into Tai-lieu-vao/.

sanitises any image (EXIF/GPS, fail-closed), idempotent via _done__ rename.

PromoteEntry (date/title/source/petal/body, verbatim quotes only), prepended newest-first to the profile + a profile_entry row.

SchoolDocExtract; bounds-guard catches OCR slips (gpa 0–10, attendance 0–100, rank ≤ size, multi-child split); clean single-child auto-commits confirmed_by='auto' as a school_report row + linked note.

out-of-bounds is not written — appended to _needs-review.md for the weekly human pass.

watchword still writes, but its journey-id surfaces same-day.

flagged "promote" in the weekly review; if a watchword/disclosure warrants it the Coordinator escalates to safeguarding and passes --sg-cleared-by before invoking (a human gate, not a tool block).

validates the funding-source enum, mints a benefit_id, writes a ledger md + a benefit row.

benefit-anomaly, keyword, grade-drop, attendance-dip) → watchlist_item rows (action_taken NULL = open) + a monthly md.

re-surface) with a note. The human owns gate 8; signals never auto-resolve.

monthly spend, by-school) behind the single-admin login.

sync with the canonical markdown; 28th emits the HXL-CSV transparency export.

Cloud: care-dashboard (Service) · care-jobs (one image, HMT_CARE_JOB selects the tool) · 8 Scheduler entries · care-db bucket · shared care_auth secrets. Feeds: journey-writer (Stream C "journey miles") · Overview tiles · Finance (benefit.funding_source app-layer join — the "where it went" loop). Gaps: not yet mounted under /care; path drift — tools reference 10_Ho-so-thu-huong/ but the live cloud uses 10_Ho-so-thu-huong/ (stale literals); report_child/cohort/school.py are CLI-only, wired into no Job (the /reports page only lists pre-generated markdown).


4. 🟠 Tài trợ — gắn kết & liên lạc nhà tài trợ (Donor engagement & communications) — Area 3

One line. Everything about the donor relationship: a donor self-registers from a website/Facebook donate link → form → a personalised VietQR; the cash gift arrives by bank; a transactional thank-you + PDF receipt goes out (auto-sent, scoped relaxation); the donor joins the distribution list + watch list; refined-format newsletters and holiday/achievement appreciation keep the relationship warm; repeat donors get history-aware wording. (Workflow 2·Tài trợ from the 2026-06-02 comments; mockup: Donor engagement & communications.)

Triggers. Website/FB donate link → Activity-style donor Form submit (webhook) · 🔓 bank-credit notification (target: a SePay Open-Banking webhook on bank credit — candidate, see Gaps; today: NCB CSV import) · scheduled newsletter · special event (holiday / Foundation milestone / donor anniversary).

Walkthrough.

Cloud: donor-input Service (built, deploy-ready) · qr_donor / thank_you_draft / thank_you_record / update_recipient_* (code-complete) · so-tai-chinh.sqlite (donor + contribution + update_recipient). Feeds: Finance (§5, shares the contribution table) · the newsletter pulls from approved media posts (§2). Gaps: 🔓 transactional auto-send needs an SMTP path + the scoped-relaxation override recorded (today nothing auto-sends, no SMTP); the bank-credit trigger is unbuilt (today = manual CSV import) — candidate under review (2026-06-02, not decided): SePay Open-Banking webhook (sepay.vn) watches the account and fires a signed webhook (~10s) with amount + transfer note (HMT-D<NNNN>) + a stable txn id; a contribution_webhook endpoint would verify HMAC-SHA256, adapt the payload to the shape contribution_import_statement already emits, then run donor_matchcontribution_promote (idempotent on bank_txn_ref; SePay id = dedup key). A confirmed match is exactly the trigger the scoped receipt auto-send is defined against (receipts-only; SMTP still needed). Our qr_donor already mints the VietQR offline, so SePay's free QR generator is not needed. Confirm before adopting: Foundation owns the SePay account + bank connection (third-party processor of financial data, external legal/data handling), NCB supported, webhook-tier pricing. Newsletter + appreciation send is unbuilt (recipient lists are opt-in metadata only); Drive band 08_Quan-he-nha-tai-tro/ not provisioned (code still emits old 02_).


5. 🟠 Tài chính — minh bạch & quản lý phân phối (Finance transparency & distribution) — Area 4

One line. An initial input sets the opening financial position; thereafter financial statements are uploaded periodically, extracted, and turned into detailed internal reports on the hub; a high-level public summary (with supporting statements) is published to the website for transparency through the media QC + /approve gate, and can seed a media story. In-kind contributions sit in a separate ledger (items received, where/when distributed). Cash (VND) and in-kind (units) are never summed. (Workflow 2·Tài chính; §0.)

Triggers. Initial financial-position input · periodic statement upload (bank CSV / financial statement) · month-end reconciliation · at-confidence transparency publish · in-kind handover / disposal.

Walkthrough.

Cloud: finance_report_monthly / finance_report_publish / inkind_record / inkind_report_monthly / finance_anon_check (code-complete) · finance_dashboard (factory ready, mounts at /finance, not deployed) · so-tai-chinh.sqlite. Feeds: website transparency · media story seed (§6) · Care (in-kind disposals + cash funding). Gaps: whole subsystem unprovisioned/undeployed; the initial-position input + a general financial-statement extractor are unbuilt (today extract = NCB-CSV only); finance_dashboard has no login of its own (relies on the parent-hub gate — the literal “~50 lines”); receipt PDFs need weasyprint + GTK; F-zero/D-zero hand pilots before scale; sponsorship + payment-aggregator + SMTP parked.


6. 🟣 Kế hoạch nội dung (Content plan / editorial intelligence) — Stream B

One line. A 12-month theme roadmap + 3-month editorial board + a wide content-source palette, refreshed by a periodic planning agent that proposes, with computed self-flagging intelligence (orphan trips, 8-petal gaps, 80/20 value:ask drift, observance countdown). The Editor confirms slot-by-slot; picking a confirmed slot routes into the normal on-demand draft→QC→approve path. The /plan surface itself is read + route only — it never drafts and never posts.

Reality check — the least-built panel. The mockup /plan is static HTML with hardcoded numbers. None of these exist: content-plan.yaml (the only new data store), the planning agent, the hub /plan route + reader, the computed flags, registry.post rows (so every count reads zero), and Knowledge/Brand/facts.md (the agent's declared fact base, missing). Live today: content-calendar can draft individual evergreen bundles (none on disk). Phase 3, allowed to lag.

Decomposition (reconciled with the newsroom split + the 2026-06-02 on-demand reshape): a new content-strategist agent plans (proposes/refreshes content-plan.yaml periodically); the existing content-calendar drafts one picked slot into a bundle. Splitting keeps planning (synthesis, no vision) apart from drafting (Opus vision).

4.A — Periodic planning → propose → confirm

Cadence. A monthly anchor run rewrites the rolling 3-month board + re-checks the 12-month roadmap; a cheap weekly refresh only recomputes the intelligence flags. Phase-A safe — it writes a proposal, never a bundle.

Sourcing palette (the content scout, wider than trips+holidays, every source already in the workspace): (1) orphan-trip feed — events with media but no story, highest priority; (2) VN observances; (3) 8-petal / 8-activity coverage gaps; (4) journey milestones (Stream C, anonymised, no PII); (5) Foundation fact base facts.md (missing — prerequisite); (6) donor "where it went" follow-ups; (7) evergreen series (explainers, "one number that grows", spotlights, partner-school news, seasonal).

Steering. A directions: block of Editor-owned plain prose at the top of content-plan.yaml ("Q3 nhấn mạnh hướng nghiệp", "ít bài kêu gọi hơn"), read as a steering prompt before the agent proposes; every slot records what produced it (source · directed_by). Same pattern as the on-demand draft direction box, lifted to plan altitude.

Propose → confirm (per-slot gate). The agent only ever writes slots as status: idea. The hub shows them as a reviewable diff. The Editor confirms slot-by-slot, promoting idea → planned with a per-slot tick (the same human-tick discipline as dignity_ok). An unconfirmed idea slot cannot be drafted. Nothing auto-advances. Artifact: Sandbox/_content-plan/content-plan.yaml (directions + roadmap_12mo themes + board_3mo slots with type/source/status/petal; flags computed at read time, never stored).

4.B — Pick a slot → generate → save & register

Pick = the "Yêu cầu viết bài" button on a planned slot — the 2026-06-02 reshape generalised from field-trips-only to any plan item. The slot's type routes the producer: A (field event / orphan trip) → caption_draft (brief + culled renditions + direction box + optional photo-pick); B (evergreen / observance / explainer) → content-calendar (fact base + direction box + photo or quote-card template); C (journey milestone) → /journey (anonymised, no photo-pick by default).

Save & register (closing today's open loop): /approvepublish_pack manual pack (Phase A) → story_archive writes the human-readable record to 10_Cau-chuyen/<slug>/reuse the existing story archive; the provisional 09_Mang-xa-hoi/ band is NOT provisioned, the social-final vs story-record distinction is carried by registry.post tags, not a separate band → on posted_id, write a registry.post row (INSERT INTO post does not exist today — the gap that makes Presence read zeros) → flip the slot → posted, link posted_id back.

4.C — Photos from outside the field pipeline (the new seam)

Ingest only reads 01_Tai-lieu-thuc-dia. Stream-B and reuse need photos that never came from a field trip: reuse of past renditions (already in registry.asset, pick by reference); brand assets / graphics (03_Tai-san-thuong-hieu; quote-cards often need no photo); partner / third-party supplied (needs a permission / public-domain / attribution basis — blocking if absent); coordinator ad-hoc. The lane: an "Đính kèm ảnh" action drops files into source/ and must run media_sanitise (EXIF/GPS strip, gate 2) + a per-asset provenance sidecar (origin, supplied_by, license_basis, attribution_required). claim-checker already blocks reposted third-party media without a recorded basis. Firewall untouched — nothing crosses out; sanitised working media in-repo is allowed (workspace-ethics.md §1).

4.D — Filing, linking, suggestions, reminders

Two layers: the human-readable 10_Cau-chuyen/<slug>/ record, and the lineage/query layer registry.sqlite post table (powers the rest, once the 4.B writer exists). Each post row carries tagsactivity_type · petal · program · school · journey_id · theme · observance (petal_anchor must be validated against the 8 canonical petals). Three read-only features fall out: (1) "related stories" at draft time (prior posts sharing school/petal/program/journey-id — guards the "single story"); (2) suggestions back into the plan (content-strategist queries the rows for under-covered petals/activities → new idea slots, the intelligence flags now backed by real data); (3) reminders / follow-up loop (time queries → the Overview today-strip countdown).

Feeds: Stream-B production · Overview (countdown + suggestions) · Presence (shares the 80/20 + petal computation, and the registry.post writer it needs) · consumes the Trips orphan-trip feed. Gaps (build order): (1) facts.md fact base; (2) registry.post writer + tag columns + petal validation (unblocks Presence and 4.D); (3) content-plan.yaml + content-strategist; (4) hub /plan route + reader + flags; (5) external-photo lane. (3)/(4) depend on the unbuilt P2 trip/presence read-views.


7. 🔵 Hoạt động & Chuyến đi (Trips, khung nhìn đọc) + 📣 Hiện diện xã hội (Presence) — two native read-views

Lưu ý: đây là khung nhìn đọc trên Hub hiển thị các hoạt động — khác với §1 là luồng thu nhận tạo ra chúng. §1 ghi dữ liệu; §7 đọc và tổng hợp.

One line. Trips reconstructs a field-record ledger (one row per event over the Dashboard Sheet + brief.yaml + registry.sqlite photo counts) and flags orphan trips (media landed but no story shipped). Presence aggregates cadence / 80-20 value:ask / 8-petal coverage over the registry.post table + monthly recaps. Both compute, never store; nothing publishes.

Reality check. Neither route exists (app/hub.py unbuilt). The underlying field data (Dashboard Sheet, brief.yaml, registry.asset) is live, but registry.post + performance are empty (posts_published: 0) and no recap bundle exists — so Presence has near-zero real input today.

Walkthrough.

inside it + a cho-upload Dashboard row (the upstream record Trips reads). Target (§0): the Service also emails the folder link back to the submitter so they know where to upload (🟣 not built yet).

row.

date, outcome, petal) + registry.asset counts at the application layer (no ATTACH) into one ledger row per event.

reached approval/packed/published; shows photo count vs story state.

recaps to aggregate cadence (2–3/week), the 80/20 mix, per-petal coverage.

gaps — the same trailing-30-day logic quality-auditor already runs offline.

action stays in the review surface, not here.

Feeds: Content-plan (orphan + petal + 80/20 signals) · Overview today-strip · review queue (an orphan points back to the bundle). Gaps: routes unbuilt (P2); critical — nothing writes a post row (no INSERT INTO post anywhere; the manual-publish loop ends at publish.yaml + posted_id and never feeds back into SQLite), so Presence reads zeros until a post-row writer is built; petal_anchor in brief.yaml is free-text, not validated against the 8 canonical petals.


8. ⚪ Cộng đồng (Community) — Op1

One line. Approval-gated handling of FB comments/messages: cluster engagement, draft brand-voice replies a human must approve, hide+escalate safeguarding-sensitive comments, monthly engagement report. Intended only — nothing is implemented: no tool, no service, no data store, no app route, no FB ingest, no send path.

Reality check. The only real artifacts are the community-manager agent prompt, the /community skill markdown, community-ops.md (R1–R6), and Knowledge/Brand/faq-replies.md — itself a 6-stub placeholder with donate/ volunteer wording still pending Foundation P0. Zero engagement-report files exist.

Intended walkthrough.

library (never verbatim).

debate publicly.

press to leadership only.

escalations) + the R6 accountability follow-up loop.

Feeds: the AUDIENCE→RESOURCES "where it went / follow-ups" return edge of the loop; safeguarding escalations → the gate-8 owner. Gaps: the entire workflow is unbuilt (Phase 5, only when Op1 is built); the return edge of the operating loop is drawn but unwired — the loop does not actually close back to the audience today.


9. 🟣 Tổng quan (Overview) + the single-login parent shell

One line. The hub's front door: a single-login parent (app/hub.py) that aggregates summary counts and a "Cần bạn xử lý hôm nay" action strip by three independent DB reads stitched in Python (never ATTACH-joined), and routes the administrator into each area's own surface where the gates live. Not built — only mock HTML exists. The three sub-apps are real (review live, care deployed, finance built); the single-login primitive (care_auth) is live and already shared by review+care.

Walkthrough (planned).

fail-closed 303 to /login (no secrets configured = locked).

(care_auth.make_session; one account, username cosmetic).

awaiting-approval ("posts to approve") + revising. (FIELD→EDITORIAL leg.)

open watchlist (action_taken IS NULL) + needs-review intake backlog.

needs_thanks (thanked_at IS NULL). (RESOURCES leg closes the loop.)

intake) + per-area tiles. Cross-area facts stitched in Python, never by SQL JOIN across files. (The one proven cross-DB seam today is finance_report_monthly.build_report(care_db=...).)

editor approval) → publish_pack. The Overview can only count and link, never approve.

Cloud (planned): one management-hub Service, two gcsfuse mounts (/data=bundles bucket, /care-data=care-db), one service account on both, mounting review /review + care /care + finance /finance, replacing the standalone review + care services. Gaps: app/hub.py + Overview + login middleware don't exist (P1); /trips, /plan, /presence don't exist (P2/P3); finance_dashboard.create_finance_app has no auth params (the literal "~50 lines"); the two-bucket single-container deploy + Dockerfile is the real heavy lift (P4); template absolute-link audit (href="/bundle/..", /children/.., /donors/..request.url_for) is required before any mount.


10. Loop integrity — what holds, what is open

Built and load-bearing (the spine that works):

publish_pack** is the one complete, Phase-A-correct hand-off. Every panel agrees the single non-overridable gate is approve-with-dignity_ok, and the read-only panels correctly keep it out of the hub.

ATTACH-joined**; the one proven cross-DB read is finance_report_monthly reading the care DB read-only.

just needs the param plumbing.

The four open edges (ranked by importance):

no INSERT INTO post anywhere; the manual-publish loop ends at publish.yaml + posted_id and never back-fills registry.sqlite. Presence reads zeros indefinitely until this is built. This is the single most important gap.

code in the whole loop is mock HTML; everything "feeds Overview" feeds nothing yet.

board-emission, facts.md missing. The EDITORIAL leg the loop pivots on is the least real.

"where it went / follow-ups" loop-back does not close.

Smaller hazards: the headless pipeline runs only gate 1 + records gate-8-pending (agent gates 3–7 not invoked in the cloud path — automated QC is thinner than qc-enforcement.md implies; the human approval is the real check); Care path drift 01_ vs live 10_Ho-so-thu-huong/; two parallel decision write-paths (review app + Dashboard Sheet onEdit, both calling decisions_core, Sheet now secondary); video_edit orphaned from the daily photo-only chain.


Build order (from plan §7, with the operating reality folded in)

at /finance + finance auth-param wiring + finance template-link audit.

Add: a post-row writer so Presence/AUDIENCE has data (the #1 gap above — not currently called out in the plan).

create the missing facts.md.

two-bucket gcsfuse deploy; replace the old services after a full approve-flow smoke test.