Backend Development

    Learn how our server-side code works with Next.js

    The backend is where we process data, verify users, and talk to Firebase. Unlike traditional backends, we use Next.js for both frontend and backend — it's a full-stack framework.

    Make sure you understand Prerequisites and Frontend first.

    Backend Architecture

    1. React Server Components

    What: Server Components are React components that run on the server (not in the browser).

    Why we use it: Server Components let us fetch data from Firebase before sending the page to the user. This makes pages load faster and reduces Firebase costs.

    Key difference: By default, components in app/ are Server Components. Add 'use client' at the top to make them Client Components.

    What to focus on:

    • Server Components run on the server, Client Components run in the browser
    • Server Components can directly access databases (Firebase) without API routes
    • Use Client Components when you need interactivity (useState, onClick, etc.)
    • Server Components are async by default — you can use await directly

    Example from our codebase:

    Check src/app/team/page.tsx — here's how we fetch teams on the server:

    // src/app/team/page.tsx
    import { Team } from "@/app/types/team";
    
    export default async function TeamPage() {
      const teams = await Team.readAll({
        server: true,
        public: true
      });
    
      return <div>{/* render teams */}</div>;
    }

    📚 Official Documentation:

    Next.js — Server Components

    2. API Routes

    What: API routes are server-side endpoints that handle HTTP requests (GET, POST, PUT, DELETE).

    Why we use it: API routes let us create backend endpoints for actions like creating events, submitting applications, or verifying admin permissions.

    Location: API routes live in src/app/api/ with a route.ts file.

    What to focus on:

    • How to create a route.ts file
    • Export functions named GET, POST, PUT, DELETE
    • How to read request data (request.json())
    • How to return responses (NextResponse.json())

    Examples from our codebase:

    Check src/app/api/ — here's an example API route structure:

    // src/app/api/example/route.ts
    import { NextResponse } from "next/server";
    
    export async function GET() {
      // Fetch data from Firebase
      return NextResponse.json({ data: "..." });
    }
    
    export async function POST(request: Request) {
      const body = await request.json();
      // Process and save to Firebase
      return NextResponse.json({ success: true });
    }

    📚 Official Documentation:

    Next.js — Route Handlers

    3. Middleware for Protected Routes

    What: Middleware is code that runs before a request reaches your page or API route.

    Why we use it: We use middleware to protect admin routes. It checks if the user is logged in and has admin permissions before allowing access.

    Location: Our middleware is in src/middleware.ts

    How it works:

    1. User visits /admin
    2. Middleware intercepts the request
    3. Checks Firebase Auth token from service worker
    4. Calls Firebase Cloud Function to verify admin status
    5. Either allows access or redirects to login

    📚 Official Documentation:

    Next.js — Middleware

    4. Edge Runtime

    What: The Edge Runtime is a lightweight JavaScript environment that runs our backend code globally on servers close to users.

    Why we use it: Instead of one server in one location, our backend runs on a global network (via Vercel). This makes our app fast for users anywhere in the world.

    Important: The Edge Runtime has limitations — no file system, no sockets, limited Node.js APIs.

    What you need to know:

    • Our routes run on the Edge by default
    • Can't use Node.js features like fs (file system)
    • Can't use WebSockets or long-running processes
    • Focus on stateless, fast request-response patterns

    📚 Official Documentation:

    Next.js — Edge and Node.js Runtimes

    5. Firebase Cloud Functions

    What: Cloud Functions are serverless backend functions that run on Google's infrastructure.

    Why we use it: Some operations need to run on Firebase's servers (like setting custom user claims for admin permissions). Cloud Functions let us do this securely.

    Example: Our checkAdminClaims function verifies if a user is an admin.

    When to use Cloud Functions:

    • Setting custom user claims (admin status)
    • Scheduled jobs (daily cleanup, email reminders)
    • Database triggers (auto-update timestamps)
    • Operations that require Firebase Admin SDK

    📚 Official Documentation:

    Firebase — Cloud Functions

    🎯 When to Use What

    Use Server Components when:

    • You need to fetch data before rendering a page
    • You want to reduce client-side JavaScript
    • The data doesn't need to be interactive

    Use API Routes when:

    • You need to handle form submissions
    • You want a dedicated endpoint for client-side fetching
    • You need to perform mutations (create, update, delete)

    Use Firebase Cloud Functions when:

    • You need Firebase Admin SDK features
    • You want scheduled jobs or database triggers
    • Operations must run on Firebase's infrastructure

    📂 Where Backend Code Lives

    src/app/api/ — API routes (route.ts files)

    src/middleware.ts — Middleware for protected routes

    src/app/types/ — Type classes with Firebase CRUD operations

    functions/ — Firebase Cloud Functions (separate project)