Commit Graph

11 Commits

Author SHA1 Message Date
Émile Ré
eecf8a1d97 Make profile state filters multi-value
Address PR review feedback on the profile-state split: SAML sign-in now
activates a pending profile, deactivation counts owners against the
profile's own organization to close a last-owner bypass, the migration
leaves historical activated_at/deactivated_at NULL rather than
fabricating timestamps, and pending members are no longer rendered with
the deactivated (faded) styling.

Drop the single-value state filter in favor of the multi-value states
across the profile and signatory surfaces. Remove ProfileFilter.state
(only states[] remains) and convert the signatures profileState filter
to profileStates. Turn the console people filter, the CLI
"user list --state" flag, and the n8n listUsers and getAllSignatures
state inputs into multi-select controls, where an empty selection means
all states.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Bryan Frimin
8773a54396 Rename GraphQL APIs to compliance portal
Update console, visitor, MCP, and Slack API
surfaces so schemas and resolvers use the
Compliance Portal naming consistently.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:24 +02:00
Sacha Al Himdani
f83b42d2ec Rename signature filter state field to profileState
The DocumentVersionSignatureFilter exposed a field named `state` that
actually filters on the signatory's profile state, which was ambiguous
next to the signature `states` field. Rename it to `profileState`
(GraphQL) / `profile_state` (MCP) across the schema, spec, resolvers,
console app, and n8n node for clarity.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-07 16:06:56 +02:00
Bryan Frimin
c50aa28364 Expose alias field and set/remove mutations in console API
Adds an alias field to Document, Audit, and TrustCenterFile types.
Introduces setTrustCenterAlias and removeTrustCenterAlias mutations
with proper authorization and error handling.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:38:49 +02:00
Sacha Al Himdani
f462b124e6 Batch signature and approval notifications via debounced worker
Replace the immediate per-document approval email and the manual
"send signing notifications" action with a single debounced worker that
batches pending requests per recipient and organization.

The worker (go.gearno.de/kit/worker) polls on an interval (default 5m)
and claims one (organization, recipient) group at a time, sending one
consolidated signing email and/or one approval email per recipient/org
that lists every document awaiting their signature or approval. The
claim is a conditional UPDATE that doubles as concurrency-safe dedup, so
several workers never email the same group twice.

Each request is notified once it has been pending past the debounce
delay (default 15m), then reminded at 1x, 2x and 3x the reminder
interval (default 1 day) after the previous email, after which it stops.
New last_notified_at and notification_count columns on signatures and
approval decisions drive the debounce, the widening reminder cadence and
the four-email cap.

Email copy lists each document with its title, type and a deep link to
the employee page. Removed the inline approval-on-publish email, the
SendSigningNotifications service method/mutation/MCP tool, its IAM action,
and the related console UI and n8n operation.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-06-18 15:39:04 +02:00
Sacha Al Himdani
bf20ca1a90 Add esign to document signatures
Employee document signatures recorded an acknowledgment with no
cryptographic proof, unlike document approvals which already create
and accept an electronic signature on every decision.

Mirror the approval flow on the sign path: generate the signed
document PDF, create-and-accept an esign record, and persist its id
on the document_version_signatures row through a new
electronic_signature_id column. Capture the signer IP and user agent
in the resolver, and re-check the published/archived preconditions
inside the transaction so the seal cannot race document state.

Make the consent wording a single backend source of truth shared by
the text that is sealed and the text shown in the UI. Define
DocumentSignatureConsentText and DocumentApprovalConsentText in the
probo service package and the NDA copy in the trust service, each
owned by the flow that uses it, and stop esign from appending the
generic clause to caller-provided consent text so approvals no
longer seal a duplicated sentence.

Expose the resolved consent text through GraphQL on
EmployeeDocumentVersion and DocumentVersionApprovalDecision, and have
the signing, approval, and NDA pages render it from the API instead
of hard-coded strings, mirroring how the NDA page already worked.

Align the wording with the actual interaction: the buttons read
"Review and sign" and "Review and approve", the clauses reference
those actions, and the inaccurate "typing my full name" phrasing is
removed everywhere.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-06-15 19:18:42 +02:00
Sacha Al Himdani
83445c6e34 Fix signature count mismatch with signatures tab on documents
The badge on a document version showed signatures filtered by
activeContract: true, while the signatures tab fetched signatures with
no filter and listed people filtered by contractEnded: false and
state: ACTIVE. The two views disagreed both when a signer's contract had
ended and when a signer was deactivated while still under contract.

Add a state: ProfileState field to DocumentVersionSignatureFilter
alongside the existing activeContract filter, so the signature query
can mirror the same predicates as the people query. Pass
{ activeContract: true, state: ACTIVE } from the badge, the document
list item, and the signatures tab fragment. The same filter is now
evaluated on both the count and the list.

Threaded through the console and MCP resolvers, the MCP spec, and the
n8n getAllSignatures operation.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-22 14:34:35 +02:00
Sacha Al Himdani
1434d8336c Allow publishing generated documents as minor versions
Generated documents (asset list, risk register, SoA, ...) previously
only ever produced a new major version. Every regeneration of an
auto-built register consumed a major number, even when the change was
trivial. They now accept a minor flag and publish as
currentMajor.currentMinor+1 when set, bypassing the approval flow.

To carry the flag through cleanly, the document publish API was
refactored. The three split mutations (publishMajor, publishMinor,
requestDocumentVersionApproval) and the two bulk variants collapse
into a single publishDocument / bulkPublishDocuments, both taking the
new minor: Boolean! and a now-required changelog: String!. The same
shape flows through the CLI ("prb document publish --minor"), the MCP
tool, the n8n operations, and the Relay dialogs, where each
generated-doc dialog gains a "Publish as minor" button. Publishing
minor without an existing major is rejected with
ErrCannotPublishMinorWithoutMajor.

This is a deliberate breaking change for callers of the prior
mutations.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-06 14:02:59 +02:00
Sacha Al Himdani
c635492f75 SOA as document: replace export with publish workflow
Statements of Applicability are no longer exported as one-off PDFs.
Instead, each SOA owns a persistent document that accumulates versions
over time, following the same publish/approve lifecycle as authored
documents.

Publishing without approvers publishes immediately; publishing with
approvers creates a draft pending approval via the existing quorum
system. SOAs can also store default approvers that are pre-populated in
the publish dialog.

The SOA is removed from the snapshot system — applicability statements
are now queried directly (snapshot_id IS NULL) rather than through
snapshot copies.

A standalone migration script (cmd/migrate-soa-snapshots-to-documents)
converts existing SOA snapshots into documents with proper ProseMirror
content, preserving version history and approval decisions.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 00:01:13 +02:00
Émile Ré
5f93071b20 Consolidate hub type definitions into their own files
Move Organization, Identity, TrustCenter, and Viewer definitions to
include all their connection fields directly, removing all extend type
blocks for these hub types from entity files.

This eliminates the Relay schemaExtensions constraint where extend type
could only target types defined in the main schema file. Entity files
now only define their own standalone types and extend type Mutation.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 09:19:39 +04:00
Émile Ré
31cca05ca4 Split GraphQL schemas into per-entity files
Split each API's monolithic schema.graphql into per-coredata-model
files under graphql/ subdirectories. gqlgen's follow-schema layout
with {name}.resolvers.go template generates one resolver file per
schema file. Relay uses schema + schemaExtensions to load the split
files.

Connect API: 8 files (base, session, organization, profile,
personal_api_key, saml, scim, audit_log)

Trust API: 5 files (base, trust_center, auth, nda, mailing_list)

Console API: 25 files covering all domain entities

Types extended across files (Organization, Mutation, Viewer,
TrustCenter, Identity) are defined in base.graphql as required by
Relay's schemaExtensions.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 09:19:38 +04:00