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
Email 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

Ask about my work

Ask about my career, education, projects, or blog posts.