Skip to content

ShinobiKoda/hihami

Repository files navigation

Supabase table (reference)

Create a table nfts with columns:

  • id: uuid (default uuid_generate_v4()) primary key
  • name: text not null
  • description: text
  • media_url: text not null
  • media_type: text not null # e.g., image/png, video/mp4
  • price_eth: numeric
  • chain: text not null # e.g., ethereum, polygon, sepolia
  • owner_email: text
  • owner_username: text
  • created_at: timestamp with time zone default now()

And a public storage bucket if you plan to upload files via Supabase Storage (not wired yet here).

HiHami

Full-stack Next.js app with Supabase auth (custom email verification via OTP), profile management, and password reset flow. Animated UI built with motion.

Features

  • Next.js App Router (src/app)
  • Supabase Auth (SSR cookies via @supabase/ssr)
  • Signup with username + email/password
    • OTP verification emailed via Resend
    • OTP expires after 10 minutes
  • Login with email/password
    • Blocks unverified users
    • Custom message if email doesn’t exist
  • Forgot password
    • Sends Supabase reset link
    • Non-enumerable responses (always generic success)
    • Reset page updates password using recovery session
  • Minimal user menu on Home page showing username and email
  • Type-safe validation with Zod and React Hook Form

Project Structure

  • src/lib/supabase/
    • server.ts: SSR Supabase client with cookie management
    • admin.ts: service-role client for server actions
    • browser.ts: browser client for client-side flows (reset password)
  • src/app/api/auth/
    • signup/route.ts: creates user, writes profile, generates OTP, sends email
    • verify-otp/route.ts: checks OTP + expiry, verifies auth email
    • login/route.ts: signs in; if fail, checks if email exists, returns tailored errors
    • forgot-password/route.ts: sends reset link and returns generic success
  • src/app/(auth)/
    • signup/: signup UI
    • login/: login UI
    • verify-email/: OTP input UI (expects uid and email query)
    • forgot-password/: request reset UI
    • reset-password/: set new password after email link
  • src/app/Home/page.tsx: sample home with user icon popover

Requirements

Create a .env.local with:

NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
SUPABASE_SERVICE_ROLE_KEY=... # server-only
NEXT_PUBLIC_SITE_URL=http://localhost:3000 # for building reset links

# Email provider for OTP (Resend)
RESEND_API_KEY=...
EMAIL_FROM="Enefty <[email protected]>"

Database tables (Supabase):

  • profiles (RLS as needed)
    • id: uuid (PK, references auth.users.id)
    • username: text (unique)
    • is_verified: boolean
    • otp_code: text (sha256 hex)
    • otp_expires_at: timestamptz

Development

Install dependencies and run dev server:

npm install
npm run dev

Open http://localhost:3000

Auth Flows

  1. Signup
  • POST /api/auth/signup with email/password/username
  • Creates user, saves profile, emails OTP
  • UI redirects to /verify-email?uid=...&email=...
  1. Verify Email
  • POST /api/auth/verify-otp with uid + otp
  • Verifies if OTP matches and not expired; sets is_verified
  1. Login
  • POST /api/auth/login
  • If bad credentials and email not found: returns "You don't have an account. Sign up"
  • If unverified: blocks login
  1. Forgot/Reset Password
  • POST /api/auth/forgot-password with email (always returns generic success)
  • User clicks email link to /reset-password?type=recovery...
  • Page updates password via supabase.auth.updateUser({ password })

Notes

  • OTP is 4 digits; stored as SHA-256 hash with 10-minute expiry.
  • The forgot-password endpoint avoids account enumeration by returning generic success.
  • Ensure NEXT_PUBLIC_SITE_URL is set correctly in production for password reset links.

Scripts

  • npm run dev – start dev with Turbopack
  • npm run build – build
  • npm run start – start production server
  • npm run lint – run eslint

License

MIT

Releases

No releases published

Packages

No packages published

Languages