fix: run migrations on boot and stop failures rendering as empty (#23)
The storefront showed no inventory after deploying the categories/tags release. No data was lost: the code queried categories/item_tags/ items.category_id against a database where the migration had not been run, and that failure was invisible at every layer. Three changes, each addressing one layer: Migrations now run at container start, so deployed code cannot be ahead of the schema and the easily-forgotten manual `docker exec migrate.js up` step disappears. migrate.js waits for Postgres to accept connections first, since the NAS brings the DB container up slower than the app, and still exits non-zero so a bad migration stops the container rather than serving a half-migrated schema. Express 4 does not forward a rejected async handler, and no error middleware was mounted, so a failing query never responded at all. Async routes are now wrapped and an error middleware guarantees a 500. A hung request is indistinguishable from an empty result in the UI, which is how a schema mismatch came to read as "the store has no items". The storefront now separates "request failed" from "no items" and offers a retry. fetchItems/fetchFilterOptions throw on a non-OK response rather than returning the parsed error body, which would have been set as the item list and crashed the grid on .map. Also restores the project-context update from 7fb5764, which was left out of PR #24 and ended up dangling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -54,11 +54,16 @@ export async function fetchConfig(): Promise<SiteConfig> {
|
||||
export async function fetchItems(filters?: ItemFilters): Promise<Item[]> {
|
||||
const query = filters ? filtersToSearchParams(filters).toString() : '';
|
||||
const res = await fetch(query ? `/api/items?${query}` : '/api/items');
|
||||
// An error response still parses as JSON — as `{ error: ... }`, not an array.
|
||||
// Returning that unchecked would set it as the item list and crash the grid
|
||||
// on `.map`, so a failure has to surface as a rejection the caller can show.
|
||||
if (!res.ok) throw new Error('failed to load items');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function fetchFilterOptions(): Promise<FilterOptions> {
|
||||
const res = await fetch('/api/filters');
|
||||
if (!res.ok) throw new Error('failed to load filters');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user