尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
RCCG Youth Province 23 — Attendance Portal
Parish directory and weekly Sunday-attendance returns for the Ife and Ede
families, covering every Sunday from 6 September 2026 to 30 December 2029
— 174 Sundays.
• Parishes register themselves and submit one figure per Sunday. No login.
• Provincial admins sign in with email + password to see the charts, correct
figures, approve new parishes and add churches by hand.
React + TypeScript + Tailwind, Firebase (Firestore + Auth) for the backend,
deployed to Render as a static site.檢視完整 README ↗Parish directory and weekly Sunday-attendance returns for the Ife and Ede families, covering every Sunday from 6 September 2026 to 30 December 2029 — 174 Sundays.
React + TypeScript + Tailwind, Firebase (Firestore + Auth) for the backend, deployed to Render as a static site.
npm install
cp .env.example .env # then fill in the Firebase values — see step 2
npm run dev # http://localhost:5173
https://console.firebase.google.com → Add project.
Build → Firestore Database → Create database → production mode, region
europe-west or us-central (either is fine from Nigeria).
Build → Authentication → Get started → Email/Password → Enable. Leave "Email link" off.
Project settings → General → Your apps → Web app (</>). Copy the
firebaseConfig values into .env:
| Config key | .env variable |
|---|---|
apiKey | VITE_FIREBASE_API_KEY |
authDomain | VITE_FIREBASE_AUTH_DOMAIN |
projectId | VITE_FIREBASE_PROJECT_ID |
storageBucket | VITE_FIREBASE_STORAGE_BUCKET |
messagingSenderId | VITE_FIREBASE_MESSAGING_SENDER_ID |
appId | VITE_FIREBASE_APP_ID |
These are public by design — they identify the project, they don't grant
access. firestore.rules is what protects the data.
Paste the values bare. Copying them out of the
firebaseConfigobject drags the quotes and the trailing comma along, and dotenv only strips quotes when the value ends with one — soVITE_FIREBASE_API_KEY="AIza…",reaches Firebase with the punctuation still attached andgetAuth()throws before React can mount. That is the classic blank white page.VITE_FIREBASE_API_KEY=AIzaSyC… ✅ VITE_FIREBASE_API_KEY="AIzaSyC…", ❌
src/lib/firebase.tsnow strips stray quotes and commas defensively and shows an on-screen diagnosis instead of a blank page, but a clean.envis still the thing to aim for.
Publish the rules and indexes:
npm install -g firebase-tools
firebase login
firebase use --add # pick the project you just made
firebase deploy --only firestore:rules,firestore:indexes
No CLI? Paste firestore.rules into Firestore → Rules and publish, then
let Firestore prompt you to build the indexes the first time a query needs one.
Download a service-account key — Project settings → Service accounts →
Generate new private key — and save it as service-account.json in the project
root (already gitignored).
npm run make-admin -- [email protected] "AStrongPassword" # creates the login and grants access
npm run make-admin -- --list # who currently has access
npm run make-admin -- --remove [email protected] # revoke
Then sign in at /admin and press Load province directory on the Parishes
screen. That creates all 37 parishes with their zone and area from
src/data/provinceStructure.ts — no pastor names and no phone numbers,
because pastors enter their own (see below).
npm run seed is an older path that also loads pastor names and phones from a
local seed/parishes.json. That folder is gitignored and not part of the repo;
the directory button is the supported route.
Many Google Workspace organisations enable
constraints/iam.disableServiceAccountKeyCreation, and key download then fails
with "Key creation is not allowed on this service account." You do not need
a key. Two ways round it:
A. Application Default Credentials — keeps the scripts working.
gcloud auth application-default login
npm run seed
npm run make-admin -- [email protected] "AStrongPassword"
The scripts fall back to ADC automatically and read the project id from
VITE_FIREBASE_PROJECT_ID in .env. Nothing else changes.
B. Console + admin panel — no CLI at all.
firestore.rules, Publish. (Do this first —
until it is published, production-mode defaults deny everything.)admins → Document ID = that UID → add
one field, email (string) = your email. Save./admin.Console writes are authorised by your Google account through IAM, so they bypass the security rules; that is why step 3 works before you can sign in.
| Who | Enters | Where |
|---|---|---|
| Provincial admin | The parish list — names, zones, areas | Load province directory |
| Pastor in charge | Their own name and phone number | /register (once) |
| Pastor in charge | Parish, their name, phone, the Sunday, the figure | /submit (every week) |
No personal data ships in this repository — no pastor names, no phone numbers.
src/data/provinceStructure.ts holds church structure only: Province →
Location → Zone → Area → Parish.
Every submission refreshes the contact card. Name and phone come in with the
weekly return, so the province's contact list reflects whoever is actually in
charge rather than decaying to whoever held the parish in 2026. /register
exists only to seed a number before the first Sunday.
Addresses and ordination details are not collected from pastors at all; the admin panel can still record ordination status against a parish if the province wants it.
A parish the directory does not have yet goes in through "My parish is not
listed", and lands in the admin approval queue as pending.
Done — the official lockup lives at src/components/YP23.jpg and is imported by
src/components/Logo.tsx. To replace it, overwrite that file. See
public/brand/README.md.
Push to GitHub, then in Render: New + → Blueprint, point at the repo. It
reads render.yaml and creates a Static Site:
npm ci && npm run builddist/* → /index.html so /admin/dashboard survives a hard refreshAdd the six VITE_FIREBASE_* variables under Environment, then Manual
Deploy → Clear build cache & deploy. Vite inlines env vars at build time,
so changing a variable requires a new build — restarting does nothing.
Finally, add the Render domain to Firebase → Authentication → Settings → Authorized domains, or admin sign-in fails in production while working fine locally.
| File | What it is |
|---|---|
seed/parishes.json | All 37 parishes from the two directory PDFs, with the corrections noted inside |
seed/parishes.csv | Same data, in the exact column order the admin Import CSV button expects |
seed/attendance-template.csv | Backfill sheet for Admin → Attendance → Import CSV (matches parish by name) |
seed/sundays-2026-2029.csv | All 174 tracked Sundays with service-year labels |
Regenerate the last two with npm run gen-sundays.
Both are flagged in seed/parishes.json under notes:
GLORIOUS YOUTH ASSEMBLY AREA is printed in the Ede PDF after
PREVAILERS FORT AREA, but it is numbered area 3 and holds serial numbers
7–10 — i.e. it belongs before JESUS GRACE ZONE. It has been placed under
EXCEL (YOUTH CHURCH) ZONE. Fix it in Admin → Parishes if that is wrong.POWER CATHEDRAL and LIGHTHOUSE are the two newly planted Ife
parishes "yet to be fixed". They are seeded as pending with no zone, area
or pastor, so they sit in the approval queue until you fill them in.| Collection | Read | Write | Holds |
|---|---|---|---|
parishes | public | public create (forced pending), public one-time claim, admin edit | name, pastor, address, family/zone/area |
parishContacts | admin | public create once, admin edit | phone number only |
attendance | public | public create, admin edit/delete | one figure per parish per Sunday |
admins | admin | scripts only | the access list |
Phone numbers live in a separate collection because parish records must be publicly readable (the submission form needs the dropdown) and pastors' personal numbers should not be. Firestore has no field-level security, so splitting the document is the only way to get both.
Attendance document ids are {parishId}_{YYYY-MM-DD}. One return per parish
per Sunday, enforced by the database rather than by the form: a parish that
submits twice collides with its own first record instead of quietly
double-counting itself in the charts. Corrections go through an admin.
Dates are UTC YYYY-MM-DD strings throughout. A phone on WAT, a Render box
on UTC and a laptop anywhere else all agree which Sunday a figure belongs to.
The tracking window is defined in src/lib/sundays.ts and mirrored in
firestore.rules — change both together if the exercise is extended past
2029.
The mean of a parish's last few returns against the mean of its first few,
inside the selected date range (parishGrowth in src/lib/analytics.ts). A
plain first-vs-last comparison would let one freak Sunday — a convention, a
downpour, a joint service — flip a parish from growing to shrinking. The window
is 4 Sundays, automatically halved when a parish has fewer returns so the two
samples never overlap.
A flat stretch in the province chart usually means missing returns, not empty churches — which is why the dashboard also charts how many parishes reported each Sunday and lists who is outstanding.
src/lib/chartTheme.ts. The pairs were validated, not eyeballed:
#4055A0 / #B0851F for Ife/Ede (worst adjacent CVD ΔE 27.6) and #1B57A5 /
#C0392B for growth/decline (deutan ΔE 19.7). The obvious brand pair — navy
#2E3F81 with gold #C99A2E — was rejected: the navy fell outside the
lightness band and the gold came in at 2.51:1 against white. Green-for-growth
was rejected too; against red it collapses to ΔE 6.1 for deuteranopes.
src/
lib/ firebase, sundays (the date window), analytics, csv, chartTheme
hooks/ useParishes, useAttendance, useParishContacts
components/ Logo, Layout, AdminLayout, ProtectedRoute, ui primitives
pages/ Home, SubmitAttendance, RegisterParish, Directory
admin/ Login, Dashboard, ParishesAdmin, ParishDetail, AttendanceAdmin
scripts/ seed.mjs, make-admin.mjs, gen-sundays.mjs (firebase-admin)
seed/ the sample data files above
| Command | What it does |
|---|---|
npm run dev | Dev server on :5173 |
npm run build | Typecheck, then build to dist/ |
npm run preview | Serve the built dist/ locally |
npm run typecheck | tsc --noEmit |
npm run seed | Load seed/parishes.json into Firestore |
npm run make-admin | Grant / list / revoke admin access |
npm run gen-sundays | Regenerate the Sunday CSVs |