This is a React-based project for managing and submitting event proposals for Anokha Techfest. The project is built using Firebase for backend services and ShadCN components for a modern and responsive UI.
npm install
npm install date-fnsnpm install firebase
npm install -g firebase-tools
npm install react-firebase-hooksInitialize ShadCN:
npx shadcn@latest initAdd necessary components:
npx shadcn@latest add input button card select alert sidebar tabs command popovernpm install lucide-reactCreate a file named .env.local in your project root and add:
NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-idnpm install firebase-adminGet Firebase Admin credentials:
- Go to your Firebase project console
- Click on the gear icon (⚙️) in the left sidebar to open Project Settings
- Go to the "Service accounts" tab
- Click on "Generate new private key" button
- Save the downloaded JSON file securely
Add to your .env.local file:
# Admin SDK config
FIREBASE_ADMIN_PROJECT_ID=your-project-id
FIREBASE_ADMIN_PRIVATE_KEY="your-private-key"
FIREBASE_ADMIN_CLIENT_EMAIL=your-client-emailReplace the values with the ones from:
- Your Firebase project settings for the public values
- The downloaded service account JSON for the admin values
npm run dev- Go to the Firebase Console
- Click on "Add project" or "Create a project" button
- Enter your project name (e.g., "anokha-techfest-proposals")
- Click "Continue"
- Choose whether to enable Google Analytics for your project:
- Select "Enable Google Analytics for this project" if you want analytics
- Or toggle it off if you don't need analytics
- Click "Continue"
- If you enabled Analytics, configure Google Analytics:
- Select your Analytics account or create a new one
- Choose your country/region
- Accept the terms and click "Create project"
- Wait for Firebase to set up your project (this may take a few moments)
- Click "Continue" when the setup is complete
- You'll be redirected to your Firebase project dashboard
- Set up Authentication:
- Click on "Authentication" in the left sidebar
- Click "Get started"
- Go to the "Sign-in method" tab
- Enable your preferred sign-in providers (Email/Password is recommended)
- Set up Firestore Database:
- Click on "Firestore Database" in the left sidebar
- Click "Create database"
- Choose "Start in test mode" for development (you can change this later)
- Select your database location
- Click "Done"
- Get your Firebase configuration:
- Click on the gear icon (⚙️) next to "Project Overview"
- Select "Project settings"
- Scroll down to "Your apps" section
- Click on the web icon </>
- Register your app with a nickname
- Copy the configuration object for your .env.local file
Your Firebase project is now ready to use with your application!
When developing or testing user and reviewer functionalities, manual role adjustment may be required through the Firebase console. Follow these steps to modify user roles:
- Navigate to your Firebase project console
- Select "Firestore Database" from the left sidebar
- Click on your preferred collection (typically "Auth" or "Users")
- Select the specific document for the user whose role needs modification
- A document details panel will appear displaying all user fields and data
- Locate the "role" field within the document
- Click on the edit icon next to the "role" field
- Update the role value to the desired permission level (e.g., "User", "Reviewer")
- Click "Update" to save the changes
Role changes take effect immediately and will be reflected in the application upon the user's next authentication or page refresh.
To fetch reviewer proposals, Firestore indexing must be enabled. When an API call is made from the reviewer 'View Proposals' page, a link to create the required index will be logged in the terminal. (i.e)When this API is triggered Firestore will log a helpful link in the terminal The link looks like: https://console.firebase.google.com/firestore/indexescreate_composite=...
Clicking this link will take you to Firestore’s console with the "Create Index" form pre-filled. Just click "Create".
To ensure consistent formatting across the project, run:
npx prettier --write .✅ Important: Run this before committing, pushing, or opening a pull request.
- Client Submission: Users submit data (e.g., proposal forms or reviewer actions) via the React frontend.
- Gateway Validation: Next.js API Routes intercept the request and validate the JSON payload using strictly defined Zod schemas.
- Database Execution: If validation passes, Firestore SDK services (
app/api/proposalService.js, etc.) execute the query. - Data Persistence: Data is written to Google Cloud Firestore (NoSQL), organizing parent documents and subcollections (like
History). - Client Sync: The frontend receives the response, updates state, and renders the success/failure UI.
The backend relies on Next.js App Router API endpoints that act as secure RESTful gateways to the Firestore database.
- Strict Validation Gateway: All incoming payloads are validated using Zod before any database interaction.
- Decoupled Architecture: Database logic is abstracted away from API routes into service files (e.g.,
proposalService.js,userService.js). - Stateless & Serverless: API routes execute statelessly via Vercel/Next.js edge and serverless environments.
Given Firestore is a schema-less NoSQL database, structural integrity is enforced entirely at the application layer using Zod schemas (/schemas/proposal.schema.js, /schemas/user.schema.js).
- Denormalized Hierarchy:
Auth: Root collection storing user profiles and roles.Proposals: Root collection tracking active event proposals and their current approval states.Proposals/{id}/History: Subcollection used to archive past versions, minimizing the parent document size.
- Dynamic Validation (Zod
superRefine): Conditional schema constraints are actively applied (e.g., ifisIndividualis false,groupDetailsmust be provided; if a user is aReviewer,levelmust be a number).
- User Uniqueness: Firebase Authentication inherently guarantees unique email identities.
- Data Deduplication: We rely on Firestore auto-generated Document IDs for uniqueness across proposals and history items.
- Email Domain Restriction: Zod regex ensures only
@cb.students.amrita.eduemails can register.
- Atomic Operations: Instead of reading an array, modifying it in Node, and writing it back, the API strictly uses Firestore's
arrayUnionoperator (e.g., forwarding proposals). This is an atomic database-level operation that prevents duplication and guarantees idempotency, meaning the same request sent twice won't corrupt the array. - Subcollections vs Arrays: When dealing with potentially massive data (e.g., full version histories), we use subcollections instead of arrays to bypass Firestore's 1MB document size limit and avoid transaction bottlenecks.
- Race Condition Prevention: By avoiding read-modify-write patterns and strictly utilizing Firestore atomic field operators (
arrayUnion), concurrent updates by multiple reviewers do not overwrite each other. - Version Bumping: The
versioninteger in the schema acts as a simplified optimistic concurrency control mechanism; it increments sequentially when major status changes occur (like a transition to "reviewed").
- Predictable API Responses: All service methods implement robust
try/catchblocks. - Standardized Status Codes: API routes catch exceptions and map them to appropriate HTTP status codes (e.g., 400 for Zod schema validation errors, 500 for Firestore operation failures).
- Zod Error Formatting: Zod validation failures return precise paths and custom
ZodIssueCode.custommessages so the frontend can easily display form-specific error states to the user.

