Skip to content

RootLayer-Labs/Red-Loodle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

REDLOODLE

Documentation-first portfolio platform built with Next.js, Prisma, and PostgreSQL.

The system is split into:

  • Public portfolio pages (/home, /archive, /tags, /reflections, /about, /contact)
  • Admin CMS (/admin/*) for managing content and project lifecycle
  • DB-backed persistence for projects, reflections, settings, messages, activity, and notifications
  • Pluggable media storage (local, minio, s3, or uploadthing)

1. Core Capabilities

  • Admin authentication with role-based access (ADMIN write actions)
  • Admin password recovery (email verification code + secure reset flow)
  • Full project CRUD with publish/draft/private visibility rules
  • Slug-based project routing for public archive pages
  • Tags and tools auto-derived from project tools arrays (no manual tag manager)
  • Home/About content editable from admin and rendered on public pages
  • Contact form persistence with rate limiting and spam protections
  • Activity and notifications persisted in DB
  • Media uploads with provider switching (local <-> minio/s3 <-> uploadthing)
  • SEO baseline: route metadata, JSON-LD, sitemap, robots, admin noindex headers

2. Tech Stack

  • Next.js 15 (App Router)
  • React 19 + TypeScript
  • Prisma ORM + PostgreSQL
  • NextAuth credentials auth
  • Tailwind CSS
  • Vitest (unit) + Playwright (E2E)
  • Docker / Docker Compose
  • MinIO (local S3-compatible storage for development)

3. Architecture Overview

Public surface

  • /home: hero, status strip, featured projects, and system narrative
  • /archive: searchable/filterable public project index
  • /archive/[slug]: project details (public projects only)
  • /tags: tool index derived from project tools
  • /tags/[tool]: projects filtered by selected tool
  • /reflections: public process notes
  • /about: public identity and process story
  • /contact: inbound message form

Admin surface

  • /admin/login: credentials sign-in
  • /admin/forgot-password: request verification code
  • /admin/reset-password: verify code and reset password
  • /admin/projects: project list + CRUD entry points
  • /admin/projects/new: create project
  • /admin/projects/[slug]/edit: edit project and rich sections
  • /admin/media: upload/manage media assets
  • /admin/about: manage about page content + identity
  • /admin/home: manage home page content
  • /admin/reflections: reflections CRUD
  • /admin/settings: global site and display settings
  • /admin/messages: contact inbox
  • /admin/activity: event log
  • /admin/notifications: admin notifications feed

Service layers

  • src/lib/projects/*: project repository + cached public access
  • src/lib/content/*: home/about content repository and defaults
  • src/lib/settings/*: site settings repository, defaults, and public snapshot
  • src/lib/messages/*: contact message persistence
  • src/lib/events/*: activity and notifications persistence
  • src/lib/reflections/*: reflections persistence and visibility filtering
  • src/lib/storage/*: provider abstraction for upload/delete/public URL

4. Data Model (Prisma)

Main models:

  • User: admin/editor accounts
  • Project: project summary/lifecycle fields
  • ProjectContent: JSON content document for rich project sections
  • ProjectAsset: media records linked to projects
  • Reflection: reflection entries with tag metadata
  • SiteSettings: global site identity, links, labels, display preferences
  • HomePageContent: editable public home content
  • AboutPageContent: editable public about content
  • ContactMessage: contact form inbox records
  • ContactRateLimit: anti-spam and rate-limit tracking
  • PasswordResetCode: one-time verification codes for password recovery
  • ActivityEvent: persisted admin activity log
  • AdminNotification: persisted admin notifications

Important enums:

  • ProjectStatus, ProjectCategory, ProjectVisibility
  • ReflectionTagType, ReflectionVisibility
  • ActivityEventType, AdminNotificationType, AdminNotificationStatus

5. Visibility and Publishing Rules

  • Only PUBLIC projects are returned on public routes.
  • DRAFT and PRIVATE are excluded from public pages.
  • Admin routes can read/write all visibility states.
  • Project URLs are slug-based; slug remains the public identity key.
  • Tags are auto-derived from project tools. No manual tag CRUD.

6. Performance Baseline (Implemented)

Recent cleanup applied for speed and response efficiency:

  • Public project reads are memoized per request via src/lib/projects/public.ts.
  • Public settings snapshot is request-cached via src/lib/settings/public.ts.
  • Public pages use fully dynamic server rendering (dynamic = 'force-dynamic') for immediate DB-driven updates.
  • /archive now receives server-provided initial project data (removed extra client no-store API fetch).
  • next.config.mjs optimized for runtime delivery:
    • productionBrowserSourceMaps: false
    • compress: true
    • poweredByHeader: false

Note:

  • Build-time lint/type strict blocking is currently relaxed in next.config.mjs (ignoreBuildErrors, ignoreDuringBuilds) due existing legacy lint debt across many files. Keep this in mind before production hardening.

7. Prerequisites

  • Node.js 20+
  • npm 10+
  • Docker Desktop (recommended for local DB + MinIO)

8. Environment Setup

Create local env files:

cp .env.example .env
cp .env.example .env.local

PowerShell:

Copy-Item .env.example .env
Copy-Item .env.example .env.local

Key variables:

  • DATABASE_URL
  • NEXTAUTH_URL
  • NEXTAUTH_SECRET
  • ADMIN_EMAIL
  • ADMIN_PASSWORD
  • password reset vars (PASSWORD_RESET_*)
  • SMTP vars (SMTP_*, MAIL_BRAND_NAME)
  • STORAGE_PROVIDER (local | minio | s3 | uploadthing)
  • S3/MinIO vars (S3_*)
  • UploadThing vars (UPLOADTHING_*)
  • contact guard vars (CONTACT_*)
  • NEXT_PUBLIC_SITE_URL (canonical metadata/sitemap base)

9. Local Run (Node + Docker services)

  1. Install dependencies:
npm install
  1. Start database (and optionally MinIO):
docker compose up -d db minio minio-init
  1. Apply migrations:
npm run db:migrate
  1. Seed initial data:
npm run db:seed
  1. Start app:
npm run dev

App URL: http://localhost:4028

10. Docker Workflows

Dev container

docker compose up --build

or

npm run docker:dev

Stop containers

npm run docker:dev:down

Production profile locally

npm run docker:prod

Health endpoint:

  • GET /api/health

11. Database and Seeding

Scripts:

  • npm run db:generate -> Prisma client generation
  • npm run db:migrate -> create/apply dev migration
  • npm run db:migrate:deploy -> apply existing migrations
  • npm run db:migrate:status -> migration status
  • npm run db:migrate:resolve:init -> baseline old db push database
  • npm run db:bootstrap -> deterministic admin user bootstrap
  • npm run db:seed -> seed admin + projects + reflections + settings + page content

Deterministic admin bootstrap:

  • reads ADMIN_EMAIL, ADMIN_PASSWORD, ADMIN_USER_ID
  • always enforces admin role
  • optional password reset on seed: ADMIN_RESET_PASSWORD_ON_SEED=true

12. Auth and Admin Access

  • Auth provider: NextAuth credentials (/admin/login)
  • Session strategy: JWT
  • Middleware protects /admin/* (except login + forgot/reset password pages)
  • Admin write actions require ADMIN role
  • Forgot password flow:
    1. Request 6-digit code at /admin/forgot-password
    2. Verify code + set new password at /admin/reset-password
    3. Log in normally at /admin/login
  • For Gmail SMTP, use SMTP_HOST=smtp.gmail.com and an App Password in SMTP_PASS (not your normal Gmail password).
  • Reset flow hardening includes cooldowns, per-fingerprint rate limits, and basic bot/honeypot checks.

Notes:

  • ADMIN_EMAIL / ADMIN_PASSWORD are bootstrap defaults, not permanent runtime credentials.
  • You can change admin login email/password from Admin -> Settings -> Admin Access.

13. Media Storage and Upload Flow

Storage provider selected by STORAGE_PROVIDER:

  • local: files written to public/uploads
  • minio: local S3-compatible object storage
  • s3: AWS S3 compatible mode
  • uploadthing: UploadThing-managed object storage

Upload strategy:

  • S3_UPLOAD_MODE=proxy: uploads through app API, easiest for local CORS
  • S3_UPLOAD_MODE=presigned: direct browser upload to bucket using signed URL

UploadThing requirements:

  • UPLOADTHING_TOKEN
  • UPLOADTHING_APP_ID
  • Optional: UPLOADTHING_CDN_HOST (default ufs.sh)
  • Optional: UPLOADTHING_APP_ID_LOCATION (subdomain or path)

MinIO local defaults:

  • API: http://localhost:9000
  • Console: http://localhost:9001

14. Contact Security Controls

Configured via env:

  • CONTACT_RATE_LIMIT_WINDOW_SECONDS
  • CONTACT_RATE_LIMIT_MAX_ATTEMPTS
  • CONTACT_RATE_LIMIT_BLOCK_SECONDS
  • CONTACT_MIN_FORM_FILL_SECONDS
  • CONTACT_MAX_LINKS
  • CONTACT_FINGERPRINT_SALT

These are used to reduce abuse and spam submissions.

15. SEO and Discoverability

Implemented:

  • Per-route metadata (title, description, canonical, OpenGraph/Twitter)
  • Structured data (JSON-LD) on key pages
  • robots.ts and sitemap.ts
  • Admin X-Robots-Tag: noindex, nofollow, noarchive

Sitemap includes:

  • top-level public pages
  • public project detail pages
  • tool tag pages derived from project data

16. Scripts

Core:

  • npm run dev
  • npm run build
  • npm run start
  • npm run serve

Quality:

  • npm run lint
  • npm run lint:fix
  • npm run type-check
  • npm run test
  • npm run test:watch
  • npm run test:e2e
  • npm run test:e2e:headed
  • npm run check

DB:

  • npm run db:generate
  • npm run db:migrate
  • npm run db:migrate:deploy
  • npm run db:migrate:status
  • npm run db:migrate:resolve:init
  • npm run db:bootstrap
  • npm run db:seed

Docker:

  • npm run docker:dev
  • npm run docker:dev:down
  • npm run docker:prod

17. Testing Strategy

  • Unit tests: Vitest
  • E2E tests: Playwright (e2e/)
  • Suggested local pre-push gate:
npm run type-check
npm run test

Optional:

npm run lint
npm run build

18. Project Structure

prisma/                    Prisma schema, migrations, bootstrap, seed
public/                    Static files and local uploads
src/app/                   App Router routes, layouts, API handlers
src/lib/                   Domain repositories and shared services
src/data/                  Seed/static source data
e2e/                       Playwright tests
docker-compose.yml         Local stack: app + db + minio
Dockerfile                 Multi-stage Next.js image

19. Troubleshooting

Port 4028 already in use

  • Stop existing process/container using that port.
  • Then rerun:
docker compose down
docker compose up -d --build

Docker network still in use after down

  • Another container may still be attached.
  • Run:
docker ps
docker stop <container-id>
docker compose down

Prisma migration baseline needed

  • If DB was initialized via db push, run:
npm run db:migrate:resolve:init
npm run db:migrate:deploy

Upload works in admin but image not visible publicly

  • Verify STORAGE_PROVIDER and provider URL config (S3_PUBLIC_BASE_URL or UPLOADTHING_*).
  • For MinIO, ensure bucket is created and public-read policy is applied by minio-init.

Build taking too long in constrained environments

  • Use Docker cache and stable network.
  • Run local type-check first to catch fast failures:
npm run type-check

20. Production Hardening Checklist

  • Replace default admin credentials
  • Set strong NEXTAUTH_SECRET
  • Use managed PostgreSQL
  • Use real S3 bucket + IAM credentials
  • Set NEXT_PUBLIC_SITE_URL to production domain
  • Tighten CORS and bucket policies
  • Address lint debt and remove build ignore flags
  • Add CI gate for migrations + tests + E2E smoke

21. OCI VM + Domain + HTTPS (Recommended Path)

This repo now includes:

  • docker-compose.prod.yml (app + postgres + migration job + Caddy)
  • Caddyfile (automatic HTTPS via Let's Encrypt)
  • .env.production.example (copy to .env.production)

DNS prerequisites

Before starting containers:

  • Point A record for your domain to your OCI VM public IPv4
  • Open OCI ingress ports 80 and 443 to 0.0.0.0/0
  • Keep SSH (22) restricted to your IP

Prepare env on the VM

cp .env.production.example .env.production

Set at minimum in .env.production:

  • DOMAIN
  • ACME_EMAIL
  • NEXTAUTH_URL
  • NEXT_PUBLIC_SITE_URL
  • POSTGRES_* and DATABASE_URL
  • NEXTAUTH_SECRET
  • ADMIN_EMAIL and ADMIN_PASSWORD

First deploy

docker compose -f docker-compose.prod.yml up -d --build

What happens:

  • db starts and becomes healthy
  • migrate runs prisma migrate deploy once
  • app starts on internal port 4028
  • caddy serves public 80/443 and provisions TLS certs

Verify

docker compose -f docker-compose.prod.yml ps
docker compose -f docker-compose.prod.yml logs -f caddy
docker compose -f docker-compose.prod.yml logs -f app

Open:

  • https://your-domain
  • https://your-domain/api/health

Redeploy after code changes

docker compose -f docker-compose.prod.yml up -d --build

Notes

  • Do not expose Postgres port publicly.
  • Keep NEXT_PUBLIC_SITE_URL as your final HTTPS URL for canonical/SEO metadata.
  • If certificate issuance fails, confirm DNS and that ports 80/443 are reachable from the internet.

For contribution workflow details, see CONTRIBUTING.md.

About

Documentation-first portfolio platform with public project pages, admin content management, media storage, authentication, contact workflows, SEO, Docker deployment, and database-backed publishing controls.

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages