Poplars CC — Full-Stack Cricket Club Management & Analytics Platform
2024-08 – Present
Designed and built an end-to-end cricket club management and analytics platform for **Poplars Cricket Club** (SNCL Division G, Nottingham) — from architecture through deployment — entirely as a solo project. The system serves two audiences simultaneously: club administrators via a secure admin portal, and players via a self-service portal. All infrastructure runs on **Google Cloud Platform**, with a fully automated CI/CD pipeline ensuring zero-downtime deployments on every code push.
Poplars CC — Full-Stack Cricket Club Management & Analytics Platform
Role: Sole Developer | Duration: 2024 – Present | Live: poplarscc.co.uk
Overview
Designed and built an end-to-end cricket club management and analytics platform for Poplars Cricket Club (SNCL Division G, Nottingham) — from architecture through deployment — entirely as a solo project. The system serves two audiences simultaneously: club administrators via a secure admin portal, and players via a self-service portal. All infrastructure runs on Google Cloud Platform, with a fully automated CI/CD pipeline ensuring zero-downtime deployments on every code push.
The platform replaced manual spreadsheet workflows with a fully integrated digital system covering attendance, multi-tier fee calculation, automated financial statements, squad availability, real-time league data ingestion, and an AI-powered RAG chatbot.
Technology Stack
| Layer | Technologies |
|---|---|
| Backend | Python 3.11, Flask, Jinja2, Gunicorn |
| Database | Google Cloud Firestore (NoSQL document store) |
| Hosting | Google Cloud Run (serverless containers, europe-west2) |
| Storage | Google Cloud Storage (poplars-cc-media) |
| Event Scheduling | Google Cloud Scheduler |
| Container Registry | Google Container Registry (GCR) |
| Secrets | Google Secret Manager |
| CI/CD | GitHub Actions → GCR → Cloud Run |
| Gmail SMTP (MIMEText, MIMEMultipart) | |
| AI / LLM | Claude (Anthropic), Google Gemini, RAG Chatbot |
| External Data | Play Cricket API (SNCL league data) |
| Frontend | Bootstrap 5, Vanilla JS, CSS Custom Properties |
System Architecture
┌──────────────────────────────────────────────────────────────────────┐
│ EXTERNAL INPUTS │
│ │
│ [Play Cricket API] ←──── Cloud Scheduler (Mon 19:00) │
│ │ │
│ [Admin Browser] [Player Browser] [Email Client] │
└──────────┬────────────────┬───────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────────────────────┐
│ GOOGLE CLOUD RUN — Flask Application │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ Admin Portal │ │ Player Portal│ │ RAG Chatbot (LLM Layer) │ │
│ │ /admin/* │ │ /portal/* │ │ /chat endpoint │ │
│ └──────┬───────┘ └──────┬───────┘ └────────────┬─────────────┘ │
│ │ │ │ │
│ └─────────────────┴────────────────────────┘ │
│ │ │
│ calc_player_fees() │
│ (central fee engine) │
└──────────────────────────────┬───────────────────────────────────────┘
│
┌───────────────────┼────────────────────┐
▼ ▼ ▼
[Cloud Firestore] [Cloud Storage] [Gmail SMTP]
(all app data) (media, docs, (statements,
honour board img) availability,
welcome emails)
Data Flow
1. Event-Triggered League Table Sync (Play Cricket API)
The most distinctive architectural feature is a fully automated, event-driven data pipeline that eliminates manual league table updates.
Every Monday at 19:00 UTC
│
▼
Google Cloud Scheduler
│ HTTP POST trigger
▼
Flask endpoint (/admin/sync-league)
│
▼
Play Cricket API (SNCL Division G standings, fixtures, results)
│ JSON response parsed and normalised
▼
Cloud Firestore (league_table, matches, results collections)
│
▼
Public website — live league table, fixtures & results pages
- 52 automated syncs per year — zero manual intervention
- Handles league standings, match fixtures, and match results
- Data normalised into Firestore document model before write
- Public pages render directly from Firestore on each request
2. Player Fee Calculation Engine
A central calc_player_fees() function is the backbone of all financial logic:
Attendance records (all session types)
│
▼
calc_player_fees()
├── Legacy rows: Match Fee, Nets Fee
├── Session rows: 40 Overs, Sunday, T20, Nets
├── Discount: student_discount_factor applied to match & reg fees
├── Exemption: per-season reg_exempt_years list checked
└── Returns: match_count, nets_count, match_owed, nets_owed,
reg_owed, session_owed, total_owed, outstanding
│
▼
Admin Portal → Squad Overview, Player Detail, Payments Log
Player Portal → Fee Breakdown, History (year-grouped accordion)
Email Engine → Financial Statement (HTML email with full breakdown)
Supports 5 session types across Men's, Women's, and Sunday sides with per-team fee rates.
3. Availability Management Flow
Admin creates availability request (match / training / custom)
│
▼
Flask generates unique one-click response token per player
│
▼
HTML emails dispatched via Gmail SMTP
(player clicks Available / Not Available — no login required)
│
▼
Flask endpoint validates token → writes response to Firestore
│
▼
Admin squad builder — live response tracking, resend-to-pending
│
▼
Report email dispatched to selected officials
4. Financial Statement Email Flow
Admin clicks "Send Statement" for a player
│
▼
Flask fetches: attendance rows + payment rows + fee settings
│
▼
calc_player_fees() → full financial breakdown
(match count includes all session types: 40 Overs, Sunday, T20)
│
▼
HTML email constructed:
├── Season summary (matches, nets, registration)
├── Amount owed vs paid vs outstanding
├── Last 5 payment records
└── Bank transfer details (if outstanding balance)
│
▼
Gmail SMTP → player inbox
RAG-Powered AI Chatbot
Retrieval-Augmented Generation (RAG) is the standout AI feature of the platform — moving beyond static FAQ pages to a dynamic, knowledge-grounded assistant that answers questions about league rules, club policies, finances, and club operations.
Architecture
Player or Admin asks a question
│
▼
Chatbot endpoint (/chat)
│
▼
┌─────────────────────────────────────────────────────┐
│ RAG PIPELINE │
│ │
│ 1. Query received │
│ │ │
│ ▼ │
│ 2. Retrieval — search Firestore knowledge base │
│ ├── SNCL league rules & regulations │
│ ├── Club policies (fees, discounts, conduct) │
│ ├── Financial information (fee structure, │
│ │ payment methods, student discount rules) │
│ ├── Fixture schedule & match results │
│ └── General club information (venue, contacts) │
│ │ │
│ ▼ │
│ 3. Augmentation — relevant documents injected │
│ into LLM context window as grounding │
│ │ │
│ ▼ │
│ 4. Generation — LLM produces grounded answer │
│ citing only retrieved club-specific content │
└─────────────────────────────────────────────────────┘
│
▼
Accurate, club-specific response returned to user
Knowledge Base Domains
| Domain | Example Queries Handled |
|---|---|
| League Rules | "How many overs in a 40-over match?" / "What is the SNCL points system?" / "What happens if a match is abandoned?" |
| Club Policies | "What is the match fee for Sunday games?" / "How does the student discount work?" / "Can I get a registration fee waiver?" |
| Finance | "How do I pay my outstanding balance?" / "What are the bank details?" / "What is included in my season fee?" |
| Fixtures & Results | "When is our next home match?" / "Who did we play last Sunday?" / "What is our current league position?" |
| Club Information | "Where is the ground?" / "Who is the captain?" / "How do I register for next season?" |
Why RAG over a static FAQ
- Grounded answers — the LLM only draws on retrieved club documents, not general training data, preventing hallucinations about club-specific facts
- Always up to date — Firestore knowledge base updated by admins; chatbot answers reflect current fee structures, fixture schedules, and policies without redeployment
- Reduces admin overhead — routine member queries (fee queries, fixture questions, payment instructions) answered automatically without committee involvement
AI Tools Used
Claude (Anthropic) — Primary Development Assistant
Used as the AI pair-programmer throughout the project via Claude Code. Accelerated delivery of complex features including the multi-session fee calculator, registration exemption system, RAG chatbot integration, and iterative UI refinement. Architectural decisions, debugging, and code generation all conducted through Claude Code sessions.
Google Gemini — Generative Image AI
Generated the AI-rendered wooden honour board images used as the visual backing for the club's Batting and Bowling Honour Boards. The Gemini-generated plaque image is hosted on Google Cloud Storage and serves as the CSS background for the dynamically rendered stats overlay — real Firestore data engraved on an AI-generated physical plaque aesthetic.
RAG Chatbot — LLM with Retrieval
Player and admin-facing conversational AI (detailed above) — retrieves from a curated Firestore knowledge base covering league rules, club policies, financial information, and fixture data before generating responses.
CI/CD Pipeline
Pipeline uses GitHub Actions with automatic trigger on every push to main.
Developer: git push origin main
│
▼
GitHub Actions (ubuntu-latest runner)
│
├── 1. Checkout repository (actions/checkout@v4)
│
├── 2. Authenticate to GCP (GCP_SA_KEY secret)
│ Service account roles:
│ - Cloud Run Admin
│ - Storage Admin
│ - Secret Manager Secret Accessor
│
├── 3. Set up Cloud SDK (gcloud CLI)
│
├── 4. Configure Docker for GCR
│
├── 5. Build Docker image
│ Base: python:3.11-slim
│ Server: Gunicorn (2 workers, 4 threads, 120s timeout)
│ Port: 8080
│ User: non-root (appuser)
│ Tags: :latest + :<git-sha> (for rollback)
│
├── 6. Push image to Google Container Registry (GCR)
│
└── 7. Deploy to Cloud Run (europe-west2 / London)
CPU: 1 vCPU
Memory: 512 MB
Min instances: 1 (always warm, no cold starts)
Max instances: 3 (auto-scales under load)
Concurrency: 80 requests/instance
Timeout: 300 seconds
Total duration: ~2–3 minutes end-to-end
Secrets Management
Sensitive credentials are never committed to source code:
| Store | What lives there |
|---|---|
| GitHub Secrets | GCP_PROJECT_ID, GCP_SA_KEY (pipeline auth only) |
| GCP Secret Manager | SECRET_KEY, ADMIN_USERNAME, ADMIN_PASSWORD, SMTP_EMAIL, SMTP_PASSWORD, Firestore service account JSON |
Secrets injected at Cloud Run startup as environment variables — application reads them at runtime, never at build time.
Rollback
Every build is tagged with its Git commit SHA. Rollback to any previous deployment:
gcloud run deploy poplar-cricket-club \
--image gcr.io/<PROJECT_ID>/poplar-cricket-club:<previous-sha> \
--region europe-west2 --platform managed --quiet
Key Outcomes
| Metric | Detail |
|---|---|
| 52 automated syncs/year | Monday league table updates via Cloud Scheduler — zero manual steps |
| 100% digital fee tracking | All session types (40 Overs, Sunday, T20, Nets) tracked and calculated automatically |
| 5 session types supported | Men's, Women's, Sunday sides with per-team fee rates and student discount |
| Zero-downtime deployments | Rolling Cloud Run updates on every push — ~2–3 min pipeline |
| RAG chatbot | Answers league rules, club policies, finance queries from live Firestore knowledge base |
| Eliminated spreadsheets | Full squad overview, payment logs, and CSV export replaced manual tracking |
Repository
github.com/naresh198457/poplar-cricket-club — private
Live site: poplarscc.co.uk