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.
FieldValue
ProductFLA Event & Awards Platform (working title "Event")
URLhttps://event.production1.jugaar.ai (plain 443 HTTPS — no ports, no localhost)
StackPHP 8.3 (plain, no framework) · MariaDB 10.11 · Nginx · GD
Version0.1.0 (docs + scaffold baseline)
StatusDraft — living
Last updated2026-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

TermMeaning
ApplicantPerson registering for an award category
GoHGuest of Honor (C-level: CIO etc.) invited/approved to give awards
VoterPublic person who votes via a shared link; verified via LinkedIn
JudgePanel member reviewing applicants in the review board
StaffTeam members (comms, manual entries, ticket replies)
AdminOwner-level access; finalize results, veto, all visibility
Share linkhttps://event.production1.jugaar.ai/v/{public_token} per applicant
Share cardGenerated PNG for social posting (applied / visiting / winner)
Mock modeRunning with simulated AI/LinkedIn/WhatsApp until API keys exist

1.4 References

  • ROADMAP.md — milestone plan · TODO.md — live session handoff
  • docs/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)

#DecisionValue
D1StackPlain PHP 8.3, modular (src/Core + src/Modules/*), no framework
D2DBMariaDB fla_event (installed host)
D3DeploymentSubdomain https://event.production1.jugaar.ai on plain 443
D4BrandingDB settings table, edited in Control Panel, defaults until configured
D5AIProvider gateway; default driver MiniMax platform model minimax-m3; mock until keyed
D6LinkedInOIDC client; mock fixture in dev
D7WhatsAppAbstract gateway; Null driver (logged no-op) until provider + keys
D8Share cardsGD driver now; AI image driver reserved (ApiCardDriver)
D9Voting math70% aggregate public + 30% board; admin veto absolute (BR-005)
D10DocsRepo .md files are the single source; /docs renders them as webpages
D11ChartsChart.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

ActorDescriptionAccess
GuestUnauthenticated visitorLanding, docs, public results, vote links
VisitorRegistered attendee"I'm visiting" card, event info, dashboard-lite
ApplicantAward candidate in one categoryOwn votes + voters, AI interview, tickets, share cards
VoterAuthenticated via LinkedInCast vote (+ optional reason) per rules
JudgeAssigned reviewerReview board: profiles, AI stats, approve/disapprove
GoHC-level guest presenting awardsApproval-based registration; profile
StaffTeam supportManual entries, tickets, mass comms, shared dashboards
AdminOwnerEverything incl. toggles, categories, veto, finalize, audit UI
System/AIAutomated actorsAI marking, badge generation, notifications, announcements

4. Business rules

IDRule
BR-001One person may hold exactly one registration per event (DB unique (event_id, user_id)).
BR-002An award applicant cannot also be Guest of Honor in the same event (and vice versa).
BR-003Voting default: one vote per LinkedIn profile per candidate; admin may relax/change per event — logged.
BR-004Final score = 70% public-vote share + 30% board score, normalized per category.
BR-005Admin veto is absolute: admin may exclude any applicant at any stage; audit-logged with reason.
BR-006An applicant sees own vote count and voter identities only — never others'. Only admin sees the global leaderboard before finalization.
BR-007WhatsApp number is required for award and GoH registrations.
BR-008Registration prefers LinkedIn OAuth; voters must authenticate with LinkedIn.
BR-009Winners are announced by the system only after admin approval + audit lock.
BR-010AI interview: category-scoped questions drawn randomly from the active bank; answers AI-marked; stats attached to the applicant.

5. Functional requirements

FR-0100 — Platform, Branding & Docs

IDRequirementModule
FR-0101Admin edits branding: name, logo, tagline, primary color, favicon → live everywhereBranding
FR-0102Admin toggles features on/off (per module) without deploysBranding/Admin
FR-0103All repository .md docs rendered as organized webpages under /docsDocs
FR-0104Campaign texts for share cards edited in admin (placeholders {event} {name} {category})Branding
FR-0105Base URL = subdomain on plain 443; absolute_url() used for share linksCore

FR-0200 — Events & Categories

IDRequirement
FR-0201CRUD events: name, type (normal / ai / award), dates, venue, status lifecycle
FR-0202CRUD award categories per event: name, description, show/hide (is_active), sort order
FR-0203Categories shown publicly only when active; admin chooses what displays

FR-0300 — Registration (v0.4.0)

IDRequirement
FR-0301Two public entry paths: "Register as Visitor" and "Apply for an Award" (separate links OK)
FR-0302LinkedIn OAuth signup preferred; system captures id, name, email, picture
FR-0303Fallback basic form: name, email, WhatsApp (+ passwordless)
FR-0304Award flow: pick category → info → WhatsApp → photo upload → AI interview
FR-0305GoH flow: title/company/bio/photo; approval-based; staff may enter manually (incl. government guests)
FR-0306Staff manual entry "on behalf of" for any type (entered_by_user_id)
FR-0307Enforce BR-001/BR-002/BR-007 with clear errors
FR-0308Photo stored under storage/uploads, bound to registration

FR-0400 — AI Engine (v0.5.0)

IDRequirement
FR-0401Question bank per category, admin-managed, active flag
FR-0402Interview session: N random active questions (default 5), one at a time
FR-0403Each answer AI-marked (score 0–100 + feedback); session total + summary
FR-0404Stats shown on applicant dashboard + judges board
FR-0405Non-AI ("normal") events skip the interview entirely (normal registration OK)
FR-0406Provider-swappable gateway; mock mode until key; cost/logging of calls

FR-0500 — Public Voting (v0.6.0)

IDRequirement
FR-0501Applicant gets personal share link + dashboard to copy it
FR-0502Vote page: candidate card (photo, name, category, AI summary if enabled)
FR-0503Voter authenticates via LinkedIn before voting (BR-008)
FR-0504Optional one-line reason ("what is this person good at") — toggleable per event
FR-0505Enforce voting restrictions; friendly errors; duplicate attempt shown as already-voted
FR-050670/30 weighting engine computes blended score on demand (BR-004)
FR-0507Admin veto action UI (BR-005) with mandatory reason → audit
FR-0508Applicant sees own votes + voters (BR-006); public leaderboard optional/admin-only pre-final

FR-0600 — Share Cards (v0.6.0)

IDRequirement
FR-0601Generate PNG cards: applied / visiting / winner from photo + campaign text
FR-0602GD driver default; AI driver pluggable (cards.driver)
FR-0603Card + share link packaged for LinkedIn/FB posting (Open Graph tags on vote page)

FR-0700 — Judges Panel (v0.7.0)

IDRequirement
FR-0701Admin creates judge accounts + assigns event/category scope
FR-0702Judges board: list contestants in scope w/ profile, photo, AI stats, media
FR-0703Judge decision per contestant: approve / disapprove / needs info + notes
FR-0704Compiled report → main admin (per category: votes, AI score, judge tallies)

FR-0800 — Dashboards (v0.8.0, starter in v0.2.0)

IDRequirement
FR-0801Applicant: votes over time (chart), voter list (own), AI results, notifications, tickets, share cards
FR-0802Staff: queues (tickets, pending manual entries), comms tools
FR-0803Admin: comprehensive — registrations, votes, AI, judges, comms, audit, toggles
FR-0804Reminders/notifications surface on dashboards (FR-1200)
FR-0805Admin 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-0806Admin 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-0807Audit tab on admin dashboard: live audit-log feed with filters (actor, action, entity, date) — FR-1102 UI

FR-0400 — AI Engine (v0.5.0)

IDRequirement
FR-0401Question bank per category, admin-managed, active flag
FR-0402Interview session: N random active questions (default 5), one at a time
FR-0403Each answer AI-marked (score 0–100 + feedback); session total + summary
FR-0404Stats shown on applicant dashboard + judges board
FR-0405Non-AI ("normal") events skip the interview entirely (normal registration OK)
FR-0406Provider-swappable gateway; mock mode until key; cost/logging of calls
FR-0407AI 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)

IDRequirement
FR-0901Applicants/visitors open tickets; staff reply in thread; statuses tracked
FR-0902Mass communication to audiences (all/visitors/applicants/goh/category/status)
FR-0903Channels: email first; WhatsApp when provider keys arrive (numbers already collected)
FR-0904Public media/gallery sections per event

FR-1000 — Winners (v0.9.0)

IDRequirement
FR-1001Finalize per category: blend 70/30 + judge results → shortlist
FR-1002Admin approves → audit lock → system publishes winners (BR-009)
FR-1003Winner badges + "Winner" share cards auto-generated
FR-1004Public results page + notifications to winners

FR-1100 — Audit (v0.9.0)

IDRequirement
FR-1101Append-only audit log (actor, action, entity, ip, meta, time)
FR-1102Admin filter/search UI; no edit/delete of audit rows

FR-1200 — Notifications (v0.8.0)

IDRequirement
FR-1201In-app notifications (vote milestones, ticket replies, results)
FR-1202Reminder surface on dashboards; channel escalation (WhatsApp/email) later

6. Use-case library

Full step-by-step flows live in docs/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 upload → 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); 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-honor form (title e.g. CIO, company, bio, photo, LinkedIn) → pending approval → admin approves → 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=winner rows; 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-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.

7. Non-functional requirements

IDRequirement
NFR-01Responsive: mobile-first; all flows usable on phones (voting especially).
NFR-02HTTPS only at https://event.production1.jugaar.ai, plain 443, HSTS once live.
NFR-03Auditability: sensitive actions (login, vote, veto, finalize, manual entries, comms) logged.
NFR-04Performance: p95 page load < 2 s on shared hosting; voting/cards cached where possible.
NFR-05Security: PDO prepared statements, output escaping, CSRF tokens on forms, rate-limit votes/login.
NFR-06Privacy: minimal PII; LinkedIn data only id/name/email/picture; voter list visible to the candidate only (BR-006).
NFR-07Extensibility: modules self-contained under src/Modules/<Name>; core stays lean.
NFR-08Degradability: full flow works in mock mode without any external API key.
NFR-09Availability: graceful error pages; AI/LinkedIn outage never blocks browsing.
NFR-10Backups: nightly DB dump (ops; procedure in HELP.md).

8. Integrations

ServicePurposeMode nowNeeded from owner
MiniMax platform (platform.minimax.io)AI Q&A marking, summaries, insightsMockAPI key (+ confirm exact m3 model id & base URL)
LinkedIn OIDCRegistration + voter verificationMockApp client id/secret (developer.linkedin.com)
WhatsApp (Meta Cloud API or Twilio)Comms to collected numbersNull (logged)Provider choice + keys
AI image API (TBD)Fancy share cardsGD fallbackAPI 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

  1. Confirm MiniMax m3 model id + exact base URL; obtain API key (platform.minimax.io).
  2. LinkedIn App credentials (OIDC scopes openid profile email).
  3. WhatsApp provider: Meta Cloud API vs Twilio.
  4. AI image API for share cards (later).
  5. Email sender (SMTP host / transactional service) for comms & notifications.
  6. Allowed vote-change policy (default: votes are final).
  7. Public leaderboard visibility pre-finalization (default: admin-only, BR-006).

Answers get recorded here + in TODO.md when provided.

11. Version history

VersionDateChange
0.1.02026-08-29Initial SRS (docs + scaffold baseline).