fragginwagon f7152bcff3 feat: add multipart image uploads
Register Fastify multipart support, validate JPEG/PNG/WebP binary signatures, store upload bytes through ImageStorage, persist metadata after storage succeeds, clean up bytes on metadata failure, and document the upload boundary. Verification: npm test passed 68 tests and integration passed 14 tests. No build script is configured.
2026-09-08 17:38:27 -04:00
2026-09-08 17:38:27 -04:00
2026-09-08 17:38:27 -04:00
2026-09-08 17:38:27 -04:00

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. 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.

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. 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; keep it in secret management and retain it for as long as enrolled MFA methods must remain readable.

S
Description
No description provided
Readme
3 MiB
Languages
JavaScript 79.8%
Vue 15.3%
SCSS 3.4%
Shell 1.4%