Approve a filing from Telegram
Send the approval card, understand who may press it, and recover when the mail fails.
Owned by Admin · 11 steps · about 20 minutes
Why this exists
The quarterly filing has a deadline attached to a physical envelope, and the person who must approve it is rarely at a desk. So the approval gate is reachable from a Telegram card with inline buttons as well as from the dashboard. This workflow is about that path, and specifically about the fact that convenience is not authority.
Pressing the button in a chat does not approve anything by itself. The callback maps the Telegram user id to a platform user through a configured map, and then requires that user to hold an active admin grant. An unmapped or non-admin presser is answered "Not authorized", an audit row is written, and nothing changes. The chat is a remote control, not a second set of credentials.
Approval is the irreversible step. It flips the package state under a rowcount-guarded update — so two people pressing approve at the same moment produce exactly one approval and one "already processed" — then renders and hash-seals the documents and hands four envelopes to the print-and-mail adapter. Four, not five: the two federal forms share one envelope to the same agency.
And the chat can refuse for a second reason that has nothing to do with who you are. If the accrual rows and the ledger disagree for the period, the callback answers with the drift figure and sends you to the admin page instead of filing. The gate is the same one the page has; what differs is that the page can carry an acknowledgement and a card cannot, so the irreversible act is moved to the surface that can record why it was taken. It does not block the filing — the page is one tap away.
Partial mail failure has its own state, and you must recognise it. If some envelopes go and others do not, you get a 502 and the package is left in mail-submitted with the failed rows visible. The correct response is to retry the mailing. Approving again is not possible and trying is the wrong instinct — the filing is already approved; it is the post that failed.
Documents are immutable once stored. The DRAFT or APPROVED watermark is injected when a document is served, never when it is stored, and the stored hash is re-verified on every read. A tampered document fails loudly rather than printing.
Before you start
- An admin session — every tax route including the read-only ones is admin-only.
- A generated package in pending approval (the seed ships one for the launch quarter).
- The Telegram admin map configured, or the approve press will be refused as unauthorised.
Practise with
| Persona | Password | Note | |
|---|---|---|---|
| admin | admin@club.test | admin123 | can approve from the dashboard |
| admin | taxadmin@demo.club | tax-admin-123 | the seeded tax admin — a second admin to test the mapping with |
Steps 1–11 — Admin
their manual →-
1Open the tax office and find the period whose package is waiting for approval.Expected result Quarter-to-date liability tiles, a reconciliation badge, and the list of periods with their package states.Watch out for If the reconciliation badge is red, read the reconciliation workflow before you approve anything. Filing on top of a disagreement posts the disagreement to an agency.
-
2Open the period. Read the totals, the five documents, the allocation across the four agencies, the mailings panel and the audit trail.Expected result State-gated actions: only the buttons legal from the current status are live.Watch out for The documents are watermarked DRAFT until approval. That watermark is applied when the document is served, so a saved PDF from before approval will always say DRAFT — that is correct, not stale.
-
3Set or correct the allocation across the agencies before sending for approval.Expected result The allocation saved against the package.Watch out for Exactly four agencies, each at or above zero. Anything else is rejected rather than filed. This is the last comfortable moment to change the numbers.
-
4Send the package for approval. A Telegram card goes out with inline approve, view and edit buttons.Expected result The package moves to pending approval and the outbound call is recorded.Watch out for Sending again re-sends the card; it does not create a second package. If the chat is misconfigured you will see the failure in the wire log rather than on this page.
-
5Confirm the card actually left, filtering the wire log to the Telegram service.Expected result A send-message call with the package as its correlation id.Watch out for Correlation id is the package id. That is how you find every message about one filing, including the later edits that change the card as the state moves.
-
6Check the Telegram configuration: the chat, the webhook secret and the map from Telegram user ids to platform users.Expected result The settings, with the secret masked.Watch out for An approver who is not in the map cannot approve, no matter how senior they are. Being in the map is also not enough — the mapped user must hold an active admin grant at press time.
-
7Reproduce the button press deliberately: post the callback the way Telegram would, with the shared secret header and the approve callback data for your package.Expected result The package is approved, documents are rendered and hash-sealed, and four envelopes are submitted with tracking numbers.Watch out for A wrong or missing secret header is 403 — and an UNCONFIGURED secret leaves through the same refusal with the same body, on purpose, so the endpoint cannot be probed for whether it has a key. Malformed callback data is 400. An unauthorised presser gets a 200 with the answer 'Not authorized' — deliberately not an error, because the sender is Telegram, not the attacker. ADDED 2026-08-30, a fourth outcome this list omitted and the one you are likeliest to meet: if the accruals and the ledger disagree, an authorised press is REFUSED too, with the answer 'Ledger drift $X — approve from the admin page' and a link. That is not a bug and not an authority problem. A chat card has nowhere to record why you filed over a known disagreement, so the acknowledgement has to happen on the page.
-
8Use the debug replay when you want to drive the same logic without constructing a signed webhook body.Expected result The same handler, the same result.Watch out for Replaying an approve on a package that is already approved answers 'already processed' rather than approving twice. That idempotency is the property to check, not to work around.
-
9Go back to the period and read the mailings panel: one row per envelope, each with a status and a USPS tracking number.Expected result Four mailings, tracked.Watch out for Four envelopes for five documents — the two federal forms travel together to the same agency. Counting five and finding four is not a missing mailing.
-
10If any envelope failed, retry the mailing rather than reaching for the approve button again.Expected result The failed envelopes are resubmitted; successful ones are not re-sent.Watch out for Approve is a one-way door and will refuse a second attempt with 409. A package sitting in mail-submitted is not un-approved, it is un-posted.
-
11Open one filed document and notice the watermark and the hash.Expected result The stored HTML with an APPROVED watermark injected at serve time, and its hash re-verified before it is handed to you.Watch out for A hash mismatch is a 500 with a specific code, and it means the stored bytes changed after they were sealed. Treat that as a security incident, not a rendering bug.