Closes P0 #3 from .convoys/ship-readiness.md. scripts/setup-neon-db.js: - Read ADMIN_INITIAL_PASSWORD env var at the top of setupNeonDatabase() before any DB connection. Fail loudly (process.exit(1)) with an actionable message if unset or empty. - Replace bcrypt.hash('admin123', 12) with bcrypt.hash(adminPassword, 12). - Delete the two console.log lines that echoed admin user + password to stdout (R3 - stdout leak into CI logs). - Keep ON CONFLICT (email) DO NOTHING unchanged. Re-running setup-db on an env with the admin row already present is a no-op for the password (R4 - silent rotation prevention). Rotation of existing weak-hash admin rows is out of scope (Decision A - queued for the rotate-default-admin follow-up convoy). README.md: - Add ADMIN_INITIAL_PASSWORD to the install-step env-example block with a CI-secret note (and add KV_REST_API_URL/KV_REST_API_TOKEN for completeness; they're optional for local dev). - Replace the "Default Admin Account" section with "First-time admin setup", documenting the env var, openssl rand suggestion, and the operator rotation note for envs that predate this change. - Zero occurrences of 'admin123' remain in README.md (the operator rotation note refers to "the prior weak default" instead of naming the literal string, so grep verification A2 holds). Decisions A1 (going-forward only), B (operational change allowed), C1 (no vitest coverage - manual smoke in PR description) per .convoys/drop-public-setup.md section Decisions. Smoke output: see PR description. Co-authored-by: Cursor <cursoragent@cursor.com>
152 lines
No EOL
5.5 KiB
Markdown
152 lines
No EOL
5.5 KiB
Markdown
# TCG Vault
|
|
|
|
A modern trading card game collection manager built with Next.js and Neon Database.
|
|
|
|
## 🚀 Features
|
|
|
|
- **Card Management**: Track your MTG, Pokémon, and Lorcana cards
|
|
- **Collection Organization**: Create and manage card collections
|
|
- **Deck Building**: Build and share decks
|
|
- **Authentication**: Secure user accounts with JWT
|
|
- **Admin Panel**: Manage cards and users
|
|
- **Real-time Pricing**: Track card values
|
|
|
|
## 🛠️ Tech Stack
|
|
|
|
- **Frontend**: Next.js 16 (Pages router), React 18, JavaScript (TypeScript is a devDep only — see `AGENTS.md` Gotcha #9)
|
|
- **Backend**: Next.js API Routes
|
|
- **Database**: Neon PostgreSQL (serverless)
|
|
- **Authentication**: JWT with bcrypt (24-hour expiry; `lib/auth-secret.js` is the single source of truth for `JWT_SECRET`)
|
|
- **Rate limiting**: `@upstash/ratelimit` on `/api/auth/login` + `/api/auth/register` (5 attempts / 15 min per IP)
|
|
- **Testing**: Vitest (unit); Playwright queued
|
|
- **Styling**: Tailwind CSS
|
|
- **Deployment**: Vercel
|
|
|
|
## 📦 Installation
|
|
|
|
1. **Clone the repository**
|
|
```bash
|
|
git clone <repository-url>
|
|
cd tcg-vault
|
|
```
|
|
|
|
2. **Install dependencies**
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
3. **Set up environment variables**
|
|
```bash
|
|
cp .env.example .env.local
|
|
```
|
|
|
|
Update `.env.local` with your Neon database URL and a real JWT secret:
|
|
```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.
|
|
KV_REST_API_URL="https://<your-upstash-host>.upstash.io"
|
|
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
|
|
npm run setup-db
|
|
```
|
|
|
|
5. **Start development server**
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
## 🗄️ Database Schema
|
|
|
|
The application uses the following tables:
|
|
- `users` - User accounts and authentication
|
|
- `cards` - Card information and metadata
|
|
- `user_cards` - User's card collections
|
|
- `collections` - Named card collections
|
|
- `collection_cards` - Cards in collections
|
|
- `decks` - Deck definitions
|
|
- `deck_cards` - Cards in decks
|
|
|
|
## 🔧 API Endpoints
|
|
|
|
### Authentication
|
|
- `POST /api/auth/register` - User registration
|
|
- `POST /api/auth/login` - User login
|
|
|
|
### Admin
|
|
- `GET /api/admin` - Admin panel data
|
|
|
|
### Health Check
|
|
- `GET /api/health` - Application health
|
|
|
|
> **Note:** Earlier revisions of this README also listed `GET /api/test-db` (and three other unauthenticated dev endpoints: `/api/simple`, `/api/test-auth`, `/api/setup-database`). All four were deleted in `fix-auth-bypass` Brief 3 (commit `fc0dd73`) and CI now blocks their reintroduction. Don't recreate them.
|
|
|
|
## 🚀 Deployment
|
|
|
|
This app is configured for deployment on Vercel:
|
|
|
|
1. **Connect your repository** to Vercel
|
|
2. **Set environment variables** in Vercel dashboard
|
|
3. **Deploy automatically** on push to main branch
|
|
|
|
## 📁 Project Structure
|
|
|
|
```
|
|
tcg-vault/
|
|
├── pages/ # Next.js pages and API routes
|
|
│ ├── api/ # API endpoints
|
|
│ │ ├── auth/ # Authentication routes
|
|
│ │ └── admin/ # Admin routes
|
|
│ ├── _app.js # App wrapper
|
|
│ └── index.js # Home page
|
|
├── lib/ # Utility libraries
|
|
│ └── database.js # Database adapter
|
|
├── scripts/ # Database setup scripts
|
|
├── public/ # Static assets
|
|
└── .env.local # Environment variables
|
|
```
|
|
|
|
## 🔐 First-time admin setup
|
|
|
|
`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
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch
|
|
3. Make your changes
|
|
4. Submit a pull request
|
|
|
|
## 📄 License
|
|
|
|
MIT License - see LICENSE file for details |