148 lines
6.5 KiB
Markdown
148 lines
6.5 KiB
Markdown
# Pokémon Inventory & Sales Reference Catalog
|
|
|
|
A personal Pokémon inventory and sales reference catalog for documenting owned Pokémon products, comparing market pricing from supported providers, and presenting public asking prices.
|
|
|
|
## Scope
|
|
|
|
This is a catalog and sales-reference application, not an e-commerce platform.
|
|
|
|
The application supports:
|
|
- Pokémon trading cards
|
|
- Pokémon merchandise
|
|
- Sealed products
|
|
- Accessories
|
|
- Pokémon Worlds / Pokémon Center merchandise
|
|
- Other Pokémon-related products
|
|
|
|
The public site communicates what is available, what the market suggests it is worth, and what the seller is asking. Transactions occur outside the application.
|
|
|
|
## Core domain model
|
|
|
|
`Product → Inventory Item → Listing → Sale`
|
|
|
|
- **Product:** what an item is.
|
|
- **Inventory Item:** an individual physical copy owned by the seller.
|
|
- **Listing:** the current public offer for an inventory item.
|
|
- **Sale:** a manual record of an external transaction.
|
|
|
|
Products remain in the database after inventory is sold.
|
|
|
|
## Technology
|
|
|
|
- Vue 3 + Vite
|
|
- Modern JavaScript / latest ECMAScript
|
|
- Vue Router
|
|
- Pinia where justified
|
|
- Node.js + Fastify
|
|
- PostgreSQL + Drizzle ORM
|
|
- Redis + BullMQ
|
|
- REST API under `/api/v1`
|
|
- Docker + Docker Compose
|
|
- GitHub Actions
|
|
- PostgreSQL-backed search behind a `SearchService`
|
|
- Pluggable image storage and pricing-provider adapters
|
|
- Automated unit, integration, component, E2E, and accessibility tests
|
|
- WCAG 2.2 AA target
|
|
|
|
TypeScript is not used unless a documented technical justification establishes a concrete benefit that cannot reasonably be achieved with modern JavaScript.
|
|
|
|
## Repository layout
|
|
|
|
- `apps/web` — Vue frontend
|
|
- `apps/api` — Fastify API
|
|
- `apps/worker` — asynchronous jobs
|
|
- `packages/*` — genuinely shared contracts, validation, and safe utilities
|
|
- `database` — migrations and seeds
|
|
- `docs` — source-of-truth project documentation
|
|
- `.github` — Copilot instructions and CI
|
|
|
|
Read `AGENTS.md` and `.github/copilot-instructions.md` before implementing features.
|
|
|
|
## Implementation Status
|
|
|
|
Start future work from [docs/IMPLEMENTATION-STATUS.md](docs/IMPLEMENTATION-STATUS.md). It records the completed foundation, the next bounded milestone, the overall roadmap, and verification commands.
|
|
|
|
## Database Development
|
|
|
|
1. Copy `.env.example` to `.env` and replace `change-me` with a local-only password in both connection URLs.
|
|
2. Run `npm install`, `npm run db:up`, and `npm run db:migrate` to prepare the development database and Redis.
|
|
3. Create and migrate the isolated `pokemon_inventory_test` database before running integration tests.
|
|
4. Run `TEST_DATABASE_URL='postgresql://...' TEST_REDIS_URL='redis://...' npm run test:integration`.
|
|
|
|
Integration tests reject database names not ending in `_test` and truncate their tables before each test. The Redis limiter test uses a unique temporary key prefix and does not modify application session data.
|
|
|
|
## Local Development
|
|
|
|
After creating `.env`, set the required local SMTP and MFA values, then start the complete development stack from the repository root with:
|
|
|
|
```env
|
|
SMTP_URL=smtp://localhost:1025
|
|
SMTP_FROM=no-reply@example.test
|
|
MFA_ENCRYPTION_KEY=<output from: openssl rand -base64 32>
|
|
```
|
|
|
|
The MFA key must remain stable while enrolled MFA methods exist. Keep it in local secret storage and do not commit it.
|
|
|
|
```sh
|
|
npm run dev
|
|
```
|
|
|
|
This command starts healthy PostgreSQL and Redis containers, applies migrations, and runs the Fastify API, durable image worker, and Vue/Vite web app together. Open `http://localhost:5173/` in a browser. The Vite server proxies `/api` requests to the API on port `3000`.
|
|
|
|
The command does not provision an administrator automatically. Run `npm run provision:admin` once after setting the initial administrator variables in `.env` when admin access is needed. Stop the application processes with `Ctrl+C`; stop the containers separately with `npm run db:down` when they are no longer needed.
|
|
|
|
For a disposable local database reset, use:
|
|
|
|
```sh
|
|
npm run db:reset
|
|
npm run provision:admin
|
|
```
|
|
|
|
Or combine both operations with:
|
|
|
|
```sh
|
|
npm run db:reset:admin
|
|
```
|
|
|
|
`db:reset` removes the local PostgreSQL and Redis volumes, recreates healthy containers, and synchronizes the current Drizzle schema with `drizzle-kit push --force`. It is destructive and local-development-only. It does not modify `.env`.
|
|
|
|
## Visual Development
|
|
|
|
Run Storybook to inspect the authoritative design tokens and mock visual fixtures without requiring API data:
|
|
|
|
```sh
|
|
npm run storybook
|
|
```
|
|
|
|
Open `http://localhost:6006/`. Use the Storybook theme toolbar to switch between light and dark themes. The accessibility addon is enabled for component review. The fixture showcase is intentionally mock-only and is not part of the production router.
|
|
|
|
Seed representative API-backed catalog data for browser testing with:
|
|
|
|
```sh
|
|
npm run seed:demo
|
|
```
|
|
|
|
The seed is non-destructive and exits without changes when the demo catalog already exists.
|
|
|
|
## Browser Workflow Tests
|
|
|
|
With `npm run dev` running, configured local admin credentials, and demo lookup data available, run the authenticated browser workflow with:
|
|
|
|
```sh
|
|
npm run test:e2e
|
|
```
|
|
|
|
The authenticated workflows cover login, admin overview loading, product and physical inventory creation, image management, listing publication, sales and audited sale correction, settings updates, Saved Views CRUD, and export controls. They skip when `INITIAL_ADMIN_EMAIL` or `INITIAL_ADMIN_PASSWORD` is not configured.
|
|
|
|
## Initial Administrator
|
|
|
|
After the development database is migrated, set `INITIAL_ADMIN_EMAIL`, `INITIAL_ADMIN_PASSWORD`, and `INITIAL_SELLER_NAME` in your local `.env`, then run `npm run provision:admin` once. The command creates the only initial administrator and linked Seller; it refuses to run after any User exists.
|
|
|
|
## Password Recovery
|
|
|
|
Set `SMTP_URL`, `SMTP_FROM`, and `PASSWORD_RESET_URL` in the local `.env` before starting the API. For local development with an SMTP service listening on port `1025`, use `SMTP_URL=smtp://localhost:1025` and `SMTP_FROM=no-reply@example.test`. Password reset tokens are delivered only through SMTP, expire after one hour, are stored as hashes, and are single use.
|
|
|
|
## MFA Secret Protection
|
|
|
|
Set `MFA_ENCRYPTION_KEY` to a base64-encoded 32-byte key before starting the API. Generate one with `openssl rand -base64 32`, then paste the output after `MFA_ENCRYPTION_KEY=` in `.env`. A command that only runs `printf` displays the value but does not update `.env`. Keep the key in secret management and retain it for as long as enrolled MFA methods must remain readable.
|