hart
a portfolio site for showcasing original artworks with google oauth, role-based access, contact form, and a protected admin dashboard
A portfolio site built with Next.js for showcasing original artworks. Visitors can browse the gallery, shop with a full checkout flow, and reach out via a contact form — with Google OAuth or credentials-based sign-in and a role-protected admin dashboard behind the scenes. still under active development.
key features
- Public portfolio pages (home, about, contact, shop, privacy)
- Art gallery with artwork showcase
- Shopping cart with multiple payment methods (card, PayPal, Apple Pay, Google Pay)
- Dual authentication: Google OAuth + credentials provider
- Role-based access control (admin vs customer)
- Contact form with optional image uploads to AWS S3
- Protected admin dashboard
- Admin message management (view and delete)
- Dynamic admin user creation via init endpoint
- Responsive design with Tailwind CSS and DaisyUI
tech stack
# frontend
next.js | react 19 | typescript | tailwind css | daisyui
# backend & auth
next.js api routes | nextauth (google oauth + credentials) | mongodb | mongoose
# infrastructure
aws s3 | vercel deployment
api endpoints
The backend exposes API routes across four route groups.
/api/contact # contact form submission with optional S3 upload
/api/admin/messages # fetch and delete contact messages (protected)
/api/admin/initAdmin # create initial admin user
/api/auth # nextauth session and provider handling
highlights
Portfolio showcase, Google sign-in, shopping checkout, and admin dashboard.










create drawing modal


archived messages page
Supporting two auth methods in the same app was trickier than expected. Google OAuth and credentials both feed into NextAuth but create users differently, and getting the role assignment and session shape consistent across both flows meant revisiting the schema a few times before it felt right.
The checkout flow added a different kind of complexity. Managing cart state across pages, handling multiple payment methods, and keeping that logic clean on the client while auth-gating the right routes server-side was the most layered thing I’d built in a single Next.js project.