Tech Details
Database Schema (Drizzle ORM)
users (Authentication)
id: UUID
email: TEXT
password: TEXT
createdAt: TIMESTAMPTZ
messages (Guestbook)
id: UUID
name: TEXT
message: TEXT
status: ENUM
createdAt: TIMESTAMPTZ
photos (Gallery)
id: UUID
filename: TEXT
title: TEXT?
url: TEXT
fileId: TEXT
size: INTEGER
order: INTEGER
category: ENUM
createdAt: TIMESTAMPTZ
ImageKit Storage Structure
memories/{uuid}.{ext} # Memory photos
event/{uuid}.{ext} # Event photos
- Automatic image optimization and CDN delivery
- Blur placeholders via plaiceholder
- Staging prefix:
stg/ (via IMAGEKIT_FOLDER_PREFIX)
Environment Variables
Required
DATABASE_URL
JWT_SECRET
IMAGEKIT_PRIVATE_KEY
IMAGEKIT_PUBLIC_KEY
IMAGEKIT_URL_ENDPOINT
Optional
IMAGEKIT_FOLDER_PREFIX
NEXT_PUBLIC_POSTHOG_KEY
NEXT_PUBLIC_POSTHOG_HOST
Email (Cron notifications)
EMAIL_HOST
EMAIL_PORT
EMAIL_USER
EMAIL_PASS
EMAIL_TO
Authentication Flow
- Admin submits credentials via login form
- Server action validates with bcrypt
- JWT token created with jose library
- Token stored in httpOnly cookie
- Middleware validates JWT on /admin/* routes
- Middleware checks user exists in database
Service Integrations
PostHog (Analytics & Error Tracking)
- User analytics: section views, form submissions, link clicks
- Error tracking:
apiError, mutationError, queryError
- All data hooks use
useErrorTracking for capture
ImageKit (Storage & CDN)
- Upload via server-side SDK
- Delete via fileId
- Automatic WebP conversion
- Blur placeholder generation
Email (Nodemailer)
- Daily digest at 8 PM via Vercel Cron
- Lists pending messages for moderation
- Fallback: GitHub Actions cron
Authorization Rules
- messages: Public read (approved only), admin write
- photos: Public read, admin write
- users: Admin only (no public access)