Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
e32e506
fix(esign): walk first-time installers past Gatekeeper and SmartScreen
lorenzocorallo Oct 21, 2026
e8037f1
fix(esign): keep the signing dialog open on a click outside it (E5)
lorenzocorallo Oct 21, 2026
681a07c
fix(esign): name PoliNetwork eSign in the signing dialog copy (E32)
lorenzocorallo Oct 21, 2026
506967f
feat(esign): point first-time signers to the setup guide
lorenzocorallo Oct 21, 2026
3d970a4
fix(esign): keep the role box under its label until the user moves it
lorenzocorallo Oct 21, 2026
4ac8f5a
fix(esign): stop promising delivery for cancelled and declined requests
lorenzocorallo Oct 21, 2026
bfe631c
fix(esign): give the signing dialog the house dialog shell and a fini…
lorenzocorallo Oct 21, 2026
c5ecbdd
feat(esign): pick signers and roles from the keyboard
lorenzocorallo Oct 21, 2026
3ec7ac1
fix(esign): notice a closed eSign window and reuse the one that is op…
lorenzocorallo Oct 21, 2026
b07ec6d
fix(esign): open the eSign window in the computer's colour scheme (C8)
lorenzocorallo Oct 21, 2026
77bc8bb
feat(esign): say whom a request waits on and keep the status filter o…
lorenzocorallo Oct 21, 2026
30c208a
fix(esign): warn that cancelling interrupts a signature in progress
lorenzocorallo Oct 21, 2026
6191b27
feat(esign): unlock Sign with CIE when the other signer finishes
lorenzocorallo Oct 21, 2026
0915d17
fix(esign): show every composer problem at its field
lorenzocorallo Oct 21, 2026
216db00
feat(dashboard): show documents to sign on the Overview
lorenzocorallo Oct 21, 2026
3a24c7e
fix(esign): say how a signature attempt ended (E19, E20, E30)
lorenzocorallo Oct 21, 2026
3b6c574
refactor(esign): build the requests list's signer text once per row
lorenzocorallo Oct 21, 2026
c6781fc
fix(esign): show when PoliNetwork eSign stops answering mid-signature…
lorenzocorallo Oct 21, 2026
458f074
docs(esign): describe signingNow.until, lost signing access and drive…
lorenzocorallo Oct 21, 2026
ab0a381
feat(esign): ask before discarding a composer in progress
lorenzocorallo Oct 21, 2026
764f934
feat(esign): name the output folder and reopen the last one
lorenzocorallo Oct 21, 2026
502a261
fix(esign): name who is being placed in the viewer toolbar
lorenzocorallo Oct 21, 2026
c0cbd4a
fix(esign): word setup step 4 for both agent status pages
lorenzocorallo Oct 21, 2026
fb46c98
feat(esign): let a signer move their box to another page
lorenzocorallo Oct 21, 2026
463739a
fix(esign): show that an ended signature's Close is reloading the pag…
lorenzocorallo Oct 21, 2026
c21580c
fix(esign): open the next batch document without a blank wait or a slide
lorenzocorallo Oct 21, 2026
77e8eb3
fix(esign): keep focus on the arrow when reordering signers
lorenzocorallo Oct 21, 2026
8346406
Merge branch 'fix/esign-signing-ux' into feat/esign-ux-pass
lorenzocorallo Oct 21, 2026
8b5e802
Merge branch 'fix/esign-pages-ux' into feat/esign-ux-pass
lorenzocorallo Oct 21, 2026
70e079a
Merge branch 'feat/esign-composer-ux' into feat/esign-ux-pass
lorenzocorallo Oct 21, 2026
7e32c9e
fix(esign): read a cancel or decline only from a cancelled job
lorenzocorallo Oct 21, 2026
5e7caa7
fix(esign): word "document changed" and "no longer needs you" for the…
lorenzocorallo Oct 21, 2026
9022f20
fix(esign): close the eSign window when someone else ends the request
lorenzocorallo Oct 21, 2026
34d799d
fix(esign): make "Open the window again" the signing dialog's primary…
lorenzocorallo Oct 21, 2026
607b599
fix(esign): drop "Not delivered" from stopped requests that had no de…
lorenzocorallo Oct 21, 2026
cddc764
docs(esign): say which agent posts agent_unreachable and what ends it…
lorenzocorallo Oct 21, 2026
e02a0b9
docs(esign): log the 2026-10-21 UX pass and what waits for the backen…
lorenzocorallo Oct 21, 2026
26b8bb8
docs(esign): name the follow-ups plainly and both footer labels
lorenzocorallo Oct 21, 2026
3860042
feat(esign): tell phones and tablets apart from computers that can sign
lorenzocorallo Oct 21, 2026
bc63ff7
refactor(esign): share the OS detection and the agent's stable downlo…
lorenzocorallo Oct 21, 2026
36304ea
feat(esign): tell phones from computers already in the server render
lorenzocorallo Oct 21, 2026
9b70a85
feat(esign): drop "Sign a document" from To sign
lorenzocorallo Oct 21, 2026
0f94cd8
feat(esign): show phones a note instead of "Sign N together"
lorenzocorallo Oct 21, 2026
796a838
feat(esign): download for this system and pair in CIE ID on Setup
lorenzocorallo Oct 21, 2026
a5edab2
fix(esign): put the download first in Setup's install step
lorenzocorallo Oct 21, 2026
4281ac2
docs(esign): gate the Setup download buttons on the agent release
lorenzocorallo Oct 21, 2026
43a9edb
feat(esign): forward PoliNetwork eSign's User-Agent to the backend
lorenzocorallo Oct 21, 2026
835d605
feat(esign)!: remove the signed-PDF upload fallback
lorenzocorallo Oct 21, 2026
bac35ce
refactor(ui): share the shortcut hint and let a page fill the window
lorenzocorallo Oct 21, 2026
d759449
feat(esign): let the viewer, drive browser and sign button sit in a w…
lorenzocorallo Oct 21, 2026
b1b292c
feat(esign): rebuild New request as a viewer and one request column
lorenzocorallo Oct 21, 2026
09ede92
feat(esign)!: sign your own PDF from New request, without a separate …
lorenzocorallo Oct 21, 2026
77d0f36
feat(ui): let FormDialog choose where focus returns
lorenzocorallo Oct 21, 2026
79a61eb
fix(esign): stop saying where the PUK is printed
lorenzocorallo Oct 21, 2026
70d3cad
feat(esign): remember which browsers have run PoliNetwork eSign
lorenzocorallo Oct 21, 2026
4bac4d8
feat(esign): tell phones from computers before hydration
lorenzocorallo Oct 21, 2026
ce402a8
feat(esign): open the batch on the document it came from
lorenzocorallo Oct 21, 2026
c9bc696
feat(esign): one action card on the request and batch pages
lorenzocorallo Oct 21, 2026
952a81b
feat(esign): find signature spots in the PDF and place boxes in clear…
lorenzocorallo Oct 21, 2026
d44c39c
feat(esign): offer the PDF's signature spots as signers to fill
lorenzocorallo Oct 21, 2026
7c26a55
feat(esign): replace a PDF version page by page, without blank sheets
lorenzocorallo Oct 21, 2026
d19e95e
feat(esign): say when PoliNetwork eSign isn't running, and what stops it
lorenzocorallo Oct 21, 2026
6e25aa6
feat(esign): hand the signed document back to the page
lorenzocorallo Oct 21, 2026
eaede94
feat(esign): keep a signer's places when the same document is laid ou…
lorenzocorallo Oct 21, 2026
4626352
feat(ui): let a bar skeleton stand for several lines
lorenzocorallo Oct 21, 2026
8210147
feat(esign): start a new request from an earlier one with ?from=
lorenzocorallo Oct 21, 2026
4a8178b
fix(esign): keep a cancelled signing dialog's last state while it closes
lorenzocorallo Oct 21, 2026
0ddfb50
fix(esign): focus the signing dialog's primary once it has one
lorenzocorallo Oct 21, 2026
10a4992
fix(esign): show the Move box tooltip when it opens a menu
lorenzocorallo Oct 21, 2026
97bbe90
fix(esign): pin the side column only where the viewer stays readable
lorenzocorallo Oct 21, 2026
986b1bf
fix(esign): underline the links inside the action card's sentences
lorenzocorallo Oct 21, 2026
7d41c7f
fix(esign): keep the lock line to one line
lorenzocorallo Oct 21, 2026
0b88a6e
docs(esign): gate the Update download on the agent release
lorenzocorallo Oct 21, 2026
e6be002
fix(esign): offer only signable labels as spots and keep every box of…
lorenzocorallo Oct 21, 2026
d4cbe61
fix(esign): apply the source drive's sign rule to a request sent again
lorenzocorallo Oct 21, 2026
42245c6
fix(esign): let ⌘↵ send after a typed role takes its spot
lorenzocorallo Oct 21, 2026
8eb8ced
fix(esign): highlight the viewer in the signer picker so Enter adds them
lorenzocorallo Oct 21, 2026
87c85bb
fix(esign): hide the role suggestions when none match
lorenzocorallo Oct 21, 2026
f2cd660
fix(esign): ring the folder row a blocked submit focuses
lorenzocorallo Oct 21, 2026
cfaf4e9
fix(esign): size the composer column to its content
lorenzocorallo Oct 21, 2026
c499707
fix(esign): open New request for any ?from= value
lorenzocorallo Oct 21, 2026
17a68a1
fix(esign): keep the focus in the drive browser when a folder opens
lorenzocorallo Oct 21, 2026
e739e6b
fix(esign): end a long drive name with an ellipsis
lorenzocorallo Oct 21, 2026
4d87c90
docs(esign): describe how New request finds spots and places boxes
lorenzocorallo Oct 21, 2026
555a540
feat(esign): merge the Setup and To sign decisions
lorenzocorallo Oct 21, 2026
3e2db39
feat(esign): merge the request page and signing dialog decisions
lorenzocorallo Oct 21, 2026
b692040
feat(esign): merge the New request decisions
lorenzocorallo Oct 21, 2026
7546049
fix(esign): underline Setup's links inside sentences
lorenzocorallo Oct 21, 2026
d98be98
feat(esign): land a signature from New request on the signed spot
lorenzocorallo Oct 21, 2026
5a1db6e
fix(esign): keep an iPad from flashing "Sign N together" in To sign
lorenzocorallo Oct 21, 2026
c9ad69b
fix(esign): forward the User-Agent of agents released before the rename
lorenzocorallo Oct 21, 2026
19fc265
fix(esign): keep signature boxes off neighbouring labels
lorenzocorallo Oct 21, 2026
cb0bec8
fix(esign): drop "0 of 1 signed" from the lists and cap "Sign N toget…
lorenzocorallo Oct 21, 2026
e4156af
fix(esign): open Send again on a document skeleton
lorenzocorallo Oct 21, 2026
e4162c9
fix(esign): keep Setup from flashing the Mac guide on an iPad
lorenzocorallo Oct 21, 2026
d8d4284
feat(ui): let FormDialog confirm a destructive action, and use it to …
lorenzocorallo Oct 21, 2026
0d918e9
fix(esign): draw no focus ring around the action card's sentence
lorenzocorallo Oct 21, 2026
1f1404c
fix(esign): hide the stamp under a leaving signature box until it fades
lorenzocorallo Oct 21, 2026
699ccc1
fix(esign): drop the toast after New request sends, as the request pa…
lorenzocorallo Oct 21, 2026
9875c5f
fix(esign): number signers only where the order holds
lorenzocorallo Oct 21, 2026
00f6e1f
feat(esign): keep the signing dialog open while the page it lands on …
lorenzocorallo Oct 21, 2026
e347386
fix(esign): show a lost agent as stopped, and keep a ready agent's wi…
lorenzocorallo Oct 21, 2026
b8c2dab
fix(esign): word the blocked PIN and the update like the agent window
lorenzocorallo Oct 21, 2026
3999b4c
fix(esign): say when Start fails, and show "already installed" as an …
lorenzocorallo Oct 21, 2026
e18253d
docs(esign): document the agent's User-Agent, the version gate and th…
lorenzocorallo Oct 21, 2026
34bb7a7
docs(esign): record the decisions round, its deploy order and the new…
lorenzocorallo Oct 21, 2026
6592834
fix(esign): reload the shell's To sign count when New request and a b…
lorenzocorallo Oct 22, 2026
f046647
docs(esign): say that a dashboard the agent doesn't sign for reads as…
lorenzocorallo Oct 22, 2026
25023f6
fix(esign): fit "Choose signer…" beside "Me" in New request
lorenzocorallo Oct 22, 2026
f63c28d
fix(esign): keep "isn't running on this computer" on one line
lorenzocorallo Oct 22, 2026
fd91efb
Merge remote-tracking branch 'origin/main' into feat/esign-ux-pass
lorenzocorallo Oct 22, 2026
103895f
Merge branch 'feat/esign-ux-pass' into feat/esign-ux-decisions
lorenzocorallo Oct 22, 2026
bca5a79
fix(esign): keep a Drive import working when the last folder can't be…
lorenzocorallo Oct 22, 2026
5f8d5e6
fix(esign): describe the macOS Open Anyway step accurately
lorenzocorallo Oct 22, 2026
e080272
Merge remote-tracking branch 'origin/feat/esign-ux-pass' into feat/es…
lorenzocorallo Oct 22, 2026
7745a31
fix(esign): say how to open the update on macOS and Windows
lorenzocorallo Oct 22, 2026
09e5578
Merge branch 'main' into feat/esign-ux-decisions
lorenzocorallo Oct 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 138 additions & 28 deletions docs/design.md

Large diffs are not rendered by default.

86 changes: 82 additions & 4 deletions docs/esign/TRACKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ Legend: ☐ todo · ◐ in progress · ☑ done
- ☑ Review round 1 (Sol 6.1): 15 findings (4 high), all fixed with regression tests; Postgres smoke script
(`backend/scripts/esign-store-smoke.ts`) caught a jsonb double-encoding issue in the new queries.
- ☑ Fallback: upload a PDF signed with the official app (verified as current version + one CIE signature).
Removed from the dashboard on 2026-10-21: CIE ID rewrites a PDF that has no signature yet, so it never worked for
the first signer. The backend's `esign.requests.uploadSigned` is no longer called and can be removed.
- ☑ Smart placement (box under "Il Presidente"/role label), navigation badge for documents to sign.
- ☑ Review round 2 (Sol 6.1, Personal account; its safety filter cut the final report, partial notes in
`/tmp/esign-review-r2b/`): round-1 fixes confirmed; new findings fixed — ByteRange gap must be exactly /Contents,
Expand All @@ -127,16 +129,36 @@ Legend: ☐ todo · ◐ in progress · ☑ done
sign its documents; default unchanged (auth#62 roles + catalog in the snapshot, auth-kit#2, backend, admin).
- ☑ Signer picker lists every registered IdP user with `esign:sign` (filtered by the drives' sign rules), not only
people who opened Signatures; their profile is created with the request (auth#63, backend#79, admin#113).
- ☑ Sign it yourself: when the creator signs first (or is the only signer), the composer's "Create and sign" / "Sign
with CIE" creates the request and opens the agent in the same click; To sign has "Sign a document", which starts
with the creator as first signer (admin only).
- ☑ Sign it yourself, inside New request: "Me" adds the creator in one click, and when the creator signs first (or is
the only signer) the primary, "Sign and send" / "Sign with CIE", creates the request and opens the agent in the same
click ("Send request" on a phone or tablet). The backend doesn't email the creator about a turn that starts as the
request is created. To sign's "Sign a document" and the composer's `?self=true` are gone (admin only).
- ☑ Signature spots in New request: the labels in the PDF's text become rows to fill, each with a box near its label
in clear space (on the signature line when there is one, else under the label or above it), covering no text, no
label and no signature already on the page. Labels match whole and keep qualifiers apart, also wrapped over two
lines ("Vice Presidente" is never "Presidente"); several labels on a line, rotated pages, the first 40 and last 10
pages, and labels at the page bottom are handled. Field captions ("Presidente: Mario Rossi"), sentences ending on a
line of their own, labels without room to sign and labels already signed are not spots. Contracts without labels
keep the free picker, whose boxes share the foot of the last page in signing order (admin only, `places.ts`
tested).
- ☑ Send again: New request takes `?from=<request id>` (any status, so "Duplicate" is one link) and fills in the
title, the signers in order with their roles, the order, the folder, the file name and the email. The PDF is the same
OneDrive item read again, so a corrected file saved over the original is picked up, and its spots are found again
(people keep the spot their role names, the others their places). An uploaded PDF, or a OneDrive file that can no
longer be opened (the composer says so), is the request's first version, before anyone signed, fetched and uploaded
again as a new document. A declined request whose PDF has the same sha256 as that version says "Same PDF as before.",
with "Check again" for a OneDrive file (admin only).
- ☐ After a backend release, optional: reuse a version as a new request's document, so Send again of an uploaded PDF
doesn't take the bytes through the browser and opening it leaves no staged document behind.
- ☐ Create the IdP permission `esign:drives:manage` and grant it to whoever sets drive access (master admins get it).
- ☐ Real-card check that one PIN can make several signatures in a session (`cie-mw`, `opencie`, built-in `cie`).
- ☐ Docs: user guide (install agent, pair CIE), ops (Graph permissions, IdP permissions, env).
- ☐ Setup step 4 (`src/features/esign/setup-page.tsx`) says the status page "should show that PoliNetwork eSign is
running and ready to sign", which fits both v0.3.0 ("The agent is running") and the readiness status page of the next
agent release ("Ready to sign" once reader, card and software check out). Once that release is out, the step can
quote "Ready to sign".
- ☑ Setup page: its inline links (the ArchWiki guide, OpenCIE) are underlined at rest with `inlineLink`, like the
request and batch pages.

## Manual steps for the maintainer (cannot be automated here)

Expand All @@ -157,6 +179,22 @@ Legend: ☐ todo · ◐ in progress · ☑ done
- Windows: apply to SignPath Foundation (free for open source), then set the SIGNPATH_* variables and token, then
drop the Run anyway sentence from AGENT_STEPS.windows.
- ☑ Backend released as @polinetwork/backend 1.7.0 (backend#73 merged); admin uses it (vendored copy removed).
- ☐ Before deploying Setup's "Download for macOS" / "Download for Windows" and the signing dialog's "Update
PoliNetwork eSign" state (agents too old to sign): make `releases/latest` carry `PoliNetwork-eSign-macos.dmg`,
`PoliNetwork-eSign-macos.zip` and `PoliNetwork-eSign-windows-amd64.zip`. Either publish the agent release built from
`feat/sign-page-decisions` (esign "publish the macOS and Windows downloads under fixed names"), tagged `vX.Y.Z` with
no suffix so it is not a pre-release, or, to deploy the dashboard first, upload copies of v0.3.0's
`PoliNetwork-eSign-v0.3.0-macos.dmg`, `-macos.zip` and `-windows-amd64.zip` under those names to the v0.3.0 release
and regenerate its SHA256SUMS. Then check that each name answers 200:
`curl -sL -o /dev/null -w '%{http_code}\n' https://github.com/PoliNetworkOrg/esign/releases/latest/download/<name>`.
Until then they answer 404, and these links, which open in the same tab (a real download leaves the page in place),
replace the dashboard, and the signing dialog with it, with GitHub's 404 page.
- ☐ Deploy order of the decisions round (admin `feat/esign-ux-decisions`, backend `feat/esign-ux-decisions`, agent
`feat/sign-page-decisions`): release and deploy the backend before the dashboard. The dashboard's decline dialog
says "{creator} gets an email with your reason", which only the new backend sends ("Request update" emails); the
version gate works in any order (the backend lets an unknown User-Agent through, the old dashboard doesn't forward
it). The agent release (above) goes out before or with the dashboard; its `ready` and fatal messages need no
dashboard change to be safe, and older agents keep working through `seen`.

## Local end-to-end

Expand All @@ -171,11 +209,51 @@ Open `http://localhost:10431/dashboard/esign/requests` (use `localhost`, not `12

## Log

- 2026-10-22: decisions round integrated (admin `feat/esign-ux-decisions`, backend `feat/esign-ux-decisions`, agent
`feat/sign-page-decisions`; not pushed). The 17 product decisions of the UX pass are decided and built:
- Admin: the signing chain below, plus New request rebuilt as a viewer and one column with the PDF's signature spots
as rows to fill (boxes beside a stack of labels too close for one between them), signing your own PDF inside New
request (`?self` and To sign's "Sign a document" gone), Send again (`?from=`), Setup per system with a direct
download and CIE ID pairing as the check, phones and tablets review only (no flash for an iPad, whose User-Agent is
a Mac's). The New request and batch hand-offs keep their dialog above the routes (`EsignSigningHost`), so the page
they land on loads under it: New request closes it once the new request's page has drawn the signed spot. The
proxy forwards the agent's User-Agent, also the pre-rename `PoliNetwork-Sign-Agent/…`.
- Backend: the version gate (426 `agent_outdated` when the job loads, below 0.2.0, the job failed and seen),
"Request update" emails to the creator (declined, completed by someone else, delivery failed, also to who can
retry), the signed document emailed to externals in Italian with Reply-To set to the requester.
- Agent: fixed asset names for the macOS and Windows downloads, CIE ID named everywhere, the version in the pages'
footer, `ready` and fatal messages to the dashboard, the update screen instead of the PIN form, the card before the
PIN (held while no card is detected, never when presence is unknown), the wrong-PIN count with a warning before the
last attempt and "show PIN", no text on where the PIN comes from.
- Kept on purpose, against the option's wording: the action card's batch link reads "Sign N together", N counting
this document and the others the batch opens with (at most ten, as To sign's button), because that is what one PIN
signs; "Sign the other N together" would undercount it.
- Release order: see the maintainer steps (backend before the dashboard; agent release or renamed v0.3.0 copies
before Setup's downloads).

- 2026-10-21: decisions round, request and batch pages (admin `feat/esign-dec-signing`; not pushed): one action card
holds the title, the status, one sentence and the request's actions, and on desktop the right column stays put while
the cards under it scroll; "Move box" moved into the viewer's toolbar; phones and tablets only review; declined and
cancelled requests offer "Send again" (`/dashboard/esign/new?from=`, which the composer branch fills in); the upload
fallback is gone; the agent proxy forwards PoliNetwork eSign's User-Agent, so the backend can refuse versions too old
to sign. The signing dialog listens for the agent's `ready` and fatal errors (older agents through the job's `seen`),
says within 2.5 s when PoliNetwork eSign isn't running (Start for a browser that has run it, Install otherwise), asks
for an update with a direct download when the agent is too old, and hands off after signing: the page updates
behind it, then the agent window and the dialog close and the box dissolves into the stamp. The `ready` and fatal
messages need the next agent release; until then the dashboard follows `seen`. Copy kept on purpose: a missing
CIE ID module reads "CIE ID isn't set up on this computer" / "Follow the setup guide, then sign again.", as the
agent window says it, not "isn't installed" (CIE ID can be installed with its module out of reach, e.g. without
Rosetta); the lock line is one line ("Mario Rossi is signing right now."), so the card keeps its height; the To sign
and requests lists keep "Requested by {name}", the only place a row says who asks (removed from the request and
batch pages only).

- 2026-10-21: UX pass (admin `feat/esign-ux-pass`, backend `fix/esign-ux`, agent `fix/sign-page-ux`; not pushed): the
signing dialog says how an attempt ended and notices a closed or silent eSign window, jobs and agent windows end on
errors a retry can't fix, plus composer, request, batch, setup and Overview polish. Admin follow-ups after the backend
release: the lock alert's "by HH:MM" from `signingNow.until`; `lostAccess` on the signer card and the drive-access
impact confirmation before saving a sign rule. Open product decisions: `~/dev/polinetwork/esign-ux-decisions-2026-10-21.html` (outside the repo).
impact confirmation before saving a sign rule. The open product decisions it listed
(`~/dev/polinetwork/esign-ux-decisions-2026-10-21.html`, outside the repo) were decided on 2026-10-21 and built in
the decisions round above.

- 2026-10-17: merged backend#75 (released @polinetwork/backend 1.9.0), sign-agent#6 (released PoliNetwork eSign
v0.2.0) and admin#105; the upload fallback warns signers with several places. Flux rolls out the new images.
Expand Down
Loading
Loading