openvibers/openvibe.shoes AGENTS.md

AGENTS.md

main 5.7 KB · 101 lines · markdown

1# AGENTS.md — OpenVibe.Shoes
2
3## Project overview
4
5OpenVibe.Shoes is the network's shoe resource at `https://open.shoes`: one page per model with every
6store's all-in offer, Shoes' own daily price history and size-price curve, cited specs/fit/care notes,
7and an official drops calendar. A person can watch a price or paste a listing link, which Shoes hands
8to OpenVibe.Watch.
9
10- **Entry:** `server/index.js` (Express); app wiring in `server/http/router.js`; port `5180`,
11 service id `shoes`, env prefix `SHOES`.
12- **Pages:** `server/http/pages.js` (server-rendered HTML via `server/render/layout.js`/`html.js`,
13 `server/views/index.js`); own CSS in `public/css/`. No SPA and no build step.
14- **API:** `server/http/api.js` (`/api/v1`), OpenAPI in `server/http/openapi.js`, discovery in
15 `server/http/discovery.js` (robots, sitemap, llms.txt), SSO in `server/auth/`.
16- **Domain:** `server/domain/parse.js` (pure source parsers), `server/domain/drops.js` (release
17 calendar); jobs in `server/jobs/` (`offers.js`, `drops.js`, `ebay.js`).
18- **Identity:** `server/identity/` and `server/auth/` for Network sessions; the person's own token is
19 forwarded to Watch and Today.
20
21## Owns, does not own
22
23Owns the shoe catalogue, offers and daily snapshots, drops, watches stored on Shoes, cited facts and
24job-run records (`shoe_models`, `shoe_offers`, `shoe_snapshots`, `shoe_drops`, `shoe_watches`,
25`shoe_facts`, `shoe_job_runs`, `account_data_events`, `telemetry_samples`). It publishes a search
26index document and its share of account export/deletion.
27
28Does not own: store catalogues or prices (Deals and the official APIs are the sources), a person's
29general watch list (OpenVibe.Watch — Shoes forwards the link and keeps only its own `shw_` row), the
30calendar (OpenVibe.Today), or any checkout. **No raffle, draw, reservation or checkout is automated,
31ever; no affiliate links, no sponsored ordering and no Marketplace scraping.**
32
33## Who calls it, what it calls
34
35Public pages and `GET /api/v1/*` need no token; a signed-in person's writes (watch, remind) use their
36Network session. Shoes calls OpenVibe.Deals' public offer/product APIs, the eBay Browse API only
37when a developer key pair is configured, the official release calendar/rSS feeds, and the person's
38own Network token to call OpenVibe.Watch (`shw_` ↔ remote watch) and OpenVibe.Today (drop
39reminders). A missing source key turns that source off with a plain note, never an error.
40
41## Database and migrations
42
43PostgreSQL through `openvibe-sdk/db`; migrations `migrations/NNNN_*.sql` (0001 initial, 0002 search
44index, 0003 shares, 0004 outbox, 0005 product catalog), applied at boot with the owner role. Tests use
45PGlite; `npm run test:pg` runs the same suite through PgBouncer. Never edit a migration that has run;
46a schema removal waits for a contract migration. Each job writes one `shoe_job_runs` row (counts and
47errors) and refuses to start under `SHOES_DRILL=1`; tests call `runOnce()`.
48
49## Frontend loading model
50
51Every page is server-rendered HTML with the shared Frame (`openvibe-shared/shell`, navbar/footer,
52`/shared/*`); page-specific CSS is in `public/css`. There is no bundler and no route-feature loader.
53Interactive bits (watch form, reminder, the small price chart) are inline server output plus small
54scripts; keep pages usable without JavaScript and phone-first.
55
56## Auth
57
58Network SSO (RS256 JWT + session cookie) using the `shoes` OAuth client; public reads are anonymous.
59A person's Watch/Today call uses their own Network token — never a service token on their behalf. A
60session without a usable token can still save the watch on Shoes, marked "not connected". Forms are
61origin-checked; `/internal/events` is HMAC-verified and loopback-only.
62
63## Deploy
64
65Install `deploy/systemd/openvibe-shoes.service` and `deploy/nginx/open.shoes.conf`; the unit reads
66`/etc/openvibe/shoes.env`, works in `/opt/openvibe.shoes`, runs as `ubuntu:ubuntu` on
67`127.0.0.1:5180`. The vhost proxies `/api/`, `/auth/` and the forms with their own limits.
68`sudo ovhost deploy shoes` is the production path (git-checkout, install on lockfile change,
69restart, wait for `/api/ready`); rollback with `sudo ovhost rollback shoes --to <sha>`.
70
71## Commands and tests
72
73```bash
74npm ci --include=dev
75npm start # http://127.0.0.1:5180
76npm test # every test/*.test.js, PGlite, mock Network
77npm test -- importer # only matching files
78npm run test:pg # the same through PgBouncer
79npm run seed # one run of every job against live sources (needs the network)
80```
81
82`test/run.js` uses `openvibe-shared/test-runner` (90 s, serial); files get a temp PGlite database and
83an in-process Network mock, never the network. Tests cover the parsers and all-in price, snapshots
84(first check per offer per day wins), the jobs' stop/error behavior, the API and pages, Watch/Today
85forwarding, account export/deletion and the shared discovery artifacts. `VERBOSE=1` shows each file's
86output.
87
88## Conventions and pitfalls
89
90- CommonJS, 4-space indent, single quotes, semicolons; no linter. Paths and domain logic stay in
91 `server/domain/` so a parser is testable without HTTP.
92- **Prices are all-in** (price + stated shipping); keep currency and the source's own check time, and
93 mark a stale offer rather than hiding it.
94- **The first snapshot of an offer per day wins** (unique key); do not overwrite history.
95- **Cite or say "not known yet":** never invent a spec, fit note or release date; a parser that
96 cannot read a date leaves it out.
97- **Respect the source rules:** Deals public pages, eBay's official API only with keys, official
98 release pages; no scraping of Marketplace or Facebook, no affiliate URLs.
99- New environment variables go in `.env.example` and the README list; secrets live only in
100 `/etc/openvibe/shoes.env`.
101