Read
All signed-in members
Write
Admin only
The central roster of every CERT member. Document IDs are auto-generated by Firestore. Each document represents one person and is the source of truth for contact info, certifications, and member status. Many other collections reference back here by document ID.
Active status is not a stored field — it is computed from oathdate. A member is considered active if their oath date is within the past 730 days (2 years). If no oath date is recorded, status defaults to inactive.
| Field | Type | Description |
| firstname | String | Member's first name. |
| lastname | String | Member's last name. |
| email | String | Member's email address. Used to match Firebase Auth sign-ins to member records. |
| phone | String | Member's phone number, stored as a formatted string. |
| street | String | Street address (e.g., "123 Main St"). |
| city | String | City of residence. |
| state | String | State abbreviation (e.g., "CT"). |
| zip | String | ZIP code. |
| joindate | String (YYYY) | Year the member joined Wilton CERT. Used for display only. |
| oathdate | String (YYYY-MM-DD) | Date the member took their CERT oath. Drives the active/inactive status calculation. A member is active if this date is within the past 2 years. |
| certifications | String[] | Array of certification labels held by this member. Controls what roles they can fill at events and what appears on the Officers page. Common values: Driver, TC (Training Captain), DC (Deployment Captain), DDC (Deputy DC), PC (Post Captain), Training Officer, Logistics Officer, Communications Officer, etc. Any value ending in Officer automatically appears on the officers roster. |
| notes | String | Free-text admin notes about the member. Only visible on the Members admin page. |
| uid | String | Firebase Authentication UID. Set automatically when an admin creates a sign-in account for the member. Not present on older or account-less records. |
| createdAt | Timestamp | Server timestamp set when the member record was first created. |
| updatedAt | Timestamp | Server timestamp updated on every save. |
Read
All signed-in members
Write
Admin only
Controls who has administrator access to the site. Document IDs are the member's email address in lowercase. When a signed-in user visits any admin page, the app looks up their email in this collection. If a matching document exists and active is not false, they are granted admin access.
To revoke admin access without deleting the record, set active to false. To grant access, create a document here with the member's lowercase email as the document ID.
| Field | Type | Description |
| active | Boolean | Whether this admin account is currently active. If missing, treated as true. Set to false to suspend access without deleting the record. |
| adminRole | String (optional) | Informational label for the admin's role (e.g., "super", "blog"). Not currently used to gate features — all active admins have equal access. |
Read
All signed-in members
Create/Update
Admin
Officers / event managers
Delete
Super only
The single collection for all CERT events — planned deployments, unplanned deployments, and training. The
type field distinguishes them. Document IDs are generated on creation as
YYYY - Event Name (e.g.,
"2026 - Pumpkin Parade"). Volunteer sign-ups and shift definitions are
not embedded here — they live in the separate
shifts and
signups collections, linked back by
eventId.
Three event types. type: "planned" and type: "unplanned" are managed on the Deployments Admin page; type: "training" on the Training Admin page. Member-facing pages filter by this field. Deployment Officers may create/edit planned & unplanned events; Training Officers may create/edit training events; event managers (listed in managerEmails) may edit their own event.
| Field | Type | Description |
| type | String | "planned", "unplanned", or "training". Controls which admin and member pages show the event and which officer role may manage it. |
| name | String | Event name as displayed to members. Part of the document ID. |
| date | String (YYYY-MM-DD) | Date of the event; used for sorting and display. |
| status | String | "open" — accepting sign-ups; "closed" — locked. TC/DC users do not see closed events. |
| location | String | Address or place name. For virtual training, a GoTo Meeting URL (meet.goto.com/…) that triggers the virtual-meeting UI. |
| description | String | Optional free-text shown to members on the sign-up page. |
| numPosts | Number (deployments) | Number of named field posts; controls the numbered post options in the roster post-assignment dropdown. |
| managers | Object[] | Event leaders. Each entry is { memberID, email, title } where title is DC / DDC / TC / DTC. Edited in the Managers section of the event form. |
| managerEmails | String[] | Lowercase emails of the current managers. Auto-computed from managers; used by Firestore rules to grant managers edit access without a members lookup. |
| documents | Object[] | Attached document references (name + URL) shown in the event's Documents section. |
Insurance Activation Fields
| Field | Type | Description |
| activation | String | "state" (default), "town", or "none" — the insurance activation type. Managed on the Insurance Activations page. |
| actStart | String (datetime-local) | Activation window start, e.g. "2026-06-29T07:00". Empty when activation is none. |
| actEnd | String (datetime-local) | Activation window end, e.g. "2026-07-06T19:00". |
| submitted | Boolean | Activation paperwork submitted to the insurer. |
| received | Boolean | Confirmation received back from the insurer. |
actAdmin scope. Holders of the actAdmin role may update only the five activation fields above (activation, actStart, actEnd, submitted, received) — the Firestore rules reject any other field change from that role.
Cascade delete. Deleting an event (super only) also deletes its
shifts and
signups. Events can instead be snapshotted to
eventBackups via the super-only Backup button.
Read
All signed-in members
Write
Admin
Officers / event managers
Shift definitions for events. One document per shift, linked to its event by eventId. Training events have a single shift; deployments may have several. Document IDs are {eventId}-{title}. Deleting a shift cascades to its sign-ups.
| Field | Type | Description |
| eventId | String | Document ID of the parent events record. |
| title | String | Shift name shown to members (e.g., "Morning", "Class"). |
| start | Timestamp / ISO string | Shift start time. |
| end | Timestamp / ISO string | Shift end time. |
| certsNeeded | Number | Target number of certified volunteers (display only — not a hard cap). |
| driversNeeded | Number | Target number of certified drivers for the shift. |
Read
All signed-in members
Create
Any signed-in member
Update/Delete
Admin
Managers
Self (own / unconfirmed)
One document per volunteer-shift pairing — the volunteer roster. Document IDs are {shiftId}-{memberID}, so a member can appear at most once per shift. Members create their own sign-ups; they may delete an unconfirmed one or update only confirmedAt / hoursLogged (rules-enforced). Admins and event managers may edit any sign-up.
| Field | Type | Description |
| eventId | String | Document ID of the parent events record. |
| shiftId | String | Document ID of the shifts record this sign-up is for. |
| memberID | String | Document ID from the members collection. |
| certRole | String | Role at this event: VOL, PC, DDC, DC (deployments), TC (training), or Driver. Defaults to VOL. |
| post | String (deployments) | Post assignment: "NA" (unassigned), a special code from specialCodes (e.g. "CC"), or a post number as a string. |
| truck | String | null | Assigned truck ID (from trucks) when certRole is Driver; otherwise null. |
| hoursLogged | Number | Hours credited to the volunteer for this shift (set on the roster/hours pages). |
| confirmedAt | String (ISO) | null | Timestamp set when the member confirms attendance on the sign-up page; null until confirmed. A confirmed sign-up can no longer be self-deleted. |
Read
All signed-in members
Write
Admin only
Stores all blog/activity posts. Document IDs are auto-generated. Six post types share this collection; some fields are only relevant to specific types.
Universal Fields (all post types)
| Field | Type | Description |
| title | String | Post headline displayed in lists and on the post page. |
| type | String | Post category. Controls layout and which sections appear. Values: planned, unplanned, training, weather, commendation, special. |
| date | String (YYYY-MM-DD) | Date of the event or post. Used for sorting and display. |
| summary | String | Short summary shown on the blog list page (1–2 sentences). |
| body | String | Full narrative of the event in plain text / basic markdown. Shown on the post detail page. |
| tags | String[] | Array of tag strings for filtering (e.g., ["Parade", "Traffic"]). |
| status | String | "published" — visible to all members; "draft" — only visible to admins on the blog admin page. |
| members | Object[] | CERT members who participated. Each entry: { id, name, role } where id references the members collection, name is a display string, and role is the role they held at that event. |
| otherAttendees | String[] | Free-text names of non-member attendees or partner agencies. |
| othersHeader | String | Section heading for the otherAttendees list (e.g., "Wilton Police Department"). |
| photoFolder | String | Firebase Storage path to this post's photo folder (e.g., blog-photos/blog_abc123). All uploaded images for this post live under this path. |
| createdAt | Timestamp | Server timestamp set on first creation. |
Type-Specific Fields
| Field | Type | Only for | Description |
| time | String | weather | Time of the weather event (e.g., "2:30 PM"). |
| pdfUrl | String | weather | URL to a PDF storm summary document. |
| personName | String | commendation | Full name of the person being commended. |
| personPhotoUrl | String | commendation | URL to a photo of the person being commended. |
| commendationUrl | String | commendation | URL to the commendation certificate or supporting document. |
| certMembers | String[] legacy | older posts | Display names of attendees in older posts, before the structured members object array was introduced. Still rendered on old post pages that pre-date the new format. |
Read
Public
Write
Admin only
Stores the elected board / leadership team. Shown on both the public Leadership page and the members-only Leadership & Bylaws page (with contact info on the members version). Document IDs are auto-generated. The footer also reads this collection to display the Executive Director's phone number. Managed on the Board of Directors admin page (board_admin.html), which also grants each active board member view-only access to CERT Finance by writing a financeOfficers/{email} entry with canWrite: false and viaBoard: true (resolved from the member's memberID → members email). Removing or deactivating a board member deletes that synced entry; manually-added Finance Officers (without viaBoard) are never touched.
| Field | Type | Description |
| firstname | String | Board member's first name. |
| lastname | String | Board member's last name. |
| role | String | Board position. Special values that control sort order: "Executive Director" (always first), "Deputy Executive Director" (always second), "Director" (sorted by term end date). |
| active | Boolean | Set to false to hide a member from the leadership display without deleting the record. Defaults to active if omitted. |
| termEnds | String (M/D/YYYY) | Term expiration date, e.g. "12/31/2029". Shown on the leadership card and used to sort Directors (soonest-expiring first). The Board admin page converts to/from the <input type="date"> format automatically. |
| memberID | String | Document ID from the members collection. Used on the members-only page to fetch the board member's phone and email for the contact modal. |
| phone | String | Phone number. Read by the site footer to show the Executive Director's contact number in the footer contact block. |
Read
Public
Write
Admin only
A denormalized snapshot of appointed officers for the public leadership page. Because the public page cannot access the members collection (sign-in required), this collection holds a pre-computed copy of officer data. It is populated and kept in sync by the Sync Officers admin tool, which scans the members collection for any certification ending in "Officer" and writes a record here for each one.
Do not edit this collection manually. Use the Sync Officers admin tool after updating member certifications. Manual edits will be overwritten the next time the sync runs.
| Field | Type | Description |
| firstname | String | Officer's first name (copied from members). |
| lastname | String | Officer's last name (copied from members). |
| role | String | Officer title derived from their certification (e.g., "Training Officer", "Deputy Logistics Officer"). |
| active | Boolean | Whether this officer is currently shown on the leadership page. Set by the sync tool based on member active status. |
| sortOrder | Number | Display order on the leadership page. Set by the sync tool based on role name and deputy status. |
| memberId | String | Document ID from the members collection that this officer record was generated from. |
Read
All signed-in members
Write
Admin only
A lookup table that maps role abbreviations to human-readable labels, used in blog post creation and display. If a read fails, the app falls back to a hardcoded default list.
| Field | Type | Description |
| abbrev | String | Short role code displayed on volunteer rosters and blog posts. E.g., VOL, TC, DC, DDC, PC, DTC. |
| label | String | Full human-readable label. E.g., "Volunteer", "Training Captain", "Deployment Captain". |
| sortOrder | Number | Display order in role selection dropdowns. |
Read
All signed-in members
Write
Admin only
Named special post assignments for deployment events, shown in the post-assignment dropdown on the volunteer roster. Instead of being assigned to a numbered field post, a volunteer can be assigned a special post like "CERT Command." The default fallback if the collection is empty or unreadable is a single entry: CC — CERT Command.
| Field | Type | Description |
| code | String | Short code stored in the volunteer's post field (e.g., "CC"). |
| label | String | Full description shown in the dropdown (e.g., "CERT Command"). |
| sortOrder | Number | Order in which codes appear in the dropdown, before the numbered posts. |
Read
All signed-in members
Write
Admin only
Stores language capabilities of CERT members, used on the Languages member page. This collection supports the community multilingual resource directory.
Read
Public
Write
Admin only
Site-wide configuration. Currently used for theme overrides. The document settings/theme can contain CSS variable overrides that are applied globally. Public-readable so that theme settings apply to the public-facing pages as well.
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Per-category budget lines for the finance system, one document per category per fiscal year. Document IDs are
stable:
{fy} - {name} at creation — renaming changes the
name field but keeps the same id, so
arLines referencing the id stay linked. The FY
total budget is NOT stored here — it is derived from funding sources (see
sourceLines).
| Field | Type | Description |
| fy | String | Fiscal year, e.g. "2026". |
| name | String | Category name (e.g., "Equipment", "Training"). |
| budget | Number | Budgeted dollar amount for this category in this fiscal year. |
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Funding
sources (the "Sources" side of Sources & Uses) — grants, town allocations, donations. Document IDs are
{fy} - SRC-nnn. Each source's dollar amounts live in
sourceLines; the sum across non-deleted sources is the FY total budget.
| Field | Type | Description |
| fy | String | Fiscal year. |
| sourceNumber | Number | Sequential source number within the fiscal year (SRC-001, …). |
| sourceType | String | "Town", "Cat. A Grant", "Donation", or "Other Grant". |
| date | String (YYYY-MM-DD) | Source date; the fiscal year is derived from it. |
| status | String | "open" or "funded". |
| description | String | Free-text label for the source. |
| deleted | Boolean | Soft-delete flag; deleted sources are excluded from totals but can be restored. |
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Line items belonging to a funding source. Document IDs are {sourceId} - L{n}. The sum of these amounts across non-deleted sources is the derived FY total budget.
| Field | Type | Description |
| fy | String | Fiscal year (copied from the parent source for querying). |
| sourceId | String | Document ID of the parent certFunding source. |
| line | Number | Line order within the source. |
| amount | Number | Dollar amount of this funding line. |
| useType | String | "General", "Training", or "Equipment" — the coarse "use" bucket. |
| arRef | String | Optional reference to an appropriationRequests doc this funding is tied to (scoped to the source's FY). |
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Vendor list used to auto-complete the Vendor field on AR line items. Auto-generated document IDs.
| Field | Type | Description |
| name | String | Vendor name. New vendors are created on the fly when typed into an AR line. |
| active | Boolean | Set to false to hide a vendor from the picker without deleting it. |
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Appropriation Requests (ARs) — the "Uses" side of the budget: spending requests. Document IDs are
{fy} - AR-nnn. Line items live in
arLines; the AR total is the sum of its line costs.
| Field | Type | Description |
| fy | String | Fiscal year, derived from date via the configured fiscal-year-end. |
| arNumber | Number | Sequential AR number within the fiscal year. |
| date | String (YYYY-MM-DD) | Request date; determines the fiscal year. |
| requesterMemberId | String | Document ID of the requesting members record. |
| requesterName | String | Cached requester name for display. |
| description | String | Short description of the request. |
| status | String | Workflow status of the request (e.g., open). |
| notes | String | Free-text notes. |
| deleted | Boolean | Soft-delete flag; deleted ARs are excluded from totals and Budget vs Actual but keep their lines and can be restored. |
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Line items belonging to an Appropriation Request. Document IDs are {arId} - L{n}. Deleting an AR cascades to its lines.
| Field | Type | Description |
| fy | String | Fiscal year (copied from the parent AR for querying). |
| arId | String | Document ID of the parent appropriationRequests. |
| account | String | The category ID from budgetCategories (a stable id, not the display name) — so renaming a category updates everywhere. |
| vendor | String | Vendor name (matched against vendors). |
| description | String | Line description. |
| quantity / amount / cost | Number | Unit quantity, unit price, and extended cost (quantity × amount). |
| basis | String | "actual" or "forecast". |
| booking | String | "booked", "notBooked", or "placeholder". |
| link / notes | String | Optional reference link and free-text notes. |
| invoices | Object[] | Attached invoice files (PDF/PNG/JPG) — each { name, url, path } in Firebase Storage under ar-invoices/. |
ReadAdmin / finance roleFinance Officers
WriteAdmin / finance roleFinance Writers
Open purchase orders / encumbrances. Encumbered amount is derived (total − expensed). Auto-generated document IDs.
| Field | Type | Description |
| fy | String | Fiscal year. |
| poNumber | String | Purchase order number. |
| vendor | String | Vendor name. |
| total | Number | Total PO amount. |
| expensed | Number | Amount already expensed; remainder is encumbered. |
ReadAll signed-in members
Create/UpdateAdmin
DeleteAdminSelf
Grants finance access to people who are not full admins. Document ID is the member's
lowercased email. Entries are added either manually or automatically by the
board admin page (which grants board members view-only access).
| Field | Type | Description |
| email | String | The member's email (also the document ID). |
| canWrite | Boolean | Whether this officer may edit finance data. Defaults to true when omitted (legacy entries keep full access). false = read-only (e.g., board members). Enforced by Firestore rules. |
| viaBoard | Boolean | true if created by the board sync. Only viaBoard entries are auto-removed when a board member is removed/deactivated — manually-added officers are never touched. |
| memberID / name | String | For board-synced entries: the linked member's ID and display name (reference only). |
ReadAll signed-in members
Create/UpdateAdmin
DeleteAdminSelf
Three certification-synced access collections, each keyed by
lowercased email. They are populated by the
Sync Officers tool, which scans
members for the matching "Officer" certification and writes an entry. Membership in a collection grants the scoped power:
deploymentOfficers may create/edit planned & unplanned
events;
trainingOfficers may create/edit training events;
membershipOfficers may create/edit
members and
memberEmails. (See also
financeOfficers, documented separately because of its read/write field.)
| Field | Type | Description |
| email | String | The officer's email (also the document ID). The presence of the document is what grants access — no other fields are required. |
GetPublic (single doc)
ListDenied
WriteAdmin / emailAdminMembership Officers
A public-readable mirror of member email addresses, keyed by
lowercased email, used by the sign-in screen to check whether an email belongs to a member without exposing the full
members collection. It is also the
membership gate for the security rules: because Google sign-in creates a Firebase Auth account for any Google user, reads of member data (events, members, signups, shifts, …) require the signed-in email to exist here (or in
administrators, for org accounts with no member record). Single-document
get is allowed publicly; listing the whole collection is denied. Kept in sync when members are imported/edited.
| Field | Type | Description |
| email | String | The member's email (also the document ID). |
ReadAdminSelf
WriteSelf only
Login activity self-reported by each user on sign-in. Document ID is the lowercased email. A user may only write their own document (rules validate the field set); admins can list/read/delete all. Powers the Login Activity admin page.
| Field | Type | Description |
| email | String | The user's email (also the document ID). |
| createdAt | String (ISO) | When the activity record was first created. |
| firstLoginAt | String (ISO) | First recorded sign-in (optional). |
| lastLoginAt | String (ISO) | Most recent sign-in. |
ReadPublic
WriteAdmin
Organization info, stored in a single document certInfo/main. Read everywhere (including public pages); edited on the CERT Info admin page. The fiscalYearEnd drives every fiscal-year calculation in the finance system.
| Field | Type | Description |
| certName | String | Organization name. |
| fiscalYearEnd | String (MM-DD) | Fiscal year end, e.g. "06-30". Required by the finance system. |
| logo | String | Path/URL to the logo image; defaults to assets/CERT_Logo.jpg. |
ReadAll signed-in members
WriteAdmin
CERT vehicles/trucks that can be assigned to drivers on a deployment roster (referenced by
signups.truck).
| Field | Type | Description |
| name | String | Truck label shown in the driver-assignment dropdown. |
| active | Boolean | Set false to hide a retired truck without deleting it. |
| sortOrder | Number | Display order in the dropdown. |
ReadAdmin
WriteAdmin
CERT equipment/asset inventory, managed on the Inventory admin page.
| Field | Type | Description |
| name | String | Item name. |
| quantity | Number | Count on hand (may be blank). |
| status | String | "Active" or "Inactive". |
| (additional) | String | Other descriptive fields (e.g., category, location, notes) as captured on the inventory form. |
Read/Create/UpdateAdminDeployment Officers / managers
DeleteAdmin
Physical sign-in/out records with signatures for a deployment shift. Document IDs are
{shiftId}-{memberID}, mirroring a
signups record. Drives the printed roster and hours logging.
| Field | Type | Description |
| eventId / shiftId / memberID | String | Links back to the event, shift, and member. |
| signedInAt / signedOutAt | Timestamp | Sign-in and sign-out times. |
| signatureIn / signatureOut / safetySig | String (data URL) | Captured signature images. |
| hoursLogged | Number | Hours credited for the shift. |
| processedAt | Timestamp | When hours were finalized/processed. |
ReadAdmin
WriteSuper only
Single-document snapshots of a deployment, kept out of the live
events collection. Created by the super-only Backup button; the document ID matches the original event ID. Re-running a backup overwrites it.
| Field | Type | Description |
| originalId | String | Document ID of the event that was backed up. |
| backedUpAt | String (ISO) | When the snapshot was taken. |
| event | Object | Full copy of the event document. |
| shifts / signups / equipment | Object[] | Copies of the event's shifts, sign-ups, and equipment at backup time. |
CreateAnyone
Read/Update/DeleteAdmin
Outbound email queue for the Firebase Trigger Email extension — writing a document here sends an email. Used for notifications such as password-reset alerts.
| Field | Type | Description |
| to | String | String[] | Recipient email address(es). |
| message | Object | { subject, html } — the email subject and HTML body. |
CreateAnyone
Read/Update/DeleteSigned-in members
Submissions from the public "Join CERT" / interest form. Anyone may create a submission; signed-in members can review and manage them. Auto-generated document IDs.
| Field | Type | Description |
| (applicant fields) | String | Name, email, phone, and any message/answers captured by the join form. |
CreateAnyone (validated)
Read/DeleteAdmin
UpdateDenied
Log of password-reset requests made from the sign-in screen. Create is open but the rules strictly validate the field set and sizes; documents are immutable once written.
| Field | Type | Description |
| email | String | Email that requested the reset. |
| requestedAt | String (ISO) | When the request was made. |
| matchesMember | Boolean | Whether the email matched a known member (optional). |
| source / requestedBy | String | Where the request originated and who initiated it (optional). |
ReadAll signed-in members
Create/UpdateAdmin
DeleteSuper only
Miscellaneous internal configuration documents. A key collection — only super may delete.
| Field | Type | Description |
| (varies) | — | Document shape depends on the config key. |
Read/Create/UpdateAdmin
DeleteSuper only
Tracks the current program year for the rewards system. The document seedYear/current holds the active year.
| Field | Type | Description |
| year | Number | The current rewards program year. |
Member Identity
A member's Firestore document ID is the link between collections. signups.memberID, events.managers[].memberID, board.memberID, blog-posts.members[].id, and officers.memberId all reference the members collection by this ID.
Admin Access Gate
The administrators collection is keyed by lowercase email. When any admin page loads, the app calls checkIsAdmin(db, user) which does a single Firestore read to administrators/{email}. No email match = no access.
DC/TC Access Gate
Event managers (Deployment Captains, Training Captains, and their deputies) are identified by their email appearing in events.managerEmails — auto-recomputed from the events.managers array (each { memberID, email, title }) whenever managers change. Firestore rules grant a manager edit access to their own event by checking this array.
Officers Sync
The officers collection is a public-readable copy of data from members. Any member certification ending in "Officer" generates an entry. Run the Sync Officers tool after editing member certifications to keep them aligned.
Active Member Status
There is no active field on member records. Active status is computed on the fly: oathdate within the past 730 days = active. Missing or older oath date = inactive. Update oathdate after re-certification to restore active status.
Photo Storage
Blog post photos are stored in Firebase Storage, not Firestore. The Storage path is blog-photos/blog_{postId}/{filename}. The Firestore document stores only the folder path in photoFolder; the app lists files from Storage at runtime.