feat(seed): require ADMIN_INITIAL_PASSWORD + convert setup-db to ESM (drop-public-setup) #13
2 changed files with 40 additions and 7 deletions
30
README.md
30
README.md
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
Loading…
Reference in a new issue