~bigbes/sr-ht-spec

ref: 0a32fd7a58ef967cab397053f9f3b59abd719375 sr-ht-spec/.up d---------
096d25aa — Eugene Blikh 25 days ago
docs(up): finalize Phase 5a decision + deferred log
021d955a — Eugene Blikh 25 days ago
feat(cmd,graph): wire /query onto core-go's server for webhooks (Phase 5a)

The faithful runtime wiring. /query moves from spec's anon-router handler
onto core-go's authenticated router, so the webhook engine gets the
auth/database/server context it requires.

- cmd: build the executable schema via graph.NewSchema and hand it to
  both webhooks.NewQueue and server.WithSchema (one schema, both). The
  server is coreserver.New().WithDefaultMiddleware() (core-go auth +
  database + server context + the delivery worker via WithQueues). web,
  MCP and REST stay on the anon router with spec's own authn — only
  /query changes. The owner "user" row is seeded at startup so core-go's
  LookupUser stays local.
- ownerOnly middleware on /query: 403s any non-owner (core-go auth admits
  any meta user; spec is single-owner) and remaps the owner to
  AUTH_INTERNAL so the webhook engine's NewAuthConfig/FilterWebhooks
  (which refuse AUTH_COOKIE) accept them.
- graph: NewSchema exposes the raw executable schema; the webhook
  resolver ACL now requires AUTH_INTERNAL (only the owner gets it, via
  ownerOnly) instead of spec's authn, which is no longer in the /query
  chain.

Accepted trade-off: agents lose GraphQL /query reads (they keep MCP +
REST). New deploy requirement: WithDefaultMiddleware needs [mail]
smtp-from (core-go's notification queue).

Verified against a live daemon on Postgres: owner cookie creates and
lists webhooks (row stored INTERNAL/user_id 1); non-owner 403; unauth
401; web UI 200 on the anon router.
36976713 — Eugene Blikh 25 days ago
feat(db): webhook + user tables (Phase 5a foundation)

The DB foundation for GraphQL-native webhooks, matching the core-go /
pages.sr.ht convention:

- "user" table — spec is single-owner, but the webhook subscription is
  user-scoped in core-go's model, so a user row is the owner's identity
  and the FK target. Columns mirror core-go auth.LookupUser so the table
  is ready if the service ever adopts core-go auth; today only id/username
  are used (owner seeded at startup).
- webhook_event enum (PROPOSAL_OPENED/MERGED/REJECTED), auth_method enum.
- gql_user_wh_sub / gql_user_wh_delivery — column names match core-go's
  webhooks engine exactly (it selects/inserts by these names). The
  events check uses cardinality() not array_length() so an empty event
  list is rejected at the DB (array_length returns NULL there, which a
  CHECK does not reject — a latent gap in the upstream convention).

Webhook tables use bare `timestamp` (not spec's TIMESTAMPTZ) to match
core-go's `NOW() at time zone 'utc'` inserts. Verified: schema.sql and
the 0003 migration both apply and reverse cleanly; FK/check/cascade all
behave.