Software Requirements Specification (SRS)
FLA Event & Awards Platform β plain PHP, modular, subdomain-hosted.
Living document: every feature planned or built gets its use case recorded here
(rule in WORKFLOW.md). View this file in the browser at/docs/srs.
| Field | Value |
|---|---|
| Product | FLA Event & Awards Platform (working title "Event") |
| URL | https://event.production1.jugaar.ai (plain 443 HTTPS β no ports, no localhost) |
| Stack | PHP 8.3 (plain, no framework) Β· MariaDB 10.11 Β· Nginx Β· GD |
| Version | 3.0.0 (Ceremony Production System) |
| Status | Draft β living |
| Last updated | 2026-08-29 |
1. Introduction
1.1 Purpose
Define everything the platform must do, in business use-case language, so that:
- the owner knows exactly what is being built and in which order;
- any (new) development session can resume work from this file +
TODO.md; - each feature has one authoritative flow description (linked workflow docs).
1.2 Scope
A modular web platform for events whose flagship capability is public-voted, AI-assessed awards. Branding (name, logo, colors, campaign texts) is managed from an admin Control Panel β nothing brand-related is hardcoded. The platform is a single-tenant deployment on its own subdomain.
Out of scope (v1.x): payments/ticketing for paid events (not requested), native apps, multi-tenant SaaS operation.
1.3 Definitions
| Term | Meaning |
|---|---|
| Applicant | Person registering for an award category |
| GoH | Guest of Honor (C-level: CIO etc.) invited/approved to give awards |
| Voter | Public person who votes via a shared link; verified via LinkedIn |
| Judge | Panel member reviewing applicants in the review board |
| Staff | Team members (comms, manual entries, ticket replies) |
| Admin | Owner-level access; finalize results, veto, all visibility |
| Share link | https://event.production1.jugaar.ai/v/{public_token} per applicant |
| Share card | Generated PNG for social posting (applied / visiting / winner) |
| Mock mode | Running with simulated AI/LinkedIn/WhatsApp until API keys exist |
1.4 References
ROADMAP.mdβ milestone plan Β·TODO.mdβ live session handoffdocs/WORKFLOWS/*.mdβ step-by-step flows (voter flow, judge flow, β¦)WORKFLOW.mdβ engineering + git + documentation rules
2. Overall Description
2.1 System context
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Public ββββββββΊβ https://event.production1.jugaar.ai (Nginx :443 β PHP) β
(browser, β β
mobile) β βββββββββββ βββββββββββββ ββββββββββ βββββββββββββββ β
β β Brandingβ β Registrationβ βVoting β β Judges/ β β
LinkedIn OAuth β β Control β β (3 types) β β (70%) β β Winners β β
βββββββββββββββΊβ β Panel β βββββββ¬ββββββ βββββ¬ββββ βββββββββββββββ β
β βββββββββββ β β β
MiniMax m3 AI β βββββββββββββββββββ΄ββββ βββββ΄βββββββββ β
βββββββββββββββΊβ β AI gateway (mock/ β β Audit log β β
β β live) β β (append-only) β
WhatsApp API β ββββββββββββ¬βββββββββββ ββββββββββββββ β
βββββββββββββββΊβ β β
(later) β MariaDB (fla_event) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2.2 Key decisions (locked)
| # | Decision | Value |
|---|---|---|
| D1 | Stack | Plain PHP 8.3, modular (src/Core + src/Modules/*), no framework |
| D2 | DB | MariaDB fla_event (installed host) |
| D3 | Deployment | Subdomain https://event.production1.jugaar.ai on plain 443 |
| D4 | Branding | DB settings table, edited in Control Panel, defaults until configured |
| D5 | AI | Provider gateway; default driver MiniMax platform model minimax-m3; mock until keyed |
| D6 | OIDC client; mock fixture in dev | |
| D7 | Abstract gateway; Null driver (logged no-op) until provider + keys | |
| D8 | Share cards | GD driver now; AI image driver reserved (ApiCardDriver) |
| D9 | Voting math | 70% aggregate public + 30% board; admin veto absolute (BR-005) |
| D10 | Docs | Repo .md files are the single source; /docs renders them as webpages |
| D11 | Charts | Chart.js via CDN + internal JSON endpoints (no build step); ASCII/empty-state fallback without JS |
2.3 Assumptions & constraints
- One person = one registration per event (BR-001); identity anchor is the LinkedIn profile.
- Voters must authenticate with LinkedIn (other providers may be added later).
- WhatsApp number is mandatory for award/GoH registrations (BR-007).
- The platform must keep working without external keys (NFR-08 mock mode).
- Every sensitive action is audit-logged (NFR-03).
3. Actors
| Actor | Description | Access |
|---|---|---|
| Guest | Unauthenticated visitor | Landing, docs, public results, vote links |
| Visitor | Registered attendee | "I'm visiting" card, event info, dashboard-lite |
| Applicant | Award candidate in one category | Own votes + voters, AI interview, tickets, share cards |
| Voter | Authenticated via LinkedIn | Cast vote (+ optional reason) per rules |
| Judge | Assigned reviewer | Review board: profiles, AI stats, approve/disapprove |
| GoH | C-level guest presenting awards | Approval-based registration; profile |
| Staff | Team support | Manual entries, tickets, mass comms, shared dashboards |
| Admin | Owner | Everything incl. toggles, categories, veto, finalize, audit UI |
| System/AI | Automated actors | AI marking, badge generation, notifications, announcements |
4. Business rules
| ID | Rule |
|---|---|
| BR-001 | One person may hold exactly one registration per event (DB unique (event_id, user_id)). |
| BR-002 | An award applicant cannot also be Guest of Honor in the same event (and vice versa). |
| BR-003 | Voting default: one vote per LinkedIn profile per candidate; admin may relax/change per event β logged. |
| BR-004 | Final score = 70% public-vote share + 30% board score, normalized per category. |
| BR-005 | Admin veto is absolute: admin may exclude any applicant at any stage; audit-logged with reason. |
| BR-006 | An applicant sees own vote count and voter identities only β never others'. Only admin sees the global leaderboard before finalization. |
| BR-007 | WhatsApp number is required for award and GoH registrations. |
| BR-008 | Registration prefers LinkedIn OAuth; voters must authenticate with LinkedIn. |
| BR-009 | Winners are announced by the system only after admin approval + audit lock. |
| BR-010 | AI interview: category-scoped questions drawn randomly from the active bank; answers AI-marked; stats attached to the applicant. |
| BR-011 | Repeat-candidate surveillance: every registration is scanned against all registrations across events (email, LinkedIn, CNIC-hash, name+WhatsApp, repeat-application). Any match β flagged + admin alerted; admin confirms (auto-veto) or dismisses. |
5. Functional requirements
FR-0100 β Platform, Branding & Docs
| ID | Requirement | Module |
|---|---|---|
| FR-0101 | Admin edits branding: name, logo, tagline, primary color, favicon β live everywhere | Branding |
| FR-0102 | Admin toggles features on/off (per module) without deploys | Branding/Admin |
| FR-0103 | All repository .md docs rendered as organized webpages under /docs | Docs |
| FR-0104 | Campaign texts for share cards edited in admin (placeholders {event} {name} {category}) | Branding |
| FR-0105 | Base URL = subdomain on plain 443; absolute_url() used for share links | Core |
FR-0200 β Events & Categories
| ID | Requirement | |
|---|---|---|
| FR-0201 | CRUD events: name, type (normal / ai / award), dates, venue, status lifecycle | |
| FR-0202 | CRUD award categories per event: name, description, show/hide (is_active), sort order | |
| FR-0203 | Categories shown publicly only when active; admin chooses what displays | |
| FR-0205 | Event cloning: one-click copy of event + categories + question bank as a new draft | |
| FR-0210 | Event templates: snapshot an event (categories + questions + scoring) as a named reusable template; one-click draft creation from it | Events |
| FR-0211 | Calendar export: .ics per public event ("Add to calendar") | Events |
| FR-0212 | Event package export: admin JSON download (event, categories, questions, registrations, votes incl. removals, winners, snapshots, audit) | Events/Admin |
| FR-0213 | Recurring events: weekly/monthly + optional repeat-until; next occurrence auto-drafted (categories + question bank copied) when the current one finishes; parent linkage | Events |
| FR-0204 | Public events directory (/events) with live + archive sections | |
| FR-0106 | Maintenance mode (site.maintenance): public site returns 503 with custom message; admin/staff bypass |
FR-0300 β Registration (v0.4.0)
| ID | Requirement |
|---|---|
| FR-0301 | Two public entry paths: "Register as Visitor" and "Apply for an Award" (separate links OK) |
| FR-0302 | LinkedIn OAuth signup preferred; system captures id, name, email, picture |
| FR-0303 | Fallback basic form: name, email, WhatsApp (+ passwordless) |
| FR-0304 | Award flow: pick category β info β WhatsApp β photo (optional at signup, required before approval; may be completed later on dashboard) β AI interview |
| FR-0305 | GoH flow: title/company/bio/photo (optional at signup, required before approval); approval-based; staff may enter manually (incl. government guests) |
| FR-0305b | Decision messages: approve/reject β in-app + email + SMS (log transports) for all types; GoH submit confirmation email+SMS |
| FR-0306 | Staff manual entry "on behalf of" for any type (entered_by_user_id) |
| FR-0307 | Enforce BR-001/BR-002/BR-007 with clear errors |
| FR-0308 | Photo stored under storage/uploads, bound to registration; may be uploaded at signup or later via POST /dashboard/photo; required before approved (single+bulk) |
| FR-0309 | Basic (non-LinkedIn) signups get an email-verification link; verified flag tracked |
| FR-0310 | GET /verify-email?token=β¦ completes verification; unverified badge visible to admin |
FR-0400 β AI Engine (v0.5.0)
| ID | Requirement |
|---|---|
| FR-0401 | Question bank per category, admin-managed, active flag |
| FR-0402 | Interview session: N random active questions (default 5), one at a time |
| FR-0403 | Each answer AI-marked (score 0β100 + feedback); session total + summary |
| FR-0404 | Stats shown on applicant dashboard + judges board |
| FR-0405 | Non-AI ("normal") events skip the interview entirely (normal registration OK) |
| FR-0406 | Provider-swappable gateway; mock mode until key; cost/logging of calls |
FR-0500 β Public Voting (v0.6.0)
| ID | Requirement |
|---|---|
| FR-0501 | Applicant gets personal share link + dashboard to copy it |
| FR-0502 | Vote page: candidate card (photo, name, category, AI summary if enabled) |
| FR-0503 | Voter authenticates via LinkedIn before voting (BR-008) |
| FR-0504 | Optional one-line reason ("what is this person good at") β toggleable per event |
| FR-0505 | Enforce voting restrictions; friendly errors; duplicate attempt shown as already-voted |
| FR-0506 | 70/30 weighting engine computes blended score on demand (BR-004) |
| FR-0507 | Admin veto action UI (BR-005) with mandatory reason β audit |
| FR-0508 | Applicant sees own votes + voters (BR-006); public leaderboard optional/admin-only pre-final |
| FR-0509 | Per-event vote-change toggle: when enabled, voters can update reason / move their vote (audited vote.changed); default: votes are final |
| FR-0510 | Share links support ?ref= attribution, persisted through OAuth onto the vote row; applicant sees channel breakdown |
FR-0600 β Share Cards (v0.6.0)
| ID | Requirement |
|---|---|
| FR-0601 | Generate PNG cards: applied / visiting / winner from photo + campaign text |
| FR-0602 | GD driver default; AI driver pluggable (cards.driver) |
| FR-0603 | Card + share link packaged for LinkedIn/FB posting (Open Graph tags on vote page) |
| FR-0604 | Finalist certificate cards (PNG) generated for finalists after results lock |
| FR-0605 | Printable certificates (winner/finalist) β print/PDF-ready HTML page |
FR-0700 β Judges Panel (v0.7.0)
| ID | Requirement |
|---|---|
| FR-0701 | Admin creates judge accounts + assigns event/category scope |
| FR-0702 | Judges board: list contestants in scope w/ profile, photo, AI stats, media |
| FR-0703 | Judge decision per contestant: approve / disapprove / needs info + notes |
| FR-0704 | Compiled report β main admin (per category: votes, AI score, judge tallies) |
| FR-0705 | Admin can re-issue team passwords (judge/staff): new temp password, forced change on next login, audited |
| FR-0706 | Judge rubric: per-review 0β10 scores (innovation/impact/leadership) feed the board score as avg/30; legacy reviews fall back to approval ratio |
FR-0800 β Dashboards (v0.8.0, starter in v0.2.0)
| ID | Requirement |
|---|---|
| FR-0801 | Applicant: votes over time (chart), voter list (own), AI results, notifications, tickets, share cards |
| FR-0802 | Staff: queues (tickets, pending manual entries), comms tools |
| FR-0803 | Admin: comprehensive β registrations, votes, AI, judges, comms, audit, toggles |
| FR-0804 | Reminders/notifications surface on dashboards (FR-1200) |
| FR-0805 | Admin graphs: votes-over-time, registration funnel, per-category vote shares, top-10 candidates, AI score distribution β Chart.js (CDN) fed by internal JSON endpoints |
| FR-0806 | Admin stats coverage: KPI cards with trend deltas (7d/30d) β users by role, registrations by type/status, votes cast, AI interviews run, judge reviews done, tickets by status/age, comms delivery rates β all filterable by event/category/date |
| FR-0807 | Audit tab on admin dashboard: live audit-log feed with filters (actor, action, entity, date) β FR-1102 UI |
FR-0400 β AI Engine (v0.5.0)
| ID | Requirement |
|---|---|
| FR-0401 | Question bank per category, admin-managed, active flag |
| FR-0402 | Interview session: N random active questions (default 5), one at a time |
| FR-0403 | Each answer AI-marked (score 0β100 + feedback); session total + summary |
| FR-0404 | Stats shown on applicant dashboard + judges board |
| FR-0405 | Non-AI ("normal") events skip the interview entirely (normal registration OK) |
| FR-0406 | Provider-swappable gateway; mock mode until key; cost/logging of calls |
| FR-0407 | AI admin insights (v0.5.0+): natural-language summaries per applicant ("judge-ready brief"), weekly event summary for admin ("what changed this week"), vote-anomaly flags (bursts/single-IP clustering summarized by AI). All mock-compatible via the AI gateway |
FR-0900 β Ticketing & Mass Comms (v0.8.0)
| ID | Requirement |
|---|---|
| FR-0901 | Applicants/visitors open tickets; staff reply in thread; statuses tracked |
| FR-0902 | Mass communication to audiences (all/visitors/applicants/goh/category/status) |
| FR-0903 | Channels: email first; WhatsApp when provider keys arrive (numbers already collected) |
| FR-0904 | Public media/gallery sections per event |
FR-1000 β Winners (v0.9.0)
| ID | Requirement |
|---|---|
| FR-1001 | Finalize per category: blend 70/30 + judge results β shortlist |
| FR-1002 | Admin approves β audit lock β system publishes winners (BR-009) |
| FR-1003 | Winner badges + "Winner" share cards auto-generated |
| FR-1004 | Public results page + notifications to winners |
| FR-1005 | Category results can be un-locked (retract public results, winnersβfinalist, eventβjudging) β fully audited; re-lock replaces the snapshot |
| FR-1006 | Hall of fame (/hall-of-fame) β every winner across finished events |
| FR-1007 | Ceremony reveal mode: per-event toggle; locked categories revealed one-by-one (audited winner.revealed); results page, venue screen and API gated until revealed |
FR-1100 β Audit (v0.9.0)
| ID | Requirement |
|---|---|
| FR-1101 | Append-only audit log (actor, action, entity, ip, meta, time) |
| FR-1102 | Admin filter/search UI; no edit/delete of audit rows |
FR-1300 β Integrity & anti-fraud (v1.1.0)
| ID | Requirement |
|---|---|
| FR-1301 | Signal collection: normalized email, LinkedIn id/URL, CNIC (hash-only, salted SHA-256 β plain never stored), name+WhatsApp pair |
| FR-1302 | Scan on every registration (public, manual entry, claim) against all events + same-account repeat detection |
| FR-1303 | Alerts: duplicate_alerts rows + in-app notification to all admins + audit entry |
| FR-1304 | Admin review queue /admin/duplicates: side-by-side comparison β confirm (auto-veto new) or dismiss |
| FR-1305 | Visibility: β dup badge + filter on registrations list, open-alerts KPI on admin overview |
| FR-1700 | Data rights: member can download their data as JSON and irreversibly anonymize their account (PII stripped, votes retained detached, photos deleted, audited) |
| FR-1701 | Public profiles /profile/{token} (approved applicants + GoH): photo, title/company, bio, LinkedIn + X/IG/FB; contact info stays staff-only |
| FR-0107 | Auditor role: read-only team access (overview, audit, registrations, duplicates, winners, system, search); all mutations remain admin/staff-only |
| FR-0309b | Category capacity + waitlist: optional max_applicants; overflow registrations β waitlisted (notified, audited); admin promotes via approve |
| FR-0311 | CSV bulk import: staff upload (name,email,whatsapp,cnic,category,title,company) β on-behalf registrations with per-line error report; audited |
FR-1200 β Notifications (v0.8.0)
| ID | Requirement |
|---|---|
| FR-1201 | In-app notifications (vote milestones, ticket replies, results) |
| FR-1202 | Reminder surface on dashboards; channel escalation (WhatsApp/email) later |
6. Use-case library
Full step-by-step flows live indocs/WORKFLOWS/. Here: the contract version
(preconditions β main flow β alternates β postconditions).
UC-01 Configure branding & toggles β Admin
- Pre: admin logged in.
- Main: open Control Panel β edit name/logo/colors/campaign texts β save β changes live immediately; toggle module features on/off.
- Alt: restore defaults; invalid color rejected.
- Post: settings persisted; audit entry written.
UC-02 Manage event & categories β Admin
- Pre: admin. Main: create event (type award) β add categories β set active/order β announce (status).
- Alt: hide category (existing applicants unaffected); edit anytime.
- Post: public listing reflects active set.
UC-03 Register as visitor β Guest β Visitor Β· flow
- Pre: event open for registration.
- Main: open
/register/visitorβ LinkedIn sign-in (preferred) or basic form (+WhatsApp optional for visitors) β confirm β success page with "I am visiting" card β download/post to social. - Alt: existing account β resume; event closed β waitlist message.
- Post: registration row
type=visitor; notification.
UC-04 Apply for an award β Applicant + AI Β· flow
- Pre: active categories; applicant passes BR-001/BR-002 checks.
- Main: pick category β LinkedIn OAuth β profile imported β basic info + WhatsApp β photo (optional, may complete later on dashboard; required before approval) β AI interview (random category questions, AI-marked) β success page: personal share link + "I have applied" card.
- Alt: skip AI when event type = normal (BR: normal registration OK); photo may be uploaded later via
POST /dashboard/photo; re-try photo upload. - Post: registration
type=award, status=submitted+ ai_session; card PNG.
UC-05 Apply as Guest of Honor β GoH / Staff Β· flow
- Main:
/guest-of-honorform (title e.g. CIO, company, bio, photo (optional, may complete later on dashboard), LinkedIn) β pending approval β admin approves (photo required) β listed. - Alt (manual): staff uses "enter on behalf" (govt/C-level invitees) β flagged
entered_by_user_id. - Post: registration
type=goh, status=pendingβapproved; BR-002 enforced.
UC-06 Staff manual entry β Staff
- Main: staff dashboard β "Add on behalf" β choose type β fill form (+upload photo) β confirm β record marked as manual entry.
- Post: audit entry with staff actor.
UC-07 Cast a vote β Voter Β· flow
- Pre: share link
v/{token}; candidate approved; voting window open. - Main: open link β LinkedIn auth β (optional) reason β Vote β confirmation + prompt to share.
- Alt: already voted (per rules) β "already voted" with change-vote policy (default: no duplicates); voting restriction relaxed mode β allowed per admin setting.
- Post: vote row; candidate count +1; notification to applicant; audit.
UC-08 AI marking & stats β System/AI
- Main: for each answer β score + feedback β session total & summary β attach to applicant β judges/admin see stats. Mock mode deterministic until key (NFR-08).
UC-09 Applicant self-view β Applicant
- Main: dashboard β own vote count, voter identities, AI stats, share link, cards, tickets, notifications.
- Alt: attempt to view others' totals β denied (BR-006).
UC-10 Judge review β Judge Β· flow
- Main: login β assigned scope β open contestant (profile, photo, AI stats, votes-if-enabled) β decision (approve/disapprove/needs-info) + notes β save.
- Post: per-category report aggregated for admin.
UC-11 Finalize & announce winners β Admin Β· flow
- Pre: voting closed; judges reported.
- Main: review blended ranking (70/30) + judges β optional veto (reason) β select winners per category β approve & lock β system announces (public page + notifications) β winner badges + cards generated β winners share.
- Post:
status=winnerrows; audit-locked snapshot; public results.
UC-12 Generate share card β System
- Main: on applied/visiting/winner trigger β GD render (photo + campaign text) β stored β shown for download/share. Alt: AI driver later.
UC-13 Support ticket β Applicant β Staff Β· flow
- Main: applicant opens ticket (subject, question, media allowed) β staff replies from queue β status flow (openβpendingβansweredβclosed).
UC-14 Mass communication β Staff
- Main: select audience β compose (email; WhatsApp when keyed) β preview recipient count β send β per-recipient status tracked.
UC-15 Review audit log β Admin
- Main: open Audit β filter by actor/action/date β drill into entries (meta JSON).
UC-17 Flag & review a suspected duplicate β System + Admin Β· flow
- Pre: registration submitted (any path incl. manual entry/claim).
- Main: system scans identity signals across all events β on any match: alert row created, all admins notified, audit entry β admin opens
/admin/duplicatesβ compares side-by-side β Confirm (auto-veto new registration) or Dismiss. - Alt: no match β nothing happens; applicant experience unchanged (flag-and-review, never auto-block).
- Post: queue item resolved; audit trail kept.
UC-16 Admin overview & AI insights β Admin
- Pre: admin logged in (event data exists for meaningful numbers; empty states otherwise).
- Main: admin home shows KPI cards with trends (7d/30d) β graphs (votes over time, funnel, per-category shares, top candidates, AI score distribution) β tabs: Audit (live filterable feed) β AI Insights (weekly summary, applicant briefs, vote-anomaly flags) β drill into any figure to its underlying list.
- Alt: AI key missing β insights panel shows mock/sample output with "waiting for AI key" notice (NFR-08).
- Post: no writes; every query scoped to admin role and covered by the JSON feeds used for charts.
FR-1600 β Integrations & venue (v1.5.0)
| ID | Requirement |
|---|---|
| FR-1601 | Webhooks: admin-managed endpoints, event subscriptions (registration.created, vote.cast, winner.locked, duplicate.suspected, or *), HMAC-SHA256 signatures (X-FLA-Signature), delivery log with HTTP status, test ping |
| FR-1602 | Venue leaderboard screen /screen/{slug}: auto-refresh (30s), big-display dark theme; public when leaderboard_public/finished, else staff-only |
| FR-1603 | CSV exports (admin/staff): registrations & votes, event-scoped, audited (export.csv) |
| FR-1606 | Global admin search (/admin/search): one query across registrations (name/email/token), events, tickets and users; header search box on every admin page |
| FR-0906 | SMS channel for mass comms (channel=sms) β log transport (Pakistan-ready; provider keys plug in) |
| FR-0907 | Scheduled comms: optional future send-time; queued recipients; lazy dispatch on staff page + bin/send-scheduled.php for cron |
| FR-0606 | QR verification: printable certificates embed a QR β public /cards/{token}/verify page showing live winner/finalist status |
| FR-0607 | Certificate numbers (FLA-<year>-<seq>): assigned to winners+finalists at lock; printed on certificates, shown on verify page, searchable |
| FR-0608 | GoH card (campaign.goh_text) downloadable by approved Guests of Honor |
| FR-0620 | GoH ratings (internal): Seniority/Influence/Relevance 0β100 β avg; global (per person) + per event; effective = event ?? global; roster sorted as suggestion seed; audited goh.rated |
| FR-1604 | Bulk admin ops: approve/reject multiple registrations at once; audited per-row |
| FR-1800 | Nominations: public /nominate (honeypot + throttled), admin queue β Invite (log email/SMS with signed prefilled link) / Reject; auto-convert on registration (token or email match); webhook nomination.created |
| FR-1810 | AI Assistant (/assistant): multi-conversation context-aware chat for admin/staff/judge/auditor; live platform context injected (PII-free for judges); async send, 30 msgs/h/user, audited by length only |
| FR-1820 | Web Push: VAPID (ES256) + RFC 8291 encryption in pure PHP; subscriptions per user; admin broadcasts (segments) + auto-push on winner.locked; dead-subscription cleanup; member opt-in on dashboard |
| FR-1830 | Internal messaging: team β member threads (inboxes both sides, unread tracking); ai_assisted markers; audit message.sent |
| FR-1840 | AI drafting: "Draft with AI" in composer (recipient-aware: role/event/rating) + admin bulk personalized drafts (one intent β per-GoH messages, reviewed before send) |
| FR-1850 | Scheduling (both directions): GoH publishes availability slots; staff request/propose; GoH confirms/declines/counter-offers; states openβrequested/proposedβconfirmed/declined/cancelled; /admin/schedule board; notifications + audit |
| FR-0180 | Magic-link login: one-time 15-min email link for members (no LinkedIn needed); throttled; one-time use; no account enumeration |
| FR-1860 | People tracking: activity timeline per registrant (/admin/people), engagement score (logins/votes/messages/nominations); anonymous page-view tracking (hashed visitor, public pages only) |
| FR-1870 | Vote receipts + hash chain: every vote gets a receipt code (shown to voter) + chained seal; public /verify-vote; chain integrity check on /admin/system |
| FR-1880 | AI category fit: applicant describes work β AI suggests best category (mock-safe) |
| FR-1890 | Share-link click analytics: pre-auth clicks per candidate link + unique-visitor KPIs on admin overview |
| FR-2000 | QR check-in (/admin/checkin): scan/enter token or any cert/vote/profile URL β present; duplicates detected; undo; live counts |
| FR-2100 | Presenter assignment + run-sheet: GoH assigned per category (notified); printable timed run-sheet with presenters, winners, cert numbers, confirmed GoH slots |
| FR-2200 | Media gallery: members upload photos/video links β staff moderation β live on vote page + event photo wall |
| FR-2300 | Ceremony ops (/admin/ceremony): reveal buttons, presenter picks, attendance, screen + run-sheet links on one screen |
| FR-2400 | Sponsor wall: per-event sponsors (tier + logo + URL) on event admin + public event page |
| FR-2500 | Season report (/admin/report?year=): print/PDF-ready summary β events, categories, winners + cert numbers, vote totals |
| FR-3000 | MC Dashboard (/mc): dedicated MC role; slide controls (advance/back/skip/goto); stage screen link; run-sheet link |
| FR-3010 | Stage Screen (/stage/{slug}): polling-based auto-updating display; renders slide types (logo, anthem, MC intro, GoH, category, winner, sponsor, thanks, blank); multi-GoH layout (1-N presenters side by side) |
| FR-3020 | Winner queue: calling order with shield tracking (not_requested β requested β ready / override_blank); reorder (move up/down with reason); called β appeared β appearance count |
| FR-3030 | Award Team (/award-team): dedicated role; notified on shield request; confirms "shield ready β
" or "not ready β"; MC sees status live |
| FR-3040 | Admin override: admin can force "blank shield" to unblock queue |
| FR-3050 | GoH substitution: mark no-show β replace with substitute (auto-notify); goh_substitutions table; category_presenters updated |
| FR-3060 | Self check-in (/self-checkin): attendee enters code/QR β checked in β sees zone/seat + queue position |
| FR-3070 | Multi-GoH presenters: category_presenters join table (1-N per category); stage screen auto-adapts layout |
| FR-3080 | Ceremony auto-generate: admin one-click generates run-of-show from event data (slides + queue); migration 027 |
| FR-1103 | Audit CSV export via /admin/export?type=audit |
| FR-1604 | Admin 2FA (TOTP, RFC 6238): per-account enable/disable with code confirmation; passwordβcode login challenge |
FR-1500 β Public API (v1.4.0)
| ID | Requirement | |
|---|---|---|
| FR-1501 | Read-only JSON API: /api/v1/events, /events/{slug}, /events/{slug}/categories, /events/{slug}/winners β public data only, no PII, JSON 404s | |
| FR-1502 | SEO surface: /robots.txt (admin areas disallowed) + dynamic /sitemap.xml | |
| FR-1503 | Embeddable leaderboard widget /embed/leaderboard/{slug} β white-label, 30s auto-refresh, framable (public data only) | |
| FR-0810 | Vote management: admin browse/remove/restore votes; soft-deleted votes excluded from all tallies; reason mandatory; reversible; audited (vote.removed/vote.restored) | Admin |
| FR-0811 | Admin onboarding: dismissible getting-started checklist on the overview | Admin |
| FR-0812 | Guided tour: 4-step spotlight walk-through on the admin overview, once per user, skippable | Admin |
| FR-0620 | Judges transparency panel: public results page lists the judging board (names, review counts, LinkedIn) post-lock | Public |
| FR-0720 | Candidate compare: side-by-side view (max 4) with AI scores, linked from the public leaderboard | Voting |
| FR-0610 | Public GoH directory: /speakers listing approved guests of honor | Public |
| FR-1305 | Hall-of-fame search: full-text ?q= across winners/categories/events | Public |
| NFR-12 | Async queue: jobs table + minute-cron worker, retries Γ3 with backoff; Telegram ops alerts (optional) | Ops |
7. Non-functional requirements
| ID | Requirement |
|---|---|
| NFR-01 | Responsive: mobile-first; all flows usable on phones (voting especially). |
| NFR-02 | HTTPS only at https://event.production1.jugaar.ai, plain 443, HSTS once live. |
| NFR-03 | Auditability: sensitive actions (login, vote, veto, finalize, manual entries, comms) logged. |
| NFR-04 | Performance: p95 page load < 2 s on shared hosting; voting/cards cached where possible. |
| NFR-05 | Security: PDO prepared statements, output escaping, CSRF tokens on forms, rate-limit votes/login. |
| NFR-06 | Privacy: minimal PII; LinkedIn data only id/name/email/picture; voter list visible to the candidate only (BR-006). |
| NFR-07 | Extensibility: modules self-contained under src/Modules/<Name>; core stays lean. |
| NFR-08 | Degradability: full flow works in mock mode without any external API key. |
| NFR-09 | Availability: graceful error pages; AI/LinkedIn outage never blocks browsing. |
| NFR-10 | Backups: nightly DB dump (ops; procedure in HELP.md). |
| NFR-11 | Security headers on every response: HSTS (on HTTPS), X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. |
| NFR-12 | Vote rate limiting per IP (default 30/hour, admin-configurable via voting.rate_limit_per_hour), audited as vote.rate_limited. |
| NFR-13 | PWA: installable (manifest + icons + service worker; statics cached offline). |
| NFR-14 | Team accounts support TOTP 2FA; sensitive flows throttle + audit by default. |
| NFR-15 | Ops: system health dashboard (/admin/system) shows DB size, table rows, disk free, storage size, queue depths, backup recency. |
| NFR-16 | Public pages cached (file TTL 60β300s; flushed on content-affecting admin mutations). |
8. Integrations
| Service | Purpose | Mode now | Needed from owner |
|---|---|---|---|
| MiniMax platform (platform.minimax.io) | AI Q&A marking, summaries, insights | Mock | API key (+ confirm exact m3 model id & base URL) |
| LinkedIn OIDC | Registration + voter verification | Mock | App client id/secret (developer.linkedin.com) |
| WhatsApp (Meta Cloud API or Twilio) | Comms to collected numbers | Null (logged) | Provider choice + keys |
| AI image API (TBD) | Fancy share cards | GD fallback | API key β enables cards.driver=ai |
9. Data model (overview)
settings Β· feature_toggles Β· users (admin/staff/judge/applicant/visitor/goh/voter) Β· events Β· categories Β· registrations (+public_token, entered_by_user_id) Β· question_bank Β· ai_sessions Β· ai_answers Β· votes Β· judge_assignments Β· judge_reviews Β· tickets Β· ticket_messages Β· audit_log Β· notifications Β· communications Β· communication_recipients
Key uniques: users.linkedin_id, users.email, registrations(event_id,user_id) (BR-001/002), votes(registration_id,voter_user_id) (BR-003), judge_reviews(registration_id,judge_user_id). DDL: database/migrations/001β009.
10. Open questions
- Confirm MiniMax m3 model id + exact base URL; obtain API key (platform.minimax.io).
- LinkedIn App credentials (OIDC scopes
openid profile email). - WhatsApp provider: Meta Cloud API vs Twilio.
- AI image API for share cards (later).
- Email sender (SMTP host / transactional service) for comms & notifications.
- Allowed vote-change policy (default: votes are final).
- Public leaderboard visibility pre-finalization (default: admin-only, BR-006).
Answers get recorded here + in TODO.md when provided.
11. Version history
| Version | Date | Change |
|---|---|---|
| 0.1.0 | 2026-08-29 | Initial SRS (docs + scaffold baseline). |
| 1.0.0 | 2026-08-29 | Full platform implemented (all modules live + E2E-verified). |
| 1.1.0 | 2026-08-29 | Duplicate-candidate detection (BR-011, FR-1300, UC-17) + judges anchoring fix. |
| 1.2.0 | 2026-08-29 | Winner un-lock/re-announce flow (FR-1005) + team password reset (FR-0705). |
| 1.3.0 | 2026-08-29 | Polish pack: email verification (FR-0309/0310), vote-change toggle (FR-0509), referral attribution (FR-0510), finalist cards (FR-0604), security headers (NFR-11). |
| 1.4.0 | 2026-08-29 | Public discovery + ops: events directory (FR-0204), hall of fame (FR-1006), printable certificates (FR-0605), public API v1 (FR-1500), robots/sitemap, vote rate limiting (NFR-12), automated backups. |
| 1.5.0 | 2026-08-29 | Integrations & experience: webhooks (FR-1601), venue screen (FR-1602), CSV exports (FR-1603), admin 2FA TOTP (FR-1604), PWA (NFR-13). |
| 1.6.0 | 2026-08-29 | Scale & polish: maintenance mode (FR-0106), bulk ops (FR-1604), audit export (FR-1103), system health (NFR-15), vote guards hardened. |
| 1.7.0 | 2026-08-30 | Photo flexibility B: optional at signup, dashboard upload, approval guard. |
| 1.8.0 | 2026-08-30 | Search & verification: admin global search (FR-1606), SMS channel (FR-0906), QR certificate verification (FR-0606). |
| 2.0.0 | 2026-08-30 | Program growth & ops: nominations (FR-1800), AI assistant (FR-1810), judge rubric (FR-0706), cert numbers (FR-0607), ceremony reveal (FR-1007), capacity+waitlist, scheduled comms (FR-0907), embed widget (FR-1503), data rights (FR-1700), auditor role (FR-0107), event cloning (FR-0205), wa.me chat, public caching (NFR-16). |
| 2.1.0 | 2026-08-30 | Reach: Web Push (FR-1820, pure-PHP crypto), CSV import (FR-0311), waitlist UI, nomination throttle setting. |
| 2.2.0 | 2026-08-30 | Section 2 core: GoH decisions (FR-0305b), GoH card (FR-0608), event-page listing, ratings (FR-0620), public profiles + socials (FR-1701). |
| 2.3.0 | 2026-08-30 | Engage: magic-link login (FR-0180), messaging (FR-1830), AI drafting (FR-1840), scheduling both directions (FR-1850). |
| 2.4.0 | 2026-08-30 | Track & Trust: people tracking (FR-1860), vote receipts+chain (FR-1870), AI category fit (FR-1880), click analytics (FR-1890). |
| 2.5.0 | 2026-08-30 | Section 3 Day-of-Event: check-in (FR-2000), presenters+run-sheet (FR-2100), media gallery (FR-2200), ceremony ops (FR-2300). |
| 2.6.0 | 2026-08-30 | Growth: sponsor wall (FR-2400), season report (FR-2500). |
| 3.0.0 | 2026-08-31 | Ceremony Production System: MC dashboard, stage screen, award team, winner queue + shields, GoH substitution, self check-in, multi-GoH presenters (FR-3000β3080). |
