A WCAG-compliant, multi-tenant web application for butterfly houses to track shipments, quality metrics, and historical records while delivering public-facing galleries and statistics.
Install via nvm (recommended) or download directly:
# Using nvm (reads .nvmrc automatically)
nvm install
nvm use
# Verify
node -v# Install via corepack (bundled with Node.js)
corepack enable
corepack prepare pnpm@10.29.3 --activate
# Or install standalone
npm install -g pnpm@10.29.3
# Verify
pnpm -vInstall Docker Desktop for your OS, then verify:
docker -v
docker compose versionDocker Compose runs PostgreSQL and Drizzle Studio. The Next.js dev server runs locally for fast hot reload.
# Install dependencies
pnpm install
# Copy environment variables
cp .env.example .env
# Edit .env and set AUTH_SECRET (generate one with: openssl rand -base64 32)
# Start Docker services (PostgreSQL + Drizzle Studio)
docker compose up -d
# Push database schema (run once, or after schema changes)
pnpm db:push
# Start dev server
pnpm dev| Service | URL | Description |
|---|---|---|
studio |
https://local.drizzle.studio | Drizzle Studio GUI (API on port 4983) |
db |
localhost:5432 | PostgreSQL 17 |
| dev | http://localhost:3000 | Next.js dev server (run locally) |
Each Docker service is independently restartable:
docker compose restart studio # Restart Drizzle Studio
docker compose restart db # Restart PostgreSQL
docker compose logs -f studio # Follow logs for a specific service
docker compose up -d --build # Rebuild after dependency changesdocker compose down # Stop and remove containers (volumes preserved)
docker compose down -v # Stop, remove containers, AND delete volumes (full reset)
docker compose stop # Stop containers without removing them
docker compose start # Restart stopped containersAfter changing package.json, rebuild to update the studio container's dependencies:
docker compose up -d --build studioOne time setup: ensure Docker is running and the database is empty.
Ensure the scripts/data/ directory contains the necessary JSON files for seeding:
users.jsonshipments.jsonsuppliers.jsoninstitution.jsoninstitution_news.jsonmaster_butterfly_list.json
Then run:
docker compose down -v # Reset Docker volumes if data exists (caution: deletes all data)
docker compose up -d
pnpm db:migrate # Apply Drizzle migration history from scratch
pnpm seed # Run seed script to populate initial data (Ensure .json files in scripts/data/ are present)Open http://localhost:3000 to view the app.
When a migration changes the local schema in a way that is easier to rebuild than backfill, the team should start from a clean local database instead of trying to preserve old dev data.
Current recommended reset flow:
git pull
docker compose down -v
docker compose up -d
pnpm db:migrate
pnpm seedNotes:
docker compose down -vremoves the local Postgres volume and deletes all local DB data.- Use
pnpm db:migrate, notpnpm db:push, so everyone applies the committed Drizzle migration history in order. pnpm seedexpects a fresh database and will stop if data already exists.- This is the preferred workflow for the new baseline
0000migration and follow-up schema migration.
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://postgres:postgres@localhost:5432/flutr-db |
AUTH_SECRET |
NextAuth encryption secret (NEXTAUTH_SECRET accepted as fallback) |
(required, generate your own) |
AUTH_URL |
Application base URL | http://localhost:3000 |
pnpm dev # Start dev server
pnpm build # Production build
pnpm start # Start production server
pnpm lint # ESLint check
pnpm test # Run Jest tests
pnpm format # Format code with Prettier
pnpm format:check # Check code formatting
pnpm db:generate # Generate Drizzle migrations
pnpm db:migrate # Run database migrations
pnpm db:push # Push schema directly to database
pnpm db:studio # Open Drizzle Studio GUI| Technology | Purpose |
|---|---|
| Next.js 16 | Framework (App Router) |
| TypeScript | Language |
| pnpm | Package manager |
| Tailwind CSS 4 | Styling |
| Shadcn/UI | Accessible UI component library |
| React Hook Form | Form management with Zod validation |
| Recharts | Charts and statistics |
| NextAuth 5 | Authentication (credentials, JWT) |
| PostgreSQL 17 | Database (via Docker) |
| Drizzle ORM | Type-safe database queries |
| Jest | Testing |
This project uses Conventional Commits enforced by commitlint. A commit-msg hook validates every commit message automatically.
PR titles must also follow conventional commits. All PRs are squash-merged using only the PR title as the commit message on
main.
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
| Type | When to use |
|---|---|
feat |
A new feature |
fix |
A bug fix |
docs |
Documentation only changes |
style |
Formatting, missing semicolons, etc. |
refactor |
Code change that neither fixes a bug nor adds a feature |
perf |
Performance improvement |
test |
Adding or updating tests |
build |
Changes to build system or dependencies |
ci |
CI/CD configuration changes |
chore |
Other changes that don't modify src or tests |
git commit -m "feat(shipments): add shipment creation form"
git commit -m "fix(auth): handle expired JWT refresh"
git commit -m "docs: update README prerequisites"See AGENTS.md for full project context, conventions, and workflow rules used by both contributors and AI agents (Claude, Cursor).
Detailed docs live in docs/:
| Document | Description |
|---|---|
| Architecture Overview | App structure, auth, data model |
| Rules | Development conventions and standards |
| Commands | Reusable workflow templates |