Skip to content

docs(guide): rewrite GUIDE.md against the product that actually exists - #10

Merged
Przyval merged 1 commit into
masterfrom
fm/openfoundry-panduan-tertinggal
Sep 11, 2026
Merged

Przyval merged 1 commit into
masterfrom
fm/openfoundry-panduan-tertinggal

Conversation

@Przyval

@Przyval Przyval commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Why

GUIDE.md described the product from two days ago. It still sold the pest-control demo as the product, never once mentioned Sanocare or Kelava, and predated the auth, /api/v1, seed-relocation and identity-header work. Documentation that is wrong is worse than documentation that is missing, because people follow it and fail in places it does not explain.

How this was checked

Nothing here was written from memory. bash start.sh itself could not be run on this machine (port 3000 was held by an unrelated Docker container and start.sh kills whatever holds it), so its contents were run instead: the ten services it launches were started individually, plus the three it does not launch, pest control was seeded from scripts/demo/, and the console was served on a spare port and driven in a real browser through every page in the sidebar.

All 63 endpoints and status codes documented in the guide were then re-verified end to end against that stack. 62 matched on the first pass; the single mismatch was my own probe omitting a required query parameter, not the product.

What was not executed, and is labelled as such inside the guide: the three Kelava scripts (they need an SSH tunnel and live database credentials) and the docker compose deploy path (needs a full image build and the ports).

What the guide now says

  • Sanocare (Live) at /sanocare is the daily operational dashboard, reading the sanocare-kelava ontology. PestControlDashboard.tsx is called out as a deliberate archive - kept, not deleted - its route is gone, and /pest-control now renders a blank page.
  • A new Sinkronisasi Kelava section: the 8 object types and 8 link types sync-kelava.sh creates, its fail-fast behaviour without KELAVA_PASS, and seed-kelava-alerts.sh. Credentials are named by key from .env.example only - no address, host or secret is written into this public repo.
  • /api/v1 served alongside /api/v2, with the wire shapes that genuinely differ (shown side by side) and the three operations deliberately left unserved, each verified to answer 404: GET .../files, GET .../files/{filePath}, and the whole /api/v1/attachments namespace. The guide also points out that DELETE .../files/* is served and its 404 means something different.
  • Gateway auth does not enforce. Verified directly: with AUTH_PUBLIC_KEY set, GET /api/v2/ontologies with no Authorization header still returns 200, and so does a fabricated token, because authPlugin is registered encapsulated in server.ts. The guide states that plainly along with what follows (request.claims never populated, no role enforcement, ENFORCE_PERMISSIONS=true turning every proxied route into a 403), and separately states what the gateway does do: drop every client-asserted x-user-* header.
  • The six scripts/demo/ commands were re-run rather than assumed. They work - but the guide now explains that all four seeds reuse the first existing ontology and ignore ORG_RID, so the old "Ganti Industri" instructions silently merged four industries into one ontology. start.sh --industry is the only correct switch, and the clear-then-seed mechanism it relies on was verified directly.
  • The production bootstrap section now puts OPENFOUNDRY_ALLOW_OPEN_SIGNUP where it is actually read - on svc-multipass and the gateway - and shows the old form as the mistake it is.

Product defects found while testing (recorded, not fixed)

The guide's closing Batasan yang Diketahui section lists 20 verified defects. The ones worth a maintainer's attention:

  1. start.sh never starts svc-compass, svc-webhooks or svc-media, so /api/v2/compass/*, /api/v2/webhooks* and /api/v2/media* answer 502 and those pages do not work out of the box. Starting them by hand makes all three return 200.
  2. Network Graph never draws a single edge, for two independent reasons: it reads sourceObjectType/targetPrimaryKey off .../links/:lt, which returns linked objects and has no such fields; and it fires one request per object-per-link-type, which trips the gateway's own 100 req/min limit.
  3. complete-service-job derives invoiceId from jobId while the seed numbers invoices independently, so almost every job 500s wrapping a 409. On a fresh seed only JOB-2026-008 succeeds.
  4. .env.example and deploy/docker/Dockerfile.console set VITE_API_BASE_URL; the console reads VITE_API_URL. Configuring the API base URL as documented has no effect.
  5. docker-compose.yml uses a different Postgres password for the database service than for the app's DATABASE_URL.
  6. RLS is not proven end to end: the policy in 009_multi_tenancy.sql reads app.org_rid, while pg-object-store.ts sets app.current_org_rid.
  7. The Object Explorer aggregation strip is broken in two layers (only triggers on uppercase property types, which the demo seeds do not use; and when it does trigger it renders type: COUNT / value: n because the console expects data[0].metrics while the service returns a flat list).
  8. GET /api/v2/search - the navbar "Search everything..." box - 500s without Postgres.
  9. Compass silently falls back to a hardcoded tree behind an "Offline Mode" badge, which is the normal demo state; Scenarios silently falls back to hardcoded customers when no "pest" ontology exists; Webhooks shows "No webhooks configured" whether the list is empty or the service is down.
  10. Monitors created from the console always have zero effects and there is no UI to add any.
  11. pnpm db:seed points at scripts/seed.js, which does not exist.
  12. Unknown URLs, /pest-control included, render a blank page rather than a 404.

The one product change in this PR

Flagged separately, per the brief's one-line exception. bash scripts/bootstrap-admin.sh - the documented production bootstrap path - failed with a 502 on every run. The gateway forwarded the caller's Content-Length while re-serializing the parsed body, so undici rejected any request whose JSON was not already compact, and bootstrap-admin.sh sends pretty-printed JSON. One line in proxy.ts drops the header and lets fetch set it. With it, signup answers a real status (403 closed, 201 when enabled), and the full bootstrap flow was run to completion. A regression test covers it.

This affects far more than the one script: any caller posting non-compact JSON through the gateway was getting a 502.

Checks

  • npx turbo run build --continue - 49/49
  • npx turbo run test --continue - 97/97 (36 in svc-gateway, +1 new)
  • pnpm run lint - 0 errors, 227 warnings (unchanged baseline)

AGENTS.md records the start.sh service gap, the demo-seed ontology reuse, and a pointer to the guide's limitations list so no future session re-derives them.

GUIDE.md described a pest-control demo product from two days ago. It never
mentioned Sanocare or Kelava, described an Object Explorer UI that does not
exist, documented action parameters that are wrong, and promised multi-tenant
isolation and audit trails that the demo mode does not deliver.

Every command and endpoint in the new guide was executed against a running
stack before being written down: the ten services start.sh launches were
started individually, pest control was seeded, and all 63 documented endpoints
were re-verified end to end (62 pass, and the one mismatch was my probe
omitting a required query param, not the product).

What the guide now says that it did not before:

- Sanocare (Live) at /sanocare is the operational dashboard, reading the
  sanocare-kelava ontology. PestControlDashboard.tsx is kept as an archive,
  its route is gone, and /pest-control now renders a blank page.
- A Sinkronisasi Kelava section: which object and link types sync-kelava.sh
  creates, and that its credentials come from .env, with the keys named from
  .env.example and no address or secret written into this public repo.
- /api/v1 is served alongside /api/v2, with the wire shapes that actually
  differ and the three operations deliberately left unserved (both file GETs
  and the whole attachments namespace), each verified to answer 404.
- The truth about gateway auth: it does NOT enforce. Verified directly - with
  AUTH_PUBLIC_KEY set, an unauthenticated GET still returns 200, because
  authPlugin is registered encapsulated. The guide says so, and says what
  follows from it, instead of implying enforcement exists.
- start.sh does not start svc-compass, svc-webhooks or svc-media, so those
  pages 502 out of the box; the guide gives the commands to start them.
- The four scripts/demo seeds reuse the first existing ontology and ignore
  ORG_RID, so "Ganti Industri" by running a second seed silently merges
  industries. start.sh --industry is the only correct switch.
- A closing "Batasan yang Diketahui" section: 20 verified defects, including
  Network Graph never drawing an edge, the aggregation summary strip, global
  search needing Postgres, Compass falling back to a canned tree, the
  complete-service-job invoice-id collision, and the VITE_API_URL vs
  VITE_API_BASE_URL mismatch.

Also fixes one product bug, because a documented command failed on it: the
gateway forwarded the caller's Content-Length while re-serializing the parsed
body, so any request whose JSON was not already compact was rejected by undici
and answered 502. That made bash scripts/bootstrap-admin.sh - the documented
production bootstrap path - fail with 502 instead of a real status on every
run. Dropping the header lets fetch set it; a regression test covers it.

AGENTS.md records the start.sh service gap, the demo-seed ontology reuse, and
a pointer to the guide's limitations list.
@Przyval
Przyval merged commit 00e3869 into master Sep 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant