The cubeconsulting.org website, rebuilt in Next.js so the team can edit it in code instead of through the Wix editor. Includes a members-only portal with calendar, points tracker, and resources.
- Framework: Next.js 16 (App Router) + TypeScript
- Styling: Tailwind CSS v4 with custom brand tokens
- Auth: NextAuth v5 (Auth.js) with Google OAuth + email allowlist
- Data: Google Sheets API for the points tracker
- Hosting: Vercel
- Forms: Formspree (contact form)
npm install
cp .env.example .env.local # fill in real values, see "Configuration"
npm run dev # http://localhost:3000app/
layout.tsx root layout (fonts, metadata)
(public)/ public site
layout.tsx public header + footer
page.tsx home
projects/, services/, about/, join-us/, contact/
not-found.tsx
portal/ members-only area (auth-gated)
layout.tsx portal chrome
page.tsx dashboard
sign-in/page.tsx
api/
auth/[...nextauth]/ NextAuth handlers
points/ Sheets-backed points API
components/ shared UI (Header, Hero, ProjectShowcase, …)
components/portal/ portal-only components
lib/
content.ts single source of truth for site copy
team.ts executive board roster
sheets.ts Google Sheets reader
auth.ts NextAuth config (Google + allowlist)
middleware.ts protects /portal/*
public/ images and downloadable assets
Almost all marketing copy lives in lib/content.ts. To update a project, FAQ, recruitment date, or alumni list, edit the relevant constant and commit. The Executive Board roster is in lib/team.ts.
All env vars are documented in .env.example. Summary:
NEXT_PUBLIC_FORMSPREE_ID— Formspree project ID for the Contact form. Without it the form simulates submissions in dev.
AUTH_SECRET—openssl rand -base64 32AUTH_GOOGLE_ID/AUTH_GOOGLE_SECRET— Google OAuth client credentials. Set redirect URI tohttps://<your-domain>/api/auth/callback/google.PORTAL_ALLOWLIST— comma-separated lowercase emails. Anyone signed in via Google whose email isn't on this list will be bounced. Leave blank in dev to allow any Google user.
NEXT_PUBLIC_CALENDAR_EMBED_SRC— the public embedsrcfrom Google Calendar. Calendar settings → "Integrate calendar" → "Embed code" → copy thesrc=…URL.
POINTS_SHEET_ID— long ID from the Sheet's URL.POINTS_SHEET_RANGE— defaults toPoints!A2:B. Column A = name, Column B = points.GOOGLE_API_KEY— API key with Sheets API enabled. Share the Sheet "Anyone with the link can view".
If POINTS_SHEET_ID or GOOGLE_API_KEY is missing, the points UI falls back to a baked-in demo roster so the page is still explorable.
- Push to
mainon GitHub. - Import the repo at vercel.com → Add new project.
- Add every var from
.env.examplein the Vercel project's Environment Variables section. - Set
AUTH_TRUST_HOST=trueif Vercel doesn't auto-detect the deployment URL. - Set the Google OAuth redirect URI to
https://<your-vercel-url>/api/auth/callback/google.
| Route | Purpose |
|---|---|
/ |
Home (hero, pillars, photo gallery, testimonials) |
/projects |
Spring 2026 projects with team rosters |
/services |
Multidisciplinary Solutions, service categories, testimonials |
/about |
Mission, exec board, alumni placements |
/join-us |
Recruitment timeline, FAQs, photo carousel |
/contact |
Contact form (Formspree) |
/portal |
Member dashboard (auth required) |
/portal/sign-in |
Google sign-in |
/about-1, /s-projects-basic |
308 redirects to new slugs (old Wix URLs) |
npm run dev— local dev servernpm run build— production buildnpm run start— serve the production buildnpm run lint— ESLintnode scripts/scrape-assets.mjs— one-off: pulls images from the old Wix site intopublic/scraped/