Skip to content

feat: migrate to Next.js, add Supabase schema, implement Auth & Votin… - #2

Merged
Ashelycole1 merged 1 commit into
mainfrom
landing-page
Jul 27, 2026
Merged

Ashelycole1 merged 1 commit into
mainfrom
landing-page

Conversation

@Ashelycole1

Copy link
Copy Markdown
Collaborator

…g UI

Copilot AI review requested due to automatic review settings July 27, 2026 19:43
@Ashelycole1
Ashelycole1 merged commit 3ee255a into main Jul 27, 2026
1 check passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the project from a static HTML entrypoint to a Next.js App Router application, adding Clerk-based authentication, a Supabase-backed data model (schema + server access), and initial voting flows (dashboard + ballot + vote casting).

Changes:

  • Introduces a Next.js App Router structure with global styling and reusable UI components (Topbar, landing, dashboard, election cards).
  • Adds Supabase schema (tables + RLS policies) and a Supabase client/admin client used by server routes/actions.
  • Implements Clerk auth protection (middleware), a Clerk webhook for user sync, and a voting page + server action to cast votes.

Reviewed changes

Copilot reviewed 27 out of 36 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tsconfig.json Adds TypeScript configuration suitable for Next.js App Router.
supabase/schema.sql Introduces Supabase tables (voters/elections/candidates/votes) plus RLS policies.
src/middleware.ts Adds Clerk middleware to protect non-public routes.
src/lib/supabase.ts Adds Supabase browser/admin clients and shared database types.
src/components/Topbar.tsx Adds a fixed top navigation bar with Clerk auth UI.
src/components/Topbar.module.css Styles Topbar.
src/components/LandingContent.tsx Implements landing sign-in/sign-up UI via Clerk components.
src/components/LandingContent.module.css Styles landing layout and visuals.
src/components/ElectionCard.tsx Adds a presentational election card component.
src/components/ElectionCard.module.css Styles ElectionCard.
src/app/page.tsx Redirects signed-in users to dashboard; otherwise shows landing.
src/app/page.module.css Adds (currently unused) page-level CSS module from template.
src/app/layout.tsx Adds root layout with ClerkProvider and global font setup.
src/app/globals.css Defines global design tokens and shared UI utility classes (buttons, Clerk overrides).
src/app/election/[id]/vote/VoteForm.tsx Client-side candidate selection + vote submission UI.
src/app/election/[id]/vote/page.tsx Server-rendered ballot page: loads election, voter, vote state, candidates.
src/app/election/[id]/vote/page.module.css Styles ballot page and candidate cards.
src/app/election/[id]/vote/actions.ts Server action to validate election and insert a vote.
src/app/dashboard/page.tsx Server-rendered dashboard listing live elections.
src/app/dashboard/page.module.css Styles dashboard layout.
src/app/api/webhooks/clerk/route.ts Clerk webhook endpoint to sync new users into Supabase voters table.
README.md Replaces prior README with a Next.js template README.
public/window.svg Adds template asset.
public/vercel.svg Adds template asset.
public/next.svg Adds template asset.
public/globe.svg Adds template asset.
public/file.svg Adds template asset.
package.json Adds Next.js/React/Clerk/Supabase dependencies and scripts.
next.config.ts Adds Next.js config scaffold.
index.html Removes the prior static HTML implementation.
eslint.config.mjs Adds ESLint config using Next.js flat-config presets.
CLAUDE.md Points to AGENTS.md.
AGENTS.md Adds agent guidance note about Next.js breaking changes.
.gitignore Adds Next.js/Node/Env/Clerk ignore patterns.
Comments suppressed due to low confidence (1)

src/app/api/webhooks/clerk/route.ts:44

  • Typo in error message: "occured" → "occurred".
    return new Response('Error occured', {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +28
// Get the body
const payload = await req.json();
const body = JSON.stringify(payload);

// If there are no headers, error out
if (!svix_id || !svix_timestamp || !svix_signature) {
return new Response('Error occured -- no svix headers', {
Comment on lines +9 to +11
if (!WEBHOOK_SECRET) {
throw new Error('Please add CLERK_WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local');
}
Comment on lines +42 to +48
<button className="btn-p" style={{ width: 'auto', height: '36px', fontSize: '.8rem' }}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="9 11 12 14 22 4"/>
<path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11"/>
</svg>
Open Ballot
</button>
Comment on lines +59 to +64
<div
key={c.id}
className={styles.candidateCard}
data-selected={selectedId === c.id}
onClick={() => setSelectedId(c.id)}
>
Comment thread src/lib/supabase.ts
Comment on lines +1 to +14
import { createClient } from '@supabase/supabase-js';

// ── Browser client (uses anon key + RLS) ─────────────────────────────────────
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://placeholder.supabase.co',
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || 'placeholder'
);

// ── Server / Admin client (bypasses RLS — server-side only) ──────────────────
export const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://placeholder.supabase.co',
process.env.SUPABASE_SERVICE_ROLE_KEY || 'placeholder',
{ auth: { autoRefreshToken: false, persistSession: false } }
);
Comment thread supabase/schema.sql
Comment on lines +64 to +65
create policy "voters_update_own" on voters
for update using (clerk_id = (current_setting('request.jwt.claims', true)::json->>'sub'));
.select('id')
.eq('election_id', election.id)
.eq('voter_id', voter.id)
.single();
Comment on lines +43 to +50
// 3. Insert the vote
const { error: voteError } = await supabaseAdmin
.from('votes')
.insert({
election_id: electionId,
voter_id: voter.id,
candidate_id: candidateId
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants