HackOMania 2025 is a hackathon event organized by GeeksHacking. This repository contains the web application for HackOMania 2025's landing page, user's team management portal, and the admin portal.
The web development team behind this project consists of:
- Estee Tey (@lyqht)
- Ethan Chew (@Ethan-Chew)
- Sam Tan (@MisterDoobDoob)
- Next.js 14 - React framework with App Router
- Tailwind CSS - Utility-first CSS framework
- shadcn/ui - Re-usable components built with Radix UI and Tailwind CSS
- React Hook Form - Form handling
- Supabase - Open source Firebase alternative
- PostgreSQL database
- Authentication with GitHub OAuth
- Edge Functions for serverless computing
- Row Level Security (RLS) policies
- Automated user management and team assignments
- Challenge and submission tracking
- Event registration integration with Eventbrite
- TypeScript - Static type checking
- ESLint - Code linting
- Prettier - Code formatting
- Vercel - Deployment platform
- Modern, responsive design with animated sections
- Navigation bar with smooth scrolling
- Sections for:
- Registration information
- Challenge statements from sponsors
- Prize details ($1,000 prizes from sponsors)
- Judges and mentors information
- Timeline of events
- 7 Golden Rules
- Venue details
- Sponsors showcase
- Organizers information
- Contact details
- Secure authentication with GitHub OAuth
- Team management features:
- Team creation and joining
- Team member management
- Team leader assignment
- Challenge participation:
- Challenge selection before cutoff time
- Project submission system
- Submission deadline management
- Event registration status tracking
- Profile management
- Comprehensive user management:
- View and edit user details
- Remove users
- Set team leaders
- Mark users as registered
- Team management:
- Create and edit teams
- Manage team memberships
- Export team data to Excel
- Challenge management:
- Create and edit challenges
- Track challenge selections
- Monitor submissions
- Registration management:
- Eventbrite integration
- Bulk user import from Google Sheets
- Duplicate registration handling
- Built with shadcn/ui and Radix UI primitives
- Custom components:
- Responsive navigation bar
- Section layouts with dividers
- Image carousel
- User and team cards
- Form components
- Loading spinners
- Modal dialogs
- Data tables
- Theme switcher (dark mode support)
- This project has been deployed at https://hackomania2025.vercel.app/ using Supabase Vercel Integration and Vercel deploy where environment variables are automatically assigned to the project.
- The custom domain assigned via Vercel can be found at https://hackomania.geekshacking.com.
Copy .env.example
to .env
and fill in the following required environment variables:
POSTGRES_URL= # Your Supabase PostgreSQL URL
SUPABASE_URL= # Your Supabase project URL
NEXT_PUBLIC_SUPABASE_URL= # Same as SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY= # Your Supabase anonymous key
SUPABASE_SERVICE_ROLE_KEY= # Your Supabase service role key
GITHUB_CLIENT_ID= # Your GitHub OAuth app client ID
GITHUB_CLIENT_SECRET= # Your GitHub OAuth app client secret
# Comma-separated list of GitHub usernames that should be granted admin access
# Example: ADMIN_USERS=user1,user2,user3
ADMIN_USERS= # List of GitHub usernames for admin access
# Pre-event registration settings
NEXT_PUBLIC_EVENTBRITE_PREEVENT_EVENT_ID= # Eventbrite event ID for pre-event
EVENTBRITE_PRIVATE_TOKEN= # Eventbrite API token
# Testing environment
NEXT_PUBLIC_TEST_DATETIME= # Override current datetime for testing (format: YYYY-MM-DDTHH:mm:ss)
# Example: 2025-02-15T11:20:00
# Submission cutoff times (Unix timestamps)
NEXT_PUBLIC_CHALLENGE_SUBMISSION_CUTOFF_UNIX= # Unix timestamp for challenge submission cutoff
NEXT_PUBLIC_HACKATHON_SUBMISSION_CUTOFF_UNIX= # Unix timestamp for hackathon submission cutoff
The ADMIN_USERS
environment variable controls which users get admin access in the application. When a user signs in with GitHub:
- Their GitHub username is checked against the
ADMIN_USERS
list - If their username is in the list, they are automatically granted admin role
- Admin users are redirected to
/admin
after signing in - Admin users have access to additional features like:
- User management
- Team management
- Challenge management
To add or remove admin users:
- Update the
ADMIN_USERS
environment variable with a comma-separated list of GitHub usernames - No spaces between usernames, just commas
- Example:
ADMIN_USERS=username1,username2,username3
-
Install dependencies using pnpm.
-
You can now start the Next.js local development server:
pnpm dev
The app should now be running on localhost:3000.
When you sign in with GitHub, you will be redirected to the authorization page. You have to approve the app to access your GitHub account as following.
After successful GitHub authentication, users are redirected based on their role:
-
Admin Users
- Users listed in the
ADMIN_USERS
environment variable are automatically assigned the admin role - They are redirected to
/admin
after signing in - The admin dashboard provides access to:
- User management (view, edit, remove users)
- Team management (create, edit, delete teams)
- Challenge management (create, edit challenges)
- Registration statistics and data
- Users listed in the
-
Participants
- Regular users (not in
ADMIN_USERS
list) are assigned the participant role - They are redirected to
/user/home
after signing in - The participant dashboard provides access to:
- Personal profile management
- Team creation or joining
- Challenge selection and participation
- Event information and updates
- Regular users (not in
- Check out the docs for Local Development to run Supabase locally.
- Auth with GitHub is added by following this guide for Login with GitHub | Supabase Docs.
The project includes Supabase Edge Functions to handle event registrations:
-
fetch-eventbrite-attendees
- Purpose: Retrieves attendees from a specified Eventbrite event, handling pagination automatically to get all attendees
- Required Environment Variables:
EVENTBRITE_EVENT_ID
: The ID of the Eventbrite eventEVENTBRITE_PRIVATE_TOKEN
: Eventbrite private token obtained through creating an Eventbrite api keySUPABASE_URL
: Your Supabase project URLSUPABASE_SERVICE_ROLE_KEY
: Your Supabase service role key
- Query Parameters:
email
(optional): Find an attendee by their email addresslatest
(optional): Set to "1" to bypass cache and fetch latest data from Eventbrite
- Caching:
- Results are cached in Supabase database for 24 hours to minimize Eventbrite API calls
- Cache is bypassed when
latest=1
is used - Cache is automatically refreshed after expiration
- Cache persists across function instances and cold starts
-
prepopulate-google-sheets-main-event-registrations
- Purpose: Processes registrations from a Google Sheets CSV export, creating records in multiple tables (registrations, users, teams, team members)
- Required Environment Variables:
SUPABASE_URL
: Your Supabase project URLSUPABASE_ANON_KEY
: Your Supabase anonymous key
- Input:
- CSV file via form data with specific columns (Email Address, First Name, Last Name, etc.)
- Features:
- Bulk upsert operations for better performance
- Handles team creation and membership
- Validates GitHub profile URLs
- Prevents duplicate entries using unique constraints
- Processing Flow:
- Creates/updates main event registrations
- Creates/updates users for team members
- Creates/updates teams
- Creates/updates team memberships
- Response: Returns statistics about created/updated records
To test the functions:
# Fetch Eventbrite Pre-event attendees
curl -i --location --request GET 'https://<project-ref>.supabase.co/functions/v1/fetch-eventbrite-attendees' \
--header 'Authorization: Bearer <supabase-anon-key>'
# Process Google Sheets registrations that are approved by the admins
curl -i --location --request POST 'https://<project-ref>.supabase.co/functions/v1/prepopulate-google-sheets-main-event-registrations' \
--header 'Authorization: Bearer <supabase-anon-key>' \
--form 'file=@"registrations.csv"'
Or using the Supabase client in your Next.js application:
// Fetch Eventbrite Pre-event attendees
const { data: allAttendees, error } = await supabase.functions.invoke("fetch-eventbrite-attendees");
// Process Google Sheets registrations that are approved by the admins
const formData = new FormData();
formData.append("file", csvFile);
const { data, error } = await supabase.functions.invoke(
"prepopulate-google-sheets-main-event-registrations",
{
body: formData,
},
);
Below are the steps to create schemas and generate migrations.
For more detailed information, refer to the Drizzle ORM documentation.
-
Define your schema in the
utils/db/schema
directory. For example:import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; export const users = pgTable('users', { id: serial('id').primaryKey(), name: text('name').notNull(), email: text('email').notNull().unique(), createdAt: timestamp('created_at').defaultNow().notNull() });
-
If you have multiple schema files, you can create an index file to export them all:
export * from './users'; export * from './teams'; // ... other schema exports
After defining or updating your schema, generate migrations using Drizzle Kit:
-
Run the following command:
npx drizzle-kit generate --name=some_change
-
This will create a new migration file in the
./drizzle
directory (as specified indrizzle.config.ts
). -
Review the generated SQL in the migration file to ensure it matches your intended changes.
To apply the migrations to your database:
-
Run the following command:
npx drizzle-kit push
-
This will apply any pending migrations to your database.
- Always review generated migrations before applying them to your database.
- Commit both your schema files and the generated migration files to version control.
- In a team environment, coordinate database changes to avoid conflicts.