feat(seed): require ADMIN_INITIAL_PASSWORD + convert setup-db to ESM (drop-public-setup) #13

Merged
varutasu merged 5 commits from convoy/drop-public-setup into main 2026-05-23 18:02:44 -04:00
2 changed files with 40 additions and 7 deletions
Showing only changes of commit ba1022b5db - Show all commits

View file

@ -44,6 +44,9 @@ A modern trading card game collection manager built with Next.js and Neon Databa
```env
POSTGRES_URL="postgresql://your-username:your-password@your-host/your-database"
JWT_SECRET="<generate with: openssl rand -hex 32>"
# Required for `npm run setup-db` — used once to hash the initial admin password.
# Set in .env.local for local dev, or as a CI secret if you run setup from CI.
ADMIN_INITIAL_PASSWORD="<generate with: openssl rand -base64 24>"
# Optional — exercise the rate limiter locally. Without them, `lib/rate-limit.js`
# warn-and-no-ops in dev. In production these are auto-provisioned by the
# Vercel Upstash Marketplace integration.
@ -51,6 +54,7 @@ A modern trading card game collection manager built with Next.js and Neon Databa
KV_REST_API_TOKEN="<your-upstash-rest-token>"
```
`JWT_SECRET` is **required**`lib/auth-secret.js` throws at import time if it's unset.
`ADMIN_INITIAL_PASSWORD` is **required** for `npm run setup-db` — the script exits with code 1 if it's unset.
4. **Set up the database**
```bash
@ -112,11 +116,29 @@ tcg-vault/
└── .env.local # Environment variables
```
## 🔐 Default Admin Account
## 🔐 First-time admin setup
After running the database setup:
- **Email**: admin@tcgvault.com
- **Password**: admin123
`npm run setup-db` creates a single admin user the first time it runs. The
password is read from the `ADMIN_INITIAL_PASSWORD` environment variable; the
script exits with code 1 (and does not open a database connection) if the
variable is unset or empty.
- **Local dev:** set `ADMIN_INITIAL_PASSWORD` in `.env.local` before running
`npm run setup-db`. Use `openssl rand -base64 24` (or any other strong
source) to generate the value.
- **CI / Vercel:** set `ADMIN_INITIAL_PASSWORD` as a project secret if setup
ever runs from CI. The env var is **only** read by the seed script; runtime
auth uses the per-user password stored in the database.
- **Admin email:** the seed creates `admin@tcgvault.com`. Change the password
immediately after first login via the app's profile settings.
> **Operators of envs that pre-date this change:** `npm run setup-db` is
> idempotent (`ON CONFLICT (email) DO NOTHING`) — re-running it with
> `ADMIN_INITIAL_PASSWORD` set will **not** rotate an existing admin row's
> password. If your environment was set up before this change and still has
> the prior weak default, rotate the password manually via the app
> after logging in, or wait for the queued `rotate-default-admin` follow-up
> convoy.
## 🤝 Contributing

View file

@ -13,6 +13,18 @@ require('dotenv').config({ path: '.env.local' });
const { neon } = require('@neondatabase/serverless');
async function setupNeonDatabase() {
const adminPassword = process.env.ADMIN_INITIAL_PASSWORD;
if (!adminPassword || !adminPassword.trim()) {
console.error(
'❌ ADMIN_INITIAL_PASSWORD environment variable is not set.\n' +
'\n' +
' Set it in .env.local for local dev, or as a CI secret if you run setup from CI.\n' +
' Generate a strong password with: openssl rand -base64 24\n' +
' See README.md → "First-time admin setup" for the full flow.\n'
);
process.exit(1);
}
const sql = neon(process.env.POSTGRES_URL);
try {
@ -128,7 +140,7 @@ async function setupNeonDatabase() {
// Create admin user
const bcrypt = require('bcryptjs');
const hashedPassword = await bcrypt.hash('admin123', 12);
const hashedPassword = await bcrypt.hash(adminPassword, 12);
await sql`
INSERT INTO users (email, password, role)
@ -141,8 +153,7 @@ async function setupNeonDatabase() {
console.log('');
console.log('📋 Database Details:');
console.log(' Database: Neon PostgreSQL');
console.log(' Admin User: admin@tcgvault.com');
console.log(' Admin Password: admin123');
console.log(' Admin user ready (email: admin@tcgvault.com)');
console.log('');
console.log('🔧 Next Steps:');
console.log(' 1. Test the API endpoints');