Files
pokemon-inventory/docs/IMPLEMENTATION-STATUS.md
T
2026-09-11 15:40:19 -04:00

32 KiB

Implementation Status

Last updated: 2026-09-11

Resume Here

Before changing code, read this document, AGENTS.md, and the linked source-of-truth documentation. Then confirm the current baseline with:

npm test

For persistence or Redis-backed changes, also run the isolated integration suite after setting TEST_DATABASE_URL to the *_test database and TEST_REDIS_URL to the test Redis instance:

TEST_DATABASE_URL='postgresql://...' TEST_REDIS_URL='redis://...' npm run test:integration

The current local container runtime is OrbStack. If Docker commands point at a stale host, run:

unset DOCKER_HOST
docker context use orbstack

Completed

Workspace And Database

  • Npm workspace with the API and shared contracts/validation packages.
  • PostgreSQL Compose service on local port 5433; API port 3000 is registered in .local/project-ports.json.
  • Redis Compose service on local port 6380 supports distributed login throttling.
  • Drizzle schema and migrations:
    • 0000_core_inventory: users, sellers, categories, condition profiles, conditions, products, and physical inventory items.
    • 0001_auth_sessions: hashed server-side sessions, expiry, revocation, IP address, and user agent.
    • 0002_session_csrf_tokens: session-bound hashed CSRF tokens.
    • 0003_security_audit_events: private append-only authentication security events.
    • 0004_password_reset_tokens: hashed, one-time password recovery tokens.
    • 0005_mfa_methods: protected TOTP method records and lifecycle state.
    • 0006_listings: listing records and lifecycle enum.
    • 0007_listing_image_count: persisted image prerequisite for publication.
    • 0008_inventory_images: item-owned image metadata and processing state.
    • 0009_remove_listing_image_count: publication no longer stores a listing-level image snapshot.
  • Isolated integration tests require a database name ending in _test and truncate only that database's tables.
    • Local-only npm run provision:admin creates the first Admin User and linked Seller atomically. It requires INITIAL_ADMIN_EMAIL, INITIAL_ADMIN_PASSWORD, and INITIAL_SELLER_NAME, hashes the password with scrypt, and refuses once any User exists.

Domain And Persistence

  • Product identity requires name, category, and seller.
  • Products receive seller-scoped, normalized slugs; duplicate names receive a numeric suffix.
  • Each Inventory Item is a separate physical copy.
  • Inventory condition must belong to the Product category.
  • Inventory lifecycle supports ACTIVE, SOLD, and ARCHIVED; sold and archived items are locked against ordinary edits.
  • Repositories for products, inventory items, conditions, users, and sessions use Drizzle/PostgreSQL.
  • Listing persistence supports draft creation, seller-scoped lookup, status updates, and inventory-item history.

API And Authentication

  • Fastify app bootstrap and GET /health response.
  • Admin Product endpoints:
    • GET /api/v1/admin/products
    • POST /api/v1/admin/products
  • Admin Inventory endpoint:
    • POST /api/v1/admin/inventory
  • Authentication endpoints:
    • POST /api/v1/auth/login
    • POST /api/v1/auth/logout
    • GET /api/v1/auth/me
  • Login uses asynchronous scrypt password verification. Session tokens are random, stored only as SHA-256 hashes, and never returned in JSON.
  • Session cookie settings are HttpOnly, SameSite=Strict, path /, and Secure in production.
  • Login is limited to five attempts per client IP every 15 minutes and returns 429 AUTH_RATE_LIMITED with Retry-After once exhausted. Redis atomically coordinates the limit across API processes.
  • Login sets a separate same-site CSRF cookie. Authenticated state-changing routes require its matching x-csrf-token header, validated against the session-bound hash.
  • GET /api/v1/auth/sessions returns safe metadata for the current user's active sessions and marks the current session. DELETE /api/v1/auth/sessions/:id revokes an owned session; DELETE /api/v1/auth/sessions revokes all other sessions while retaining the current one. Revoking the current session clears both cookies.
  • Active sessions renew last_activity_at after five minutes, avoiding a database write on every authenticated request.
  • Authentication events are retained separately from inventory activity. LOGIN_SUCCESS, LOGIN_FAILURE, SESSION_CREATED, and SESSION_REVOKED include the known actor where available, plus safe request context. Passwords and session/CSRF tokens or hashes are never recorded.
  • Password recovery uses generic POST /api/v1/auth/forgot-password responses to prevent account enumeration. Opaque tokens are delivered only through the SMTP adapter, stored only as hashes, expire after one hour, are consumed once, and revoke existing sessions after a password reset.
  • API startup requires SMTP_URL, SMTP_FROM, and PASSWORD_RESET_URL; configure these local values before starting the server.
  • Existing admin routes validate the authenticated session and derive seller ownership server-side.
  • Request schemas live in packages/validation; admin response DTOs live in packages/contracts.
  • MFA enrollment, verification, disable, protected secret handling, login verification, and audit events are implemented.
  • Admin listing creation and lifecycle routes are implemented:
    • POST /api/v1/admin/listings
    • GET /api/v1/admin/listings
    • GET /api/v1/admin/listings/:id
    • POST /api/v1/admin/listings/:id/publish
    • POST /api/v1/admin/listings/:id/unpublish
    • POST /api/v1/admin/listings/:id/pending
    • POST /api/v1/admin/listings/:id/archive
  • Listing publication is seller-scoped, CSRF-protected, and gated by persisted identity, price, physical inventory, condition, and image prerequisites.
  • Listing publication rejects physical inventory in SOLD or ARCHIVED status with a conflict response.
  • Listing reads are seller-scoped and return only admin listing DTO fields.
  • Item-owned image metadata can be added through a seller-scoped, CSRF-protected admin route; publication uses the persisted image count.
  • Public search is available at GET /api/v1/public/search through a normalized SearchService boundary with pagination, price filters, text matching, and sold-item visibility controls.
  • Public search also supports active category and condition lookup options, URL-backed filters, and allowlisted recent/price sorting.
  • Public search responses include items plus pagination metadata (page, limit, total, and totalPages); pending listings are visible by default and sold listings require an explicit filter.
  • Public product pages are available at GET /api/v1/public/products/:slug; responses use a public DTO and require an active physical item with an available or pending listing.
  • Public listing collection and detail reads are available at GET /api/v1/public/listings and GET /api/v1/public/listings/:id; collection responses include pagination metadata and detail reads hide internal inventory identity.
  • Public listing detail responses include safe condition labels, latest market value, and public image URLs; unavailable image states are rendered accessibly in the gallery.
  • Public listing and product detail responses and pages now surface the seller's display name and configured public contact methods (email/phone) from seller settings, covering the contact-method portion of the documented public detail requirement.
  • Public inventory collection and detail reads are available at GET /api/v1/public/inventory and GET /api/v1/public/inventory/:id; responses join only active physical items to available or pending listings and exclude private item notes.
  • The public seller directory is available at GET /api/v1/public/sellers; it returns only sellers with visible inventory and exposes display identity without user or contact fields.
  • The web workspace now has a Vue/Vite public catalog shell with Vue Router, a catalog API service, search composable, loading/error/empty states, and responsive search-first styling.
  • The web catalog now provides keyboard-accessible listing cards with stable /listings/:id links, a public listing detail page, and service-level detail loading/error handling.
  • Catalog search and pagination are synchronized to the browser URL (q and page) with accessible previous/next controls; the web port 5173 is declared in the project port registry.
  • The web catalog includes a stable /products/:slug product detail route with API-backed loading, not-found/error states, and semantic product facts.
  • The visual design foundation is centralized in web tokens with light/dark/system runtime theme support; the fixture composition has moved to Storybook at port 6006 with the accessibility addon and component stories for available, pending, and sold states.
  • ImageStorage, traversal-safe local storage, multipart upload transport, binary signature validation, and worker-backed derivative processing are implemented.
  • Derivative orchestration now defines thumbnail, medium, and large WebP storage outputs behind an injected renderer; the concrete worker-backed renderer remains.
  • The worker owns an image derivative job runner with explicit processing, completion, and failure outcomes backed by persistent PostgreSQL job records.
  • Image metadata limits are enforced in the service boundary: supported MIME types, 10 MiB default file size, and 10,000-pixel maximum dimensions.
  • Acquisition, sales, dashboard, pricing observations, market valuations, audited sale voiding, and manual market-value overrides are implemented with seller-scoped API and admin UI workflows.
  • Seller-scoped bulk archive is implemented through the CSRF-protected POST /api/v1/admin/bulk route; it validates active inventory lifecycle transitions and never substitutes for the dedicated sale workflow.

Verified Baseline

Suite Current coverage
Domain Product requirements and inventory lifecycle rules
Application Product slug allocation, condition compatibility, password verification/recovery, session issuance, activity renewal, management, and audit events
HTTP Product and inventory creation, validation, authentication/recovery, CSRF, rate limiting, and session management
Integration PostgreSQL catalog/session/audit/password recovery persistence and Redis-shared login throttling

Verified locally: npm test passes 178 tests with no failures (24 domain, 84 application, and 70 HTTP); worker tests, web tests, web build, Storybook build, Storybook interaction/accessibility checks, integration tests, and authenticated E2E workflows also pass when their required local services and credentials are available.

Public Seller Description

  • Sellers can save, edit, and clear an optional public description in Settings.
  • Descriptions are trimmed plain text, limited to 2,000 characters server-side, and stored in existing seller settings JSON without a migration.
  • Public listing and product detail pages render the description as escaped text with line breaks; public DTOs expose only the allowlisted field.
  • Dark-theme coverage also exposed and fixed insufficient status badge text contrast for Available, Pending, and Sold.
  • Coverage includes validation/partial-update/clearing tests, public HTTP contracts, PostgreSQL repository reads, settings edit/clear interactions, both public page integrations, and absent/plain-text/dark-theme component stories.
  • Validation: 166 API tests, 23 isolated PostgreSQL/Redis integration tests, 10 web tests, production web build, Storybook build, and Storybook interaction/accessibility runner (32 suites / 84 tests).

Public Browsing Accessibility

  • Public gallery labels use API image descriptions, controls wrap at narrow widths, and failed API image URLs have an accurate accessible fallback.
  • Long detail text and seller contacts reflow, read-only condition badges no longer add inactive buttons to keyboard navigation, and detail loading/errors expose announcement roles.
  • Added keyboard, 320px reflow, 200% text enlargement, and detail-state regression stories. Browser review and its native-zoom/screen-reader limitations are recorded in docs/ACCESSIBILITY.md.
  • Validation: 166 API tests, 10 web tests, production web build, Storybook build, and 32 Storybook suites / 93 tests. This frontend-only slice changes no persistence or API contracts.

Public Navigation Accessibility

  • Catalog cards use router links; catalog and detail pages have descriptive titles and named, focused main landmarks on entry.
  • Async responses and query updates preserve user focus. Filtered catalog URLs survive the explicit return link and browser Back; return destinations are restricted to the catalog.
  • Added three public browser navigation tests and return-path validation coverage; updated page/card Storybook interactions.
  • Validation: 166 API tests, 11 web tests, 3 public Playwright tests, production web build, Storybook build, and 32 Storybook suites / 93 tests. No API or persistence changes.
  • Screen-reader speech and native browser zoom remain manual review items; this slice verifies browser focus and title behavior.

Clear Public Contact Methods

  • Settings now sends explicit empty strings when a seller clears email or phone; help text explains removal. Omitted API fields still retain existing values.
  • Validation accepts empty/whitespace-only email as removal while rejecting invalid non-empty addresses. Both public detail repositories expose absent/cleared contacts as null.
  • HTTP coverage exercises real settings-service merging, validation, persistence reads and unchanged fields; PostgreSQL integration coverage verifies clear-one/clear-both behavior for listing and product detail projections.
  • Storybook covers clearing contacts while retaining the description and rendering seller information without contact links.
  • Validation: 167 API tests, 23 isolated integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 95 tests. No migration required.

Settings Error Recovery

  • Settings only exposes its form after a successful load. Failed reads offer Retry instead of editable defaults.
  • Keyboard retry restores focus to the description field on success or Retry on repeated failure.
  • Saving announces progress and disables fields/submission while in flight; failed saves retain edits and allow retry without reloading.
  • Storybook covers loading, load errors, successful/repeated retry, save failure/retry, saving/disabled states, mobile retry and dark-theme save recovery.
  • Validation: 167 API tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 102 tests. Frontend-only change; no API or persistence changes.

Saved Views Error Recovery

  • Failed list reads no longer show an empty-list message or create form; Retry restores keyboard focus on success or repeated failure.
  • Create/delete actions clear stale feedback, announce progress, and block conflicting actions. Create failures preserve drafts; delete failures preserve the view and focus; successful deletion announces completion and focuses the list heading.
  • Storybook covers populated/empty/loading/error states, load retries, create/delete recovery, invalid JSON, pending disabled states, mobile retry and dark-theme recovery.
  • Validation: 167 API tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 113 tests. Frontend-only change; API and persistence unchanged.

Image Manager Error Recovery

  • Loaded images and alt-text drafts survive action failures and refreshes. Initial-load errors offer Reload; refresh errors retain the gallery with writes disabled until reload succeeds.
  • Every action reconciles metadata even on failure, exposing partial multi-upload/reorder success without replaying mutations. Pending actions block overlapping writes and file drops.
  • Added page/component stories covering load/retry, edit/delete failure and retry, successful deletion followed by refresh failure, pending/disabled states, partial upload failure, mobile and dark-theme recovery.
  • Dark-theme coverage also fixed destructive-button contrast by separating its solid background token from error-text color.
  • Validation: 167 API tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 124 tests. No API or persistence changes.

Atomic Image Reordering

  • Move up/down now calls a single authenticated, CSRF-protected POST /api/v1/admin/images/:id/move operation. The server derives the adjacent image from current persisted order.
  • The repository locks the owning Inventory Item and its images, applies the domain move rule, and commits contiguous positions in one transaction. Ties are resolved deterministically; boundary moves are no-ops; primary state is preserved.
  • Tests cover invalid requests, ownership, CSRF, missing images, boundary moves, tied positions, rollback after the first write, concurrent moves, and UI success/failure recovery.
  • Validation: 171 API tests, 26 isolated PostgreSQL/Redis integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 126 tests. No migration required.

Image Update Validation

  • Legacy order updates require a non-negative PostgreSQL integer; alt-text updates require trimmed text up to 1,000 characters or explicit null. Missing/extra/mistyped fields are rejected before persistence.
  • Domain validation protects non-HTTP service callers as well. Authentication, CSRF and seller ownership remain unchanged.
  • The alt-text editor shows its limit, trims saved drafts, prevents oversized input and gives associated accessible feedback for oversized pre-existing text.
  • Validation: 174 API tests, 26 isolated integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 128 tests. No migration required.

Latest Vertical Slice: Server-Derived Upload Dimensions

  • Multipart uploads ignore client dimensions and persist inspected width/height plus actual buffer length. An injected Sharp inspector validates metadata and decoding before storage, metadata writes or job creation.
  • Existing MIME signatures, 10 MiB byte limit and 10,000-pixel dimension bounds remain enforced; decoder work is pixel-bounded. JSON metadata registration retains its separate existing contract.
  • Tests use actual JPEG/PNG/WebP data and cover forged/missing dimensions, forged byte counts, oversized dimensions, signature-only images and truncated pixel data whose header remains readable.
  • Validation: 178 API tests, 26 isolated integration tests, 11 web tests, production web build, Storybook build, and 32 Storybook suites / 128 tests. Existing Sharp dependency reused; no migration or visual changes.

Next bounded slice: enforce the configured per-item image count limit. docs/IMAGES.md requires configurable image counts and Settings exposes the limit, but image creation currently checks only individual-file metadata. Enforce the seller's limit atomically for uploads/metadata registration, reject excess images clearly, and cover concurrent uploads and UI feedback.

Next Milestone

Complete production configuration and operational maturity around the implemented vertical slices.

  1. Configure and validate an approved external pricing provider and provider-specific mapping data.
  2. Expand broader accessibility/manual coverage and address any remaining integration edge cases.

Acceptance criteria: production provider credentials are secret-managed, migrations and backups are exercised in the target environment, and CI runs integration, authenticated E2E, web, build, Storybook build, and Storybook interaction/accessibility gates.

CI also runs the worker suite, production dependency audit, and deployment/restore script contract checks.

Overall Roadmap

Work through one bounded vertical slice at a time. The linked documentation remains authoritative when this roadmap is less detailed.

Completed vertical slices include authentication, listings and image processing, acquisitions, sales and audited corrections, dashboard metrics/alerts, pricing observations and quality handling, provider mappings, durable pricing refresh jobs, public search/detail/image states, bulk operations, exports, settings, Saved Views, admin workflows, CI integration/E2E gates, production Docker packaging, rollback/health checks, PostgreSQL backup verification, restore drill scripts, image-storage restore support, and deployment smoke checks.

Remaining roadmap areas are approved external provider credentials/adapters, broader accessibility/manual coverage, and deployment-specific NAS/TLS validation.

Known Gaps

  • No initial User/Seller is provisioned in the development database yet. Run npm run provision:admin after setting its required local .env variables.
  • Listings are partially implemented: draft creation, seller-scoped reads, publication gating, lifecycle writes, archive behavior, sold/archived inventory checks, and item-owned image metadata are complete; storage-backed processing remains.
  • The provider abstraction, fixture provider, HTTP provider adapter, Product mapping workflow, durable refresh queue, worker execution, polling contract, retry policy, and completed-job purge operation are implemented. Production readiness still requires approved external provider credentials and provider-specific mapping data.
  • API and worker production startup now reject fixture pricing, missing provider endpoints, and non-HTTPS provider endpoints before opening runtime connections.
  • Pricing refresh requests now enqueue seller-scoped jobs and expose a safe GET /api/v1/admin/jobs/:id polling contract instead of doing provider work inline.
  • Product-level provider mappings now persist seller-scoped PRODUCT/SEARCH relationships and support active listing and controlled disabling.
  • Pricing refresh enqueue now resolves its provider from an active Product mapping and rejects unmapped Products explicitly.
  • Local development and CI can enable a deterministic fixture provider for end-to-end refresh coverage; production provider adapters remain explicitly configured deployment boundaries.
  • Pricing refresh jobs have a bounded three-attempt retry policy with exponential backoff. The worker schedules completed-job cleanup using configurable retention days and cleanup interval settings.
  • Bulk archive, asynchronous bulk pricing refresh, and Product-level bulk tag updates are implemented through the seller-scoped API boundary. Inventory SOLD remains intentionally exclusive to the audited sale workflow.
  • Admin inventory JSON export is implemented at GET /api/v1/admin/exports/inventory.json and serializes seller-scoped admin DTOs as a downloadable attachment.
  • Admin inventory CSV export is implemented at GET /api/v1/admin/exports/inventory.csv with escaped spreadsheet-safe fields and seller-scoped admin DTOs.
  • Admin inventory Excel-compatible export is implemented at GET /api/v1/admin/exports/inventory.xls using the XML workbook format and seller-scoped admin DTOs.
  • Seller-scoped admin settings are implemented through GET/PATCH /api/v1/admin/settings with strict category allowlists and server-side partial-update merging.
  • Seller-scoped saved-view CRUD is implemented through the documented admin API with validated filter maps and repository-level ownership checks.
  • Large inventory JSON exports can be enqueued through POST /api/v1/admin/exports/inventory.json/jobs, polled through GET /api/v1/admin/exports/jobs/:id, and downloaded after completion; the worker owns claim, completion, and failure processing.
  • Completed asynchronous inventory JSON exports can be downloaded through GET /api/v1/admin/exports/jobs/:id/download.
  • PostgreSQL restore verification and image snapshot restore scripts are implemented and covered by shell tests as part of the deployment drill workflow.
  • npm audit --omit=dev currently reports zero production vulnerabilities. Re-run the audit after dependency changes and review development-dependency findings separately before production releases.
  • Authenticated E2E coverage now verifies both the core catalog workflow and the Settings, Saved Views, and export-controls workflow.
  • Production dependency audit currently reports zero vulnerabilities with npm audit --omit=dev.
  • Public catalog sorting now supports recently added, recently updated, name A-Z, name Z-A, price low-to-high, and price high-to-low through a URL-synchronized atomic sort control. Broader inventory filter parity and market-value sorting remain.
  • Public catalog filtering now supports URL-synchronized set, event, and tag text filters through a reusable atomic text-filter control and the shared search API.
  • Public catalog filtering now supports explicit Available, Pending, Sold, and All status modes plus a 30-day Newly added toggle through the shared search API and atomic controls.
  • The admin workspace now includes a responsive guided inventory workflow stepper linking Product, Sources, Copy, Images, Pricing, and List stages, with progress derived from loaded admin state.
  • Product identification is now an extracted ProductIdentityStep molecule with empty/filled Storybook states, while preserving the existing create-product API workflow.
  • Source mapping is now an extracted ProviderMappingStep molecule with Product/Provider/PRODUCT-vs-SEARCH mapping states, while preserving existing mapping loading and save behavior.
  • Physical inventory creation is now an extracted InventoryCopyStep molecule with Product and condition selection states, while preserving the existing seller-scoped create-copy API workflow.
  • Image management is now surfaced as an extracted InventoryImagesStep molecule with missing-image status and direct links to the existing upload/processing manager route.
  • Pricing is now an extracted PricingReviewStep molecule covering observations, provider refresh, and reasoned manual overrides while preserving existing pricing API behavior.
  • Review and listing is now an extracted ReviewListStep molecule covering physical-copy selection and asking-price confirmation while preserving existing draft creation and publication lifecycle behavior.
  • The guided inventory workflow now has extracted Product, Source Mapping, Physical Copy, Images, Pricing, and Review/List frontend stages, each with colocated Storybook coverage.
  • Public catalog sorting now supports latest manual/calculated market value low-to-high and high-to-low, with null values placed last.
  • Public listing detail now shows market-value freshness and suppresses asking price for sold listings, with Storybook coverage for sold and valued states.
  • Public catalog filters now collapse behind an accessible mobile disclosure, show an active-filter count, and provide a reset action while preserving URL synchronization.
  • The admin image manager now supports multi-file upload with a drag-and-drop dropzone, per-image alt-text editing, primary selection, up/down reordering, and per-image retry/delete actions targeted at the correct image instead of the first uploaded image.
  • The guided inventory workflow is now a true single-step-at-a-time wizard: the stepper is clickable, only the active stage's panel is shown, Back/Next controls advance between stages, and the active stage persists across reloads through local storage.
  • Listing management (publish/mark pending) is now a dedicated /admin/listings screen with its own navigation entry; the guided workflow overview links to it and only tracks listing creation and a lightweight count for wizard completion.
  • Sale recording/voiding and acquisition recording are now dedicated /admin/sales and /admin/acquisitions screens with their own navigation entries; the guided workflow overview links to both instead of embedding their forms and history inline.
  • The guided wizard now manages focus and announces step changes: selecting a stage (via the stepper or Back/Next) moves keyboard/assistive-technology focus to that stage's labeled region and updates a live-region status announcement, with Storybook interaction coverage.
  • Seller-scoped latest market valuations are now readable through GET /api/v1/admin/valuations.
  • Physical inventory management (bulk archive, bulk pricing refresh, bulk tag updates, market valuations, and pricing job retry) is now a dedicated /admin/inventory screen with its own navigation entry; the guided workflow overview links to it and only tracks a lightweight inventory count for wizard completion.
  • Storybook now installs a lightweight router mirroring the app's named routes plus a mobile-viewport-forcing test-runner hook, enabling isolated page stories (including the public catalog) that use useRoute/useRouter or narrow-viewport CSS breakpoints.
  • The public catalog now has its own Storybook coverage, including an interaction test proving the mobile filter disclosure is keyboard-operable and correctly hides/reveals filter controls via aria-expanded. This review also found and fixed a real color-contrast failure in the catalog error-state text.
  • ListingDetailPage, ProductDetailPage, and AdminImagePage now have Storybook coverage. Adding it surfaced and fixed a color-contrast bug shared by all three: the "Back to catalog" link, pagination controls, and the selected image-gallery thumbnail were using the non-text-safe --color-interactive token instead of --color-interactive-text.
  • Per-item image limits are now enforced atomically for seller image creation and uploads, using inventory.maxImagesPerItem (default 10); concurrent inserts are serialized on the physical inventory item and return IMAGE_COUNT_LIMIT_REACHED at the configured cap.
  • Admin navigation now includes a keyboard-visible skip link to the main content region, with Storybook interaction coverage.
  • Admin inventory bulk archive, pricing refresh, tag, and retry actions now announce successful outcomes through a polite live region.
  • Admin inventory action announcements now have Storybook interaction coverage verifying the live-region contract.
  • Admin inventory valuation and pricing-job results now expose explicit screen-reader labels with item or job identity and state.
  • Admin sales and acquisition history rows now expose explicit screen-reader labels with record identity, status/date, and financial context.
  • Admin listing status cards now expose a programmatic product heading and status announcement for each listing.
  • Saved-view rows now expose an accessible view name, and the image-limit setting includes range guidance tied to its input.
  • Login errors now move focus to the announced error message so failed authentication is immediately available to keyboard and assistive-technology users.
  • Login error focus behavior now has Storybook interaction coverage using a deterministic failed-authentication response.
  • Admin logout now exposes a busy state and disables repeat activation while the session is being revoked.
  • Expired admin sessions now redirect to login with an accessible explanation that prompts the user to sign in again.
  • Session-expired login messaging now has Storybook interaction coverage.
  • Admin sale and acquisition amount fields now expose explicit units and optional-field guidance through associated help text.

Local Commands

npm install
npm run db:up
npm run db:migrate
npm run provision:admin
npm test

The Compose database requires a local .env created from .env.example. To prepare the test database once after bringing PostgreSQL up:

docker compose exec -T postgres sh -c 'createdb -U "$POSTGRES_USER" pokemon_inventory_test'

Then migrate it using its TEST_DATABASE_URL value as DATABASE_URL, and run integration tests with both TEST_DATABASE_URL and TEST_REDIS_URL set. See README.md for the environment-file prerequisites.

Suggested Resume Prompt

Read docs/IMPLEMENTATION-STATUS.md and continue the next bounded milestone. Verify the existing baseline first, follow AGENTS.md, and keep the change focused with tests.