openvibers/openvibe.shoes AGENTS.md
AGENTS.md
AGENTS.md — OpenVibe.Shoes
Project overview
OpenVibe.Shoes is the network's shoe resource at https://open.shoes: one page per model with every
store's all-in offer, Shoes' own daily price history and size-price curve, cited specs/fit/care notes,
and an official drops calendar. A person can watch a price or paste a listing link, which Shoes hands
to OpenVibe.Watch.
- Entry:
server/index.js(Express); app wiring inserver/http/router.js; port5180,
service idshoes, env prefixSHOES. - Pages:
server/http/pages.js(server-rendered HTML viaserver/render/layout.js/html.js,
server/views/index.js); own CSS inpublic/css/. No SPA and no build step. - API:
server/http/api.js(/api/v1), OpenAPI inserver/http/openapi.js, discovery in
server/http/discovery.js(robots, sitemap, llms.txt), SSO inserver/auth/. - Domain:
server/domain/parse.js(pure source parsers),server/domain/drops.js(release
calendar); jobs inserver/jobs/(offers.js,drops.js,ebay.js). - Identity:
server/identity/andserver/auth/for Network sessions; the person's own token is
forwarded to Watch and Today.
Owns, does not own
Owns the shoe catalogue, offers and daily snapshots, drops, watches stored on Shoes, cited facts and
job-run records (shoe_models, shoe_offers, shoe_snapshots, shoe_drops, shoe_watches,
shoe_facts, shoe_job_runs, account_data_events, telemetry_samples). It publishes a search
index document and its share of account export/deletion.
Does not own: store catalogues or prices (Deals and the official APIs are the sources), a person's
general watch list (OpenVibe.Watch — Shoes forwards the link and keeps only its own shw_ row), the
calendar (OpenVibe.Today), or any checkout. No raffle, draw, reservation or checkout is automated,
ever; no affiliate links, no sponsored ordering and no Marketplace scraping.
Who calls it, what it calls
Public pages and GET /api/v1/* need no token; a signed-in person's writes (watch, remind) use their
Network session. Shoes calls OpenVibe.Deals' public offer/product APIs, the eBay Browse API only
when a developer key pair is configured, the official release calendar/rSS feeds, and the person's
own Network token to call OpenVibe.Watch (shw_ ↔ remote watch) and OpenVibe.Today (drop
reminders). A missing source key turns that source off with a plain note, never an error.
Database and migrations
PostgreSQL through openvibe-sdk/db; migrations migrations/NNNN_*.sql (0001 initial, 0002 search
index, 0003 shares, 0004 outbox, 0005 product catalog), applied at boot with the owner role. Tests use
PGlite; npm run test:pg runs the same suite through PgBouncer. Never edit a migration that has run;
a schema removal waits for a contract migration. Each job writes one shoe_job_runs row (counts and
errors) and refuses to start under SHOES_DRILL=1; tests call runOnce().
Frontend loading model
Every page is server-rendered HTML with the shared Frame (openvibe-shared/shell, navbar/footer,
/shared/*); page-specific CSS is in public/css. There is no bundler and no route-feature loader.
Interactive bits (watch form, reminder, the small price chart) are inline server output plus small
scripts; keep pages usable without JavaScript and phone-first.
Auth
Network SSO (RS256 JWT + session cookie) using the shoes OAuth client; public reads are anonymous.
A person's Watch/Today call uses their own Network token — never a service token on their behalf. A
session without a usable token can still save the watch on Shoes, marked "not connected". Forms are
origin-checked; /internal/events is HMAC-verified and loopback-only.
Deploy
Install deploy/systemd/openvibe-shoes.service and deploy/nginx/open.shoes.conf; the unit reads
/etc/openvibe/shoes.env, works in /opt/openvibe.shoes, runs as ubuntu:ubuntu on
127.0.0.1:5180. The vhost proxies /api/, /auth/ and the forms with their own limits.
sudo ovhost deploy shoes is the production path (git-checkout, install on lockfile change,
restart, wait for /api/ready); rollback with sudo ovhost rollback shoes --to <sha>.
Commands and tests
npm ci --include=dev
npm start # http://127.0.0.1:5180
npm test # every test/*.test.js, PGlite, mock Network
npm test -- importer # only matching files
npm run test:pg # the same through PgBouncer
npm run seed # one run of every job against live sources (needs the network)
test/run.js uses openvibe-shared/test-runner (90 s, serial); files get a temp PGlite database and
an in-process Network mock, never the network. Tests cover the parsers and all-in price, snapshots
(first check per offer per day wins), the jobs' stop/error behavior, the API and pages, Watch/Today
forwarding, account export/deletion and the shared discovery artifacts. VERBOSE=1 shows each file's
output.
Conventions and pitfalls
- CommonJS, 4-space indent, single quotes, semicolons; no linter. Paths and domain logic stay in
server/domain/so a parser is testable without HTTP. - Prices are all-in (price + stated shipping); keep currency and the source's own check time, and
mark a stale offer rather than hiding it. - The first snapshot of an offer per day wins (unique key); do not overwrite history.
- Cite or say "not known yet": never invent a spec, fit note or release date; a parser that
cannot read a date leaves it out. - Respect the source rules: Deals public pages, eBay's official API only with keys, official
release pages; no scraping of Marketplace or Facebook, no affiliate URLs. - New environment variables go in
.env.exampleand the README list; secrets live only in
/etc/openvibe/shoes.env.