Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

57 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Recall πŸ“Š

Centralized Feedback & Analytics Platform for the Computer Science Association (CSA), RIT Kottayam

Recall is a professional, high-performance web application designed for the Computer Science Association (CSA) at RIT Kottayam. It replaces fragmented, ad-hoc feedback collection tools (like Google Forms) with a centralized, persistent system to record, analyze, and archive feedback for all association eventsβ€”including workshops, bootcamps, hackathons, and technical talks.


πŸ“– Table of Contents

  1. Project Motivation
  2. Key Features
  3. Tech Stack
  4. Firestore Database Schema
  5. Architecture & System Flows
  6. Directory Structure
  7. Installation & Local Setup
  8. Firebase Console & Security Rules Configuration
  9. Deployment
  10. Maintainability & Handover Guide

🎯 Project Motivation

The current reliance on individual-led feedback loops (primarily Google Forms) introduces three critical failure points:

  • Access Fragmentation: Responses are visible only to the form creator. Sharing access is manual, leading to data siloing and lost insights.
  • Institutional Memory Loss: When a new Executive Committee (Excom) takes charge, there is no permanent archive of past events, feedback, or operational issues. Every new committee starts blind.
  • Lack of Automated Analytics: Raw spreadsheet data requires manual parsing. There is no automated, recurring visualization of ratings, option selections, or qualitative sentiment.

Recall resolves these issues by establishing a centralized dashboard accessible to all authenticated CSA members, preserving event archives across handovers, and generating real-time analytics with exportable data options.


✨ Key Features

  • πŸ“… Event Dashboard: Unified dashboard listing all events (workshops, hackathons, bootcamps, etc.) sorted chronologically, displaying active status and total response counts.
  • πŸ› οΈ Drag-and-Drop Questionnaire Builder: Dynamic form builder supporting four question types: single_choice (radio), mcq (checkbox), short_text (textarea), and star_rating. Powered by @hello-pangea/dnd with custom autoscroll easing, slower scroll-rate dampening, and dynamic touch handle pill indicators designed for optimized mobile reordering.
  • πŸ”’ Auto-Locking Safety: The questionnaire builder automatically locks once an event receives its first response, preventing structural database mismatches.
  • πŸ›‘οΈ Questionnaire Integrity Protection: Leverages a custom hashing mechanism to generate a signature for each form state. Submissions are rejected if the participant's form state does not match the active server configuration.
  • πŸ“Š Live Analytics & Visualization: Interactive analytics using Recharts with optimized tab transitions using React 19 useTransition and a responsive toolbar loading shimmer state for instantaneous feedback.
    • Single Choice: Rendered as colorful Pie Charts.
    • Multiple Choice (MCQ): Visualized as Horizontal Bar Charts with multi-select labels.
    • Star Ratings: Averages and star distributions.
    • Short Text: Searchable, scrollable lists sorted by submission time.
  • πŸ“ Dynamic Viewport Layouts: Utilizes a ResizeObserver dynamic offset tracker to calculate and adjust top padding in the questionnaire builder automatically, ensuring header title cards are fully visible under floating navigation bars across all device viewports.
  • πŸ“₯ Client-Side Excel/CSV Export: Enables administrators to download event response data instantly. Generates clean, structured, and properly-escaped spreadsheet reports directly in the browser as a .csv file (fully compatible with Microsoft Excel and Google Sheets) containing respondent details, timestamps, and corresponding answers.
  • πŸ”‘ Hybrid Cookie-Based Auth: Combines client-side Firebase Auth with secure, server-side HTTP-Only session cookies verified by Next.js Middleware.
  • πŸŒ€ Premium Visual Interface: Built with a curated dark color palette, custom glassmorphism components, and a fluid 3D Three.js particle background (PixelBlast) that adds a premium feel.

πŸ’» Tech Stack

Layer Choice Reason
Framework Next.js 16 (App Router) React Server Components, server-side API routes, and optimized assets.
Runtime React 19 Standardized DOM rendering and async state handlers.
Styling Tailwind CSS v4 & PostCSS Rapid utility styling paired with modern CSS variables.
Database Cloud Firestore (NoSQL) Real-time nested document storage, highly scalable, and flexible.
Auth Firebase Authentication Secure, managed authentication for internal members.
Admin Operations Firebase Admin SDK Bypasses standard rules securely in serverless endpoints.
Charts Recharts Canvas-free, SVG-based declarative charting library.
Visual Effects Three.js & Postprocessing Renders high-performance interactive 3D particle backgrounds.

πŸ—„οΈ Firestore Database Schema

Firestore stores data in a hierarchical collection-document structure. Below is the nested design used in Recall:

events/                                  [Root Collection]
  β”œβ”€β”€ {eventId}/                         [Document: Event Metadata]
  β”‚     β”œβ”€β”€ title: string
  β”‚     β”œβ”€β”€ description: string | null
  β”‚     β”œβ”€β”€ start_date: string           (ISO Date YYYY-MM-DD)
  β”‚     β”œβ”€β”€ end_date: string             (ISO Date YYYY-MM-DD)
  β”‚     β”œβ”€β”€ event_type: string           ("Workshop" | "Bootcamp" | "Hackathon" | "Technical Talk" | "Other")
  β”‚     β”œβ”€β”€ is_published: boolean
  β”‚     β”œβ”€β”€ created_at: string           (ISO Timestamp)
  β”‚     β”‚
  β”‚     β”œβ”€β”€ questions/                   [Subcollection: Form Structure]
  β”‚     β”‚     └── {questionId}/          [Document: Question Configuration]
  β”‚     β”‚           β”œβ”€β”€ question_text: string
  β”‚     β”‚           β”œβ”€β”€ question_type: string  ("single_choice" | "mcq" | "short_text" | "star_rating")
  β”‚     β”‚           β”œβ”€β”€ options: string[] | null
  β”‚     β”‚           β”œβ”€β”€ order_index: number
  β”‚     β”‚           └── is_required: boolean
  β”‚     β”‚
  β”‚     └── responses/                   [Subcollection: Submissions]
  β”‚           └── {responseId}/          [Document: Respondent Header]
  β”‚                 β”œβ”€β”€ respondent_token: string   (Client-side UUID for deduplication)
  β”‚                 β”œβ”€β”€ respondent_name: string    (Optional)
  β”‚                 β”œβ”€β”€ questionnaire_signature: string
  β”‚                 β”œβ”€β”€ submitted_at: string       (ISO Timestamp)
  β”‚                 β”‚
  β”‚                 └── answers/         [Subcollection: Submitted Values]
  β”‚                       └── {questionId}/   (Document ID matches Question Document ID)
  β”‚                             └── answer_value: string | string[] | number

Note

Nesting answers inside a responses document allows the system to read a full submission in a single database read, while naming answer document IDs after their corresponding questionId optimizes per-question analytics aggregation.


πŸ”„ Architecture & System Flows

Administrative Authentication Flow

Recall uses a split authentication guard to maintain a secure admin boundary while enabling unauthenticated responses:

sequenceDiagram
    participant Browser as Admin Browser
    participant Context as AuthContext
    participant Server as Next.js API (/session)
    participant SDK as Firebase Auth SDK
    participant MW as Middleware (Edge)

    Browser->>SDK: Login(email, password)
    SDK-->>Browser: Return UserCredential & ID Token
    Browser->>Context: State Change Detected
    Context->>Server: POST /api/session { token }
    Server-->>Browser: Set HTTP-Only '__session' Cookie
    Note over Browser, MW: Subsequent Navigation to /dashboard
    Browser->>MW: Request Page
    alt Has Valid Cookie
        MW-->>Browser: Render Dashboard (200)
    else No Cookie / Invalid
        MW-->>Browser: Redirect to /login (307)
    end
Loading

Questionnaire Integrity (Signatures)

When a questionnaire is built or updated, it has a cryptographic signature based on its structural layout (question texts, types, order, requirements, options). This signature is validated on response submission to prevent data pollution if an admin changes questions while a user is answering:

  1. Signature Generation: Normalized fields are hashed using a djb2 implementation:
    // lib/questionnaire-signature.ts
    function hashString(value: string) {
      let hash = 5381;
      for (let i = 0; i < value.length; i++) {
        hash = (hash * 33) ^ value.charCodeAt(i);
      }
      return (hash >>> 0).toString(36);
    }
  2. Validation Route: During POST /api/submit-response:
    • Fetch active questions from Firestore.
    • Recompute the signature.
    • Compare the server-side signature with the payload's questionnaire_signature.
    • If they mismatch, return 409 Conflict (Code: QUESTIONNAIRE_CHANGED), forcing the participant browser to reload.

Excel / CSV Export Flow

Recall simplifies feedback retrieval by generating and compiling data client-side with zero external cloud dependencies or API authorization overhead. When an administrator clicks the "Save as Excel" button:

sequenceDiagram
    participant Admin as Administrator
    participant Browser as Browser (Client)
    participant DB as Firestore
    Admin->>Browser: Click "Save as Excel"
    Browser->>DB: Fetch Responses & Answers for Event
    Browser->>Browser: Construct CSV Headers (Timestamp, Name, Token, Questions...)
    Browser->>Browser: Iterate responses & map answers to columns
    Browser->>Browser: Sanitize content & escape double quotes
    Browser->>Browser: Generate CSV Blob with UTF-8 encoding
    Browser->>Browser: Trigger file download: recall-[event-title]-responses.csv
    Browser-->>Admin: Download completed
Loading

The exported spreadsheet file matches standard tabular structures:

  • Columns: Map out Respondent metadata (Submitted Timestamp, Respondent Name, Token) followed by each question defined in the questionnaire.
  • Rows: A separate entry for each submitted response.
  • Cell Values: Raw text strings, numbers, or semi-colon-separated lists (for multiple choice questions).

πŸ“ Directory Structure

recall/
β”œβ”€β”€ app/                                 # Next.js App Router Pages & API Routes
β”‚   β”œβ”€β”€ (portal)/                        # Administrative Authenticated Layout
β”‚   β”‚   β”œβ”€β”€ dashboard/                   # Event list & creation entry point
β”‚   β”‚   └── events/                      # Event details, builders, and statistics
β”‚   β”‚       β”œβ”€β”€ new/                     # Event metadata creator
β”‚   β”‚       └── [event-id]/
β”‚   β”‚           β”œβ”€β”€ builder/             # Drag-and-drop questionnaire editor
β”‚   β”‚           └── responses/           # Analytics charts and exports
β”‚   β”œβ”€β”€ api/                             # Backend Endpoints
β”‚   β”‚   β”œβ”€β”€ export-responses-to-sheets/  # Unused legacy endpoint (Excel downloads are client-side)
β”‚   β”‚   β”œβ”€β”€ ping/                        # Keeping database active (cron target)
β”‚   β”‚   β”œβ”€β”€ session/                     # HTTP-Only cookie injector/remover
β”‚   β”‚   └── submit-response/             # Validated public response receiver
β”‚   β”œβ”€β”€ login/                           # Administrator login panel
β”‚   β”œβ”€β”€ reset-password/                  # Re-authentication password gate
β”‚   β”œβ”€β”€ respond/[event-id]/              # Public participant response form
β”‚   β”œβ”€β”€ globals.css                      # Global styles and Tailwind layout
β”‚   β”œβ”€β”€ layout.tsx                       # Root layout & providers (Auth, Theme)
β”‚   └── middleware.ts                    # Edge protection middleware
β”œβ”€β”€ components/                          # React Components
β”‚   β”œβ”€β”€ ui/                              # Core design system components
β”‚   β”‚   β”œβ”€β”€ Button.tsx                   # Customized primary/secondary action handlers
β”‚   β”‚   β”œβ”€β”€ Card.tsx                     # Content containers with custom glassmorphism
β”‚   β”‚   β”œβ”€β”€ Input.tsx / Select.tsx       # Pre-styled visual inputs
β”‚   β”‚   β”œβ”€β”€ NavBar.tsx                   # Site headers and navigation controls
β”‚   β”‚   β”œβ”€β”€ PixelBlast.tsx               # Three.js 3D dynamic particle background
β”‚   β”‚   └── Spinner.tsx                  # Pre-styled visual loaders
β”‚   β”œβ”€β”€ AnalyticsCharts.tsx              # Recharts visualization selector
β”‚   β”œβ”€β”€ ParticipantForm.tsx              # Public questionnaire renderer & validator
β”‚   β”œβ”€β”€ ParticipantLinkShare.tsx         # Copy-to-clipboard invite links
β”‚   └── QuestionnaireBuilder.tsx         # Form layout configurator
β”œβ”€β”€ lib/                                 # Core Utilities & Library Wrappers
β”‚   β”œβ”€β”€ auth.ts                          # Firebase Auth abstraction layer
β”‚   β”œβ”€β”€ AuthContext.tsx                  # Client context listener
β”‚   β”œβ”€β”€ db-admin.ts                      # Server-side Firestore operations (Firebase Admin)
β”‚   β”œβ”€β”€ db.ts                            # Client-side Firestore operations (Firestore SDK)
β”‚   β”œβ”€β”€ firebase-admin.ts                # Firebase Admin SDK initializer
β”‚   β”œβ”€β”€ firebase.ts                      # Client Firebase SDK initializer
β”‚   β”œβ”€β”€ questionnaire-signature.ts       # Hashing helper
β”‚   └── types.ts                         # Global TypeScript type contracts

πŸš€ Installation & Local Setup

Prerequisites

  • Node.js v22.x
  • npm v10.x
  • A Firebase Project (with Firestore and Email/Password Sign-In enabled)

1. Clone the repository and install dependencies

git clone https://github.com/kevinjose06/Recall.git
cd Recall
npm install

2. Configure Environment Variables

Create a .env.local file in the root directory:

# Client Firebase Keys (Publicly accessible in client bundles)
NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project-id.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project-id.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id

# Server-Side Firebase Admin Secret (Keep private)
# Escape double quotes inside the private key string or paste the service account JSON on a single line
FIREBASE_SERVICE_ACCOUNT_JSON={"type":"service_account","project_id":"your-project-id","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n","client_email":"firebase-adminsdk-...@your-project-id.iam.gserviceaccount.com",...}

3. Start the Development Server

npm run dev

Open http://localhost:3000 with your browser.


πŸ”’ Firebase Console & Security Rules Configuration

To keep the platform's backend secure while allowing unauthenticated form submissions, configure Cloud Firestore with the following security schema in the Rules tab:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // Helper: Checks if the request is from an authenticated administrator
    function isAdmin() {
      return request.auth != null;
    }

    match /events/{eventId} {
      // Events can only be read or written by administrators
      allow read, write: if isAdmin();

      match /questions/{questionId} {
        // Form questions are only manageable by administrators
        allow read, write: if isAdmin();
      }

      match /responses/{responseId} {
        // Anyone can submit a response container (required for public forms)
        allow create: if true;
        // Only administrators can view submitted responses
        allow read: if isAdmin();

        match /answers/{questionId} {
          // Anyone can submit individual answer records
          allow create: if true;
          // Only administrators can read individual answer records
          allow read: if isAdmin();
        }
      }
    }
  }
}

🌐 Deployment

1. Hosting on Vercel

Recall is fully compatible with Vercel.

  • Link your repository to Vercel.
  • Add all variables in the .env.local file to the Environment Variables tab in your Vercel project settings.
  • Trigger a production build.

2. Keep-Alive Strategy (Supabase/Firebase Idle Prevention)

Although Cloud Firestore has no inactivity pause, any external components or microservices (e.g. Supabase instances integrated in adjacent projects) might sleep. A keepalive route is available at /api/ping. You can configure a periodic health check via cron-job.org targeting https://<your-vercel-domain>/api/ping every 5 days to ensure adjacent services stay active.


πŸ‘₯ Maintainability & Handover Guide

To ensure future Executive Committees can take over operations seamlessly, follow this protocol:

  • πŸ” Password Rotation:
    • Administrative accounts use a shared login (csa@ritkerala.ac.in or similar).
    • Rotation must occur once per year during the leadership transition.
    • The outgoing Tech Lead must update the password directly via the Firebase Console (Authentication -> Users -> Reset Password).
    • The incoming Tech Lead should change the password in-app at /reset-password after proving knowledge of the current credentials.
    • Distribute the new password securely via official college emails (never via messaging applications).
  • πŸ“ˆ Firebase Admin SDK Permissions:
    • Ensure that the service account JSON defined in the FIREBASE_SERVICE_ACCOUNT_JSON environment variable has the necessary permissions to access your Firestore database (e.g., Firebase Admin SDK Administrator Service Agent or Editor role on the project).

Created and maintained by the Computer Science Association (CSA), RIT Kottayam.

Releases

Packages

Contributors

Languages