check / check (push) Waiting to run
Rewritten from scratch, sections kept, every statement checked against the code. Passed independent review in round 4. Model: fable-5-1 (writing); opus-5-5 (review, merge)
78 lines
3.6 KiB
Markdown
78 lines
3.6 KiB
Markdown
# Workflow
|
|
|
|
One issue per unit of work, and one branch and one PR per issue:
|
|
|
|
- make sure a tracked issue exists with a definition of done
|
|
- branch from `next`, never from `main`
|
|
- do the work and push the branch
|
|
- open a PR with base `next`, never `main`
|
|
- pass an independent review
|
|
- the repository manager squash-merges it into `next`
|
|
|
|
The repository manager is the role that merges each issue's PR into `next`.
|
|
Nothing stays local-only: every commit is pushed.
|
|
|
|
`next` is the branch for the next milestone. It must stay green and mergeable
|
|
into `main` at all times. A milestone's work reaches `main` through one PR from
|
|
`next`. The owner, @sneak, merges that PR. Cutting a release from `main` is a
|
|
separate step after that.
|
|
|
|
The tracker (https://git.eeqj.de/sneak/webhooker/issues) records what is done
|
|
and what is under way. This file keeps no list of either.
|
|
|
|
# Status
|
|
|
|
What is still open for 1.0.0 is in its milestone
|
|
(https://git.eeqj.de/sneak/webhooker/milestone/9). `v1.0.0` is not tagged. Only
|
|
@sneak tags it.
|
|
|
|
Delivery is at least once by design. When webhooker cannot record the outcome of
|
|
a delivery, it sends that delivery again. The target can then receive the same
|
|
event twice. The alternative is a lost delivery that nothing reports. The README
|
|
says so. Such a duplicate is not a defect to re-file.
|
|
|
|
# Next Step
|
|
|
|
@sneak runs webhooker in limited production, then tags `v1.0.0`. Merging `next`
|
|
into `main` is a separate act. It waits on neither the production run nor the
|
|
tag.
|
|
|
|
# Future Steps
|
|
|
|
- Per-webhook rate limits, set in the web UI and enforced at the entrypoint.
|
|
Today `RECEIVER_RATE_LIMIT` is the only rate-limit setting. It is how many
|
|
requests per minute one client address may send to one entrypoint. The same
|
|
address is also capped at ten times that across all entrypoints together.
|
|
- API key authentication for programmatic access. The `APIKey` model and its
|
|
`api_keys` table exist. Nothing creates a key and nothing checks one.
|
|
- REST API v1. `/api/v1` is mounted with no routes today.
|
|
- CRUD for webhooks, entrypoints and targets
|
|
- event viewing and filtering endpoints
|
|
- event redelivery endpoint
|
|
- OpenAPI specification
|
|
- Analytics in the web UI: response times summarised per webhook or per target,
|
|
and figures for all webhooks together. Today the webhook page shows event,
|
|
delivery and failure counts and failure percentages. The target list counts
|
|
each target's deliveries. The event log shows every attempt's duration.
|
|
`/metrics` carries server-wide counts and delivery durations.
|
|
- A remember-me option at login. Today every session survives a browser restart.
|
|
It lasts up to 7 days. It ends sooner after `SESSION_IDLE_TIMEOUT` (default 24
|
|
hours) without use.
|
|
- Password reset over the web for a forgotten password. Today a signed-in user
|
|
can change their password. A lost password is reset from the command line with
|
|
`webhooker resetpw` (https://git.eeqj.de/sneak/webhooker/issues/208).
|
|
- Later, nice to have
|
|
- email delivery target type
|
|
- SNS and S3 delivery targets
|
|
- data transformations, such as a configurable Slack message format. The
|
|
Slack target sends one fixed format today.
|
|
- JSONL file delivery with periodic S3 upload. Today an archive target
|
|
writes events to SQLite files. An archive target can rotate those files
|
|
hourly, daily or monthly. The webhook page offers them as one gzipped JSON
|
|
download.
|
|
- webhook event search, and filtering beyond the event log's failed and
|
|
pending views
|
|
- multi-user with role-based access control. Today each webhook belongs to
|
|
one account. Only the account made at first boot exists. There is no way
|
|
to add another.
|