Skip to content

🧾 Bring your personal RevBank account into Pixel - #147

Open
davidvanleeuwen wants to merge 6 commits into
mainfrom
feat/revbank-private-api
Open

davidvanleeuwen wants to merge 6 commits into
mainfrom
feat/revbank-private-api

Conversation

@davidvanleeuwen

@davidvanleeuwen davidvanleeuwen commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

🧾 Your RevBank account, right in Pixel

Check your credits before your next visit, see your latest bookings, and find out where your balance went — all through private Discord replies.

Available to Friends, Members and Admins; Guests cannot use the RevBank commands.

This adds a personal RevBank connection to Pixel, with a human-verified account link and a separate private service that reads the existing backup.

A quick look

Illustrative response — fictional data:

/revbank balance

Your RevBank balance: €8.50
Backup: 21 Oct 2026, 12:00.
Command What you get
/revbank link Request a link; enter your RevBank nickname in Discord’s nick field
/revbank status Check your link or pending request
/revbank balance Your balance, with the backup timestamp
/revbank transactions Your last ten confirmed bookings
/revbank unlink Remove your link and any pending request

🔗 Link once, then just ask

  1. Request your account link in Pixel.
  2. Verify ownership in person with an authorised link manager.
  3. Approve that exact request using /revbank manage.
  4. Check your account whenever you need it. Every reply is private.

Link managers can review, approve, reject and revoke links. Managing a link does not grant access to someone else's balance or transactions.

On the Pixel website

RevBank now has a homepage feature card and appears in the animated command picker. The getting-started guide explains linking your account, and the command reference covers both personal commands and link management, including the required permissions.

🔒 Personal by design

  • Your account only: financial requests use the caller's immutable Discord ID.
  • Private replies throughout: including the initial acknowledgement and errors.
  • Separate private gateway: Pixel gets no backup credentials and never reads the backup repository.
  • Minimal disclosure: confirmed bookings only; raw terminal input and free-form private descriptions stay out of replies.
  • Clear freshness: every financial response shows its source backup timestamp.
  • Read-only financial access: RevBank, the Pi and the existing backup remain untouched.
For reviewers: implementation and trust boundaries

The new Revbank port and HTTP client integrate with Pixel's existing feature registry and dispatcher. Link management requires the explicit revbank-link-admin capability; the gateway independently checks its manager allow-list.

Responses are schema-validated and streamed with a 16 KiB cap and an eight-second deadline. Redirects and automatic retries are disabled. Financial responses are not persisted or logged by Pixel.

The integration defaults off. This PR includes environment validation, Key Vault/Terraform wiring, ADR 0018, privacy documentation and operator instructions.

Trust boundary: the gateway authenticates Pixel with a service token and trusts its assertion of the Discord caller's identity. A compromised Pixel/token can impersonate linked users. Review this boundary and the private gateway before enabling production.

Validation and rollout

Local validation passed. Malformed gateway URLs are covered by four regression cases and report a redacted ConfigError naming REVBANK_API_URL:

  • just check — 2,174 tests, including all coverage thresholds
  • just build
  • just docs-build
  • Website checked in light and dark themes, at desktop and 390px mobile widths; no horizontal overflow
  • just tf-validate
  • Changelog validation

The companion TypeScript/Node.js gateway passed its 39 tests, Docker checks and Terraform validation. It is available on main in the separate private repository. GitHub CI reports the checks for this PR separately.

Rollout still needed: deploy the private TypeScript gateway into Pixel’s existing Azure Container Apps environment using its documented just workflow, configure credentials and link managers, and register the commands through the normal deployment process. The gateway uses internal HTTPS ingress, dedicated storage and secrets, and separate Terraform state keys in the existing backend. No infrastructure has been applied or live secrets changed.

Payments, financial writes, reminders and public statistics are outside this PR.

@davidvanleeuwen davidvanleeuwen changed the title Add private personal RevBank access through a separate gateway 🧾 Bring your personal RevBank account into Pixel Oct 21, 2026
@davidvanleeuwen
davidvanleeuwen marked this pull request as ready for review October 21, 2026 12:13
Comment thread src/config.ts
Comment on lines +60 to 70
!url.hash &&
url.pathname === "/" &&
(url.protocol === "https:" || ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))
);
},
{ error: "must be an HTTPS origin (HTTP is allowed only on loopback)" },
);

const pixelEnv = z.enum(["local", "dev", "prod"]).default("local");
const pixelRuntime = z.enum(["local", "cloud"]).default("local");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Calling new URL(v) without a try/catch in revbankUrl's .refine() causes an unhandled TypeError on invalid URL input instead of a formatted ConfigError identifying REVBANK_API_URL.
Severity: LOW

Suggested Fix

Wrap the new URL(v) invocation inside the .refine() callback in a try...catch block and return false if a TypeError is caught.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: src/config.ts#L50-L70

Potential issue: In `src/config.ts`, `revbankUrl` uses `z.url().refine(...)` where the
refine callback calls `new URL(v)` without error handling. In Zod, a failed format check
records an issue but allows subsequent `.refine()` checks on the same schema to execute
unless abort behavior is enforced. If an invalid URL such as 'example.com' is supplied
for `REVBANK_API_URL`, `new URL(v)` throws an unhandled `TypeError: Invalid URL`. This
bypasses Zod error formatting and prevents the `ConfigError` identifying
`REVBANK_API_URL` from being produced.

Did we get this right? 👍 / 👎 to inform future reviews.

This branch was successfully deployed

2 active (outdated) deployments
dev — d55d3fcd Deployed Oct 21, 2026 by davidvanleeuwen via Plan envs/dev #111
prod — d55d3fcd Deployed Oct 21, 2026 by davidvanleeuwen via Plan envs/prod #111
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