Commit Graph

1562 Commits

Author SHA1 Message Date
Cursor Agent
478e34b82f Add display names for resource-alias OAuth scopes
The OAuth token and consent UIs fall back to the raw scope string when
a label is missing from scopeLabels. Add read and manage labels for
v1:resource-alias so it matches other API scopes.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-02 16:31:32 +02:00
Cursor Agent
a0329a9696 Raise compliance report upload limit to 30MB
Third-party compliance report PDFs were rejected above 10MB in the
upload dialog. Increase the client-side Dropzone limit and enforce the
same cap on the backend file validator.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-02 16:20:51 +02:00
Sacha Al Himdani
2fb06d742e Fix compliance page treating any Slack connector as connected
The compliance page rendered a Slack connector as "Connected" whenever
any SLACK connector existed for the org — including one created for an
access review with no channel configured — and only offered Disconnect,
which deletes the shared connector row.

Distinguish channel-configured connections from unconfigured ones and
let users (re)connect in place to pick a channel without first
disconnecting, reusing the existing reconnect-with-union-scopes flow via
connector_id.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-01 18:04:51 +02:00
Sacha Al Himdani
a651d56c8c Refactor third parties frontend to page arborescence
Mirror the risks refactor (c78a713): colocate routes.ts, split the
detail layout query so each child route owns its Loader + Page, rename
tabs/*Tab to resource folders with *Page, move dialogs into
_components/, and extract ThirdPartyRow with its own fragment.

Remove outlet context data passing and deprecated
loaderFromQueryLoader. Delete the monolithic ThirdPartyGraph hook,
colocating each GraphQL operation with its consumer: the create
mutation in CreateThirdPartyDialog (now useMutation + useToast) and
the third-party list queries in ThirdPartiesCell and
ThirdPartiesMultiSelectField (now useQueryLoader + usePreloadedQuery).

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-01 17:43:45 +02:00
Sacha Al Himdani
1df4af4556 Add document webhook events
Add a resource-oriented set of webhook events for the document
lifecycle. Each event carries the document plus only the sub-resource
it concerns (version, signature or approval).

Events:
- document.created / updated / archived / unarchived / deleted
- document.version.created / updated / published / rejected / deleted
- document.version.signature.requested / signed / cancelled
- document.version.approval.requested / approved / rejected / voided

Wires the new types through the migration, Go enum, GraphQL schema,
CLI, n8n nodes and the console webhooks settings UI.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-01 17:13:59 +02:00
Cursor Agent
ba2a47d262 Use entries count for access review closure
Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-06-30 14:11:08 +02:00
Cursor Agent
5bf8727076 Allow closing failed access reviews
Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-06-30 14:11:08 +02:00
Émile Ré
930c6bab45 Build compliance portal home page sections
Add the frameworks (Compliance), security commitments, trusted-by, and
recent updates sections to the home page, plus a site-wide "Powered by
Probo" footer. Frameworks, references, and updates are relay-driven; the
security commitments section uses placeholder POJO data until a backend
exists.

Keep generic primitives in the v2 kit (ProboLogo, a faint Text tone, and
a soft Card variant with padding="none") and place the product-specific
cards under the app's components folder, composing the base Card. Resolve
each framework's themed logo in the graph via Framework.themedLogoUrl,
mirroring the trust center logo resolver.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-29 09:15:50 +02:00
Émile Ré
6bcb7461be Address compliance-portal review feedback
Fix the valid issues raised in the scaffold review.

UI kit: the Button loading state now replaces only the leading icon
instead of dropping the label, Button consumes the `active` variant so
it no longer leaks onto the DOM, and every v2 skeleton sets aria-hidden
after the prop spread so a consumer cannot override it.

@probo/relay: guard the caller-supplied onCompleted/onError callbacks so
a throwing callback still settles the awaitable mutation promise instead
of leaving it pending.

compliance-portal: normalize external website hrefs and read hostname
via URL.hostname, add a localized catch-all not-found route, and widen
the .gitattributes glob so colocated __generated__ artifacts at any depth
are marked generated.

Docs: correct the forms guide (Base UI passes plain values, Zod v3
flatten API), spread the child fragment in the permissions example, and
drop references to v2 components that do not exist in the ui guide.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 18:40:08 +02:00
Émile Ré
2a69129a83 Resolve themed trust center logo in the graph
Add a TrustCenter.themedLogoUrl Relay live resolver that reads the
light and dark logos from the graph and subscribes to the system
prefers-color-scheme media query, returning the dark logo (falling
back to the light one) when the OS prefers dark.

The TopBar now selects this single field instead of pulling both logo
URLs and branching on useSystemTheme, keeping the theme-to-URL logic in
the graph where any component can reuse it.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 15:16:18 +02:00
Émile Ré
68907762c7 Wrap user menu email label in a dropdown group
DropdownGroupLabel renders Base UI's Menu.GroupLabel, which requires a
Menu.Group ancestor. The user menu rendered the label directly in the
popup, so opening it threw a missing MenuGroupContext error. Wrap the
email label in a DropdownGroup.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 15:01:12 +02:00
Émile Ré
148f753528 Follow system color scheme live
The dark-mode script set the .dark class once at load. Subscribe to the
prefers-color-scheme media query so the theme also updates while the page
is open when the OS appearance changes.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 15:01:11 +02:00
Émile Ré
c004490b07 Make skeleton widths caller-controlled and sized
TextSkeleton and HeadingSkeleton baked w-full into their shared base.
Under tailwind-variants/lite (no tailwind-merge) that collided with the
caller's width class and won by stylesheet order, so every skeleton
ignored its width: bars stretched full in column contexts and collapsed
in flex rows.

Drop w-full from the base so the single caller width applies, matching
ButtonSkeleton/AvatarSkeleton. Size the compliance-portal TopBar and
Hero skeleton bars to roughly match their English copy, and add a rule
so skeleton widths are revisited when en-US strings change.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 15:01:04 +02:00
Émile Ré
8bfcabd58d Match system color scheme at page load
Add a synchronous head script to the compliance portal that sets the
.dark class on <html> when the OS prefers a dark scheme, so the v2 Radix
theme resolves to dark values before first paint with no flash. Declare
a color-scheme meta so native UI matches the active scheme.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 14:12:37 +02:00
Émile Ré
f53736e352 Remove unused graphql field
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 14:06:16 +02:00
Émile Ré
a5e0fb59e9 Translate portal chrome and page strings
Replace the remaining hard-coded UI copy in the top bar, user menu, home
hero, and the documents/subprocessors/updates/requests pages with i18next
keys, and supply the en-US and fr-FR catalog entries for them. The home
hero title uses value interpolation rather than string concatenation so
word order stays correct across locales.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 14:04:31 +02:00
Émile Ré
86077e6c27 Set up i18next with lazy per-route catalogs
Wire i18next into the compliance portal with a custom backend built on
import.meta.glob, so each _locales/*.json becomes its own lazily loaded
chunk keyed by a namespace derived from the folder path. The active
language is resolved from the browser, collapsing any fr*/en* tag to
fr-FR/en-US with en-US as the ultimate fallback; fallbackLng then only
covers individual missing keys.

Add an app-level default namespace catalog and switch the documents
page title to a translation key to exercise the lazy-loading path.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-28 13:58:14 +02:00
Émile Ré
6ec7efb4fc Use layout skeleton as the root route fallback
On a hard reload the root route briefly showed a generic centered pulse
(PageSkeleton) while the layout chunk downloaded, then snapped to the
topbar skeleton. Point the root Fallback at MainLayoutSkeleton so the
chunk-load fallback matches the loader's own skeleton and the transition
is seamless. PageSkeleton is now unused and removed.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 22:35:20 +02:00
Émile Ré
fe8ac00c70 Add Trust Center hero and page headers
Build the Trust Center landing hero and the nav page headers on a shared
HeaderBand shell. The home page loads its own query and feeds the Hero
(org headline, description, and contact info) via a colocated fragment;
the Documents, Subprocessors, Updates, and Data Requests pages use a
PageHeader (size-7 title, optional count, inline actions). Switch the
layout body to the grey sand-2 canvas so the white header bands read as
surfaces on top.

Split the header UI into focused components rather than one
over-configurable Hero: HeaderBand owns the band, Hero the landing
content, PageHeader the nav-page content. Add a hostname helper under
lib/url and standardize the 1024px container on the max-w-5xl token.

The Documents/Subprocessors filter/search/tabs toolbars and item counts
are deferred until the matching v2 components and queries exist.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 22:33:03 +02:00
Émile Ré
68eaabe0ea Add Trust Center top bar to compliance portal
Build the Trust Center top navigation in a Relay-wired layout route. The
portal now mounts a Relay environment and provider, and the root layout
loads a query whose fragment feeds the TopBar: brand, ghost-pill nav with
an active state from the router, and a guest "Get Access" button versus an
authenticated user menu. Placeholder section routes keep the nav links and
active state functional until real pages land.

Wire the Relay tagged-template transform via @rolldown/plugin-babel and
set the router basename to the /trust/{slug} path prefix so the app
resolves under its served path.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 21:55:09 +02:00
Émile Ré
4656469c47 Drop unused eslint-plugin-relay-types from apps
The @probo/eslint-plugin-relay-types shim only types an
`eslint-plugin-relay` import, which no app makes anymore now that
linting runs through the single root eslint.config.mjs. The apps'
tsconfig.node.json even pulled it in for a per-app eslint.config.mjs
that no longer exists.

Remove the devDependency and the `types` entry from each app's
node tsconfig, and drop the stale eslint.config.mjs include. The
shim stays for packages/eslint-config, its real consumer.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:06 +02:00
Émile Ré
ff966b462e Promote useMutation to the @probo/relay package
Extract the awaitable useMutation into @probo/relay as a
createUseMutation factory that delegates feedback to an injected
MutationNotifier, keeping the package free of UI and i18n
dependencies. compliance-portal binds it to its Base UI toast +
i18next + formatError stack and imports it by explicit path
(#/lib/relay/useMutation), dropping the lone intra-app barrel; a
compliance-portal-scoped no-restricted-imports rule forbids
react-relay's useMutation.

Bring packages/relay and packages/routes into the shared ESLint
scope and fix the violations that surfaced, and deprecate the
legacy withQueryRef / loaderFromQueryLoader helpers. Document the
shared-hook pattern and the "index.ts for package entrypoints only"
rule in the relay, hooks, and app-arborescence guides.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:05 +02:00
Émile Ré
023fb70a58 Add routing foundation to compliance-portal
Wire up react-router with a root layout route and an index home page,
following the single-arborescence conventions: pages live under pages/,
routes are built from AppRoute via routeFromAppRoute, and route bundles
load lazily behind a Suspense fallback.

Add the @probo/routes and @probo/react-lazy workspace dependencies that
the route setup relies on.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:05 +02:00
Émile Ré
eabf46c5cb Add HTTP endpoint helpers to compliance-portal
Introduce a lib/http module with buildEndpoint and getPathPrefix,
extracted from the trust app so the compliance portal can resolve its
GraphQL endpoint with the same path-prefix handling.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:05 +02:00
Émile Ré
18d4b8aa02 Add compliance-portal bundle entrypoint on v2 theme
The compliance-portal scaffold had an index.html pointing at a
src/main.tsx that did not exist, and carried stale config copied
from another app, so the bundle could not build.

Add the React entrypoint (main.tsx, App.tsx), a Tailwind index.css
wired to the standalone v2 theme, and vite-env.d.ts for the CSS
side-effect import and env typing. Scope the Tailwind @source scan
to packages/ui/src/v2 since this is a v2-only build, and use v2
color and type scales in index.html and App.

Drop the deprecated baseUrl from tsconfig.app.json and remove the
invalid react() babel relay option, which is unsupported by
@vitejs/plugin-react 6 and unneeded until Relay queries exist.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:05 +02:00
Émile Ré
c9cc46d359 Migrate compliance-portal to the global ESLint config
The compliance-portal app still carried the per-workspace ESLint
scaffold that the rest of the monorepo dropped when linting was
centralized into the root eslint.config.mjs. It defined its own
local config, lint script, and lint-only devDeps, and was not
covered by the root lint script, so it was never linted.

Remove the local eslint.config.mjs, the lint script, and the
eslint/@probo/eslint-config devDeps, then add the app to the root
appDirs so the shared ts, react, and relay rule sets apply to it.

Replace the explicit per-directory list in the root lint script
with a bare `eslint .`, which the root config was already designed
for via its globalIgnores. Ignore pkg/** so the vendored minified
JS under the Go tree is not linted.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:04 +02:00
Émile Ré
5bc6452eb6 Scaffold compliance-portal frontend app
Add the root configuration files for apps/compliance-portal, the
refactor of the legacy trust center SPA. The scaffold mirrors the
existing trust app (Vite, Tailwind, Relay, TypeScript project
references, ESLint) and targets the trust v1 GraphQL schema, which
the compliancepage backend already serves under /api/trust/v1.

Wire the app into the root relay.config.json with a dedicated
complianceportal project so the Relay compiler emits artifacts for
its sources. External dependencies are pinned to current latest
versions rather than matching the older majors used by the other
apps.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-26 18:52:04 +02:00
Sacha Al Himdani
45b434dd99 Redirect employee to tab list for missing documents
When an email link points to an employee signature or approval document
that has been deleted or is no longer accessible to the user, the detail
pages rendered an infinite spinner. Redirect to the signatures/approvals
tab list instead, both when the document resolves to null and when it has
no accessible versions.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-06-24 19:13:29 +02:00
Cursor Agent
002c91ba11 Fix third party assessment header
Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Sacha Al Himdani <SachaProbo@users.noreply.github.com>
2026-06-23 15:04:20 +00:00
Sacha Al Himdani
a8e8e3e0e7 Allow signature requests only on current published version
Requesting a signature only validated that the version was PUBLISHED, so a
signature could be requested on a superseded (older) published version. Reject
versions that are not the document's current published major/minor, and hide
the request button in the console for non-current versions.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-06-23 16:39:18 +02:00
Bryan Frimin
87f769a816 Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:40:18 +02:00
Bryan Frimin
cb7fb8f5e9 Split trust node lookup into node and aliasedNode
The trust node query previously accepted a String and resolved both GIDs
and slugs through one field, which forced the frontend to lose the ID
type guarantee. Restore node(id: ID!) as a strict GID lookup and add a
dedicated aliasedNode(alias: String!) that parses a GID first and falls
back to slug resolution before delegating to Node.

Inline the former nodeByGID switch directly into Node and drop the helper
file. Point the trust DocumentPage query at aliasedNode so slug-or-ID URLs
keep working.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:40:17 +02:00
Bryan Frimin
a81d3921cf Use resource alias mutations in compliance page
Update the compliance page alias field and list items to call the
generic setResourceAlias and removeResourceAlias mutations instead of
the trust-center-specific ones, and drop the now-removed audit alias
field usage.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:40:16 +02:00
Bryan Frimin
92b1264603 Fix alias resolver, field blur, and sitemap URLs
The audit alias resolver returned raw service errors. Log them
and return gqlutils.Internal like other resolvers in the file.

Remove-only users could edit the alias field to a new value that
was never saved. Reset local state when set permission is missing,
and catch mutation rejections on blur.

Sitemap generation appended audit report file IDs without
deduplication, which could emit duplicate document URLs when
multiple audits share the same report file.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:38:51 +02:00
Bryan Frimin
cd52e7fb0c Use alias slugs for navigation in trust center
Document, file, and audit rows now navigate to /documents/<alias>
when an alias is set, falling back to the resource ID otherwise.
The document page query accepts a string ID to support both forms.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:38:51 +02:00
Bryan Frimin
391ec141e3 Show alias field in compliance page list items
Adds an editable alias column to the documents, files, and audits
tables so operators can set and clear aliases from the console.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:38:50 +02:00
Émile Ré
4d28dab2f4 Centralize ESLint into a single root config
Replace the duplicated per-workspace eslint.config.mjs files in
apps/console, apps/trust, packages/ui, and packages/eslint-config with
one root eslint.config.mjs that reuses the shared @probo/eslint-config
rule sets and scopes them per directory. Linting now runs from the repo
root, so pin the type-checked project service root and broaden the
import-x resolver to every workspace tsconfig (the #/* aliases live in
each app's tsconfig.app.json).

Drop the now-redundant per-package lint scripts and lint-only devDeps,
and add a root lint script that runs eslint over the four dirs with
multithreading restored via --concurrency auto, then lints n8n-node
through a direct workspace call. packages/n8n-node keeps its own
external preset.

Collapse the redundant lint-js -> npm-lint Makefile chain into a single
lint-js target and update the make docs accordingly.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 16:47:43 +02:00
Émile Ré
4348c409a1 Fix lint findings on upgraded console pages
Wrap the usePreloadedQuery calls whose explicit type arguments pushed
them past the 120-character limit, and merge the two duplicate
@probo/helpers imports in FrameworkControlPage into one. These were
flagged by reviewdog on the dependency-upgrade PR.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 14:31:30 +02:00
Émile Ré
abb641111a Fix rela type issue
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 14:27:25 +02:00
Émile Ré
7e943c8105 Drop merged GraphQL schema for split files
Relay no longer needs a single merged schema.graphql: each project in
relay.config.json now reads the split graphql/*.graphql files directly
via `schema` (base.graphql) plus `schemaExtensions`. gqlgen already
consumed the split files, so the merge step only fed Relay and the
optional IDE GraphQL extension.

Remove the merge machinery (contrib/merge-graphql-schema.sh, the
RELAY_SCHEMAS make rules, and the gitignore entry) and drop the
graphql-config files (apps/trust/graphql.config.yml and the root
package.json graphql field); the Relay extension provides schema-aware
language features from relay.config.json on its own.

relay-compiler keeps generated artifacts in sync (stale ones are
removed automatically), so the relay npm script just runs the local
relay-compiler and the make target delegates to it.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 13:51:17 +02:00
Émile Ré
89427845c4 Fix type-aware lint errors on OAuth tokens page
The linter's project service ignores the generated Relay artifacts,
so the untyped usePreloadedQuery call left viewer as an error type and
triggered no-unsafe-argument/member-access errors. Pass the explicit
query generic like the sibling audit-log page does.

Drop the redundant GraphQLError cast on the revoke error handler since
formatError already accepts the callback's error type.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 13:51:17 +02:00
Émile Ré
f98b73f073 Upgrade frontend toolchain to latest majors
Bump React 19.2, Relay 21, React Router 8, Vite 8 with
@vitejs/plugin-react 6, ESLint 10, GraphQL 17, TypeScript 6,
@types/node 24, and Tailwind 4.3 across the workspaces.

vite-plugin-react 6 (Vite 8) no longer runs Babel, so the Relay
tagged-template transform now runs through @rolldown/plugin-babel
in the console and trust Vite configs.

Relay 21 ships first-party types and enables the ambiguous-alias
check by default; disable that flag to preserve existing queries
and add explicit usePreloadedQuery type arguments where the new
types no longer infer the operation. TypeScript 6 deprecations and
stricter inference are addressed in tsconfigs and call sites.

Keep n8n-node on ESLint 9 and eslint-plugin-react on 7.37.5, the
newest releases compatible with their toolchains.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 13:51:17 +02:00
Émile Ré
f1fc2dc0e0 Show persistent for local-storage trackers
Local storage, IndexedDB, and cache storage have no expiry yet
persist until explicitly cleared, so a missing max-age should read
as "persistent", not "session" (the latter only fits cookies and
session storage, which end with the session or tab).

Thread the tracker type through humanizeSeconds (helpers) and
humanizeDuration (cookie-banner, with a localized persistent label)
and pass it at every console and banner call site. The consent
record query now selects trackerType so its duration column can
make the same distinction. This mirrors the Go HumanizedDuration
helper that already renders these types as persistent.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 10:46:44 +02:00
Émile Ré
f56d3daa2c Make tracker pattern category editable on detail page
The category property on the tracker pattern detail page was
read-only text. Wire in the existing MoveToCategorySelect and the
moveTrackerPatternToCategory mutation so a pattern can be recategorized
directly from its detail view, matching the table-row behaviour.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 10:46:44 +02:00
Émile Ré
265c56d00b Improve tracker source and first-party cleanup
Surface every CookieSource value in the console: the trackers page
filter was missing the HTTP option and the source badge helper had no
EXTENSION case, so HTTP-sourced rows could not be filtered and
extension-sourced rows rendered the raw enum string.

On the backend, the mark-first-party verdict now blanks the stale
description on both the catalog row and its uncategorised org tracker
patterns. A terminal non-third-party row keeps no vendor link, so a
description naming the (now-cleared) vendor would be misleading; the
mapping worker only copies descriptions into empty rows and never
clears them, so clearing is done explicitly here.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-19 10:46:43 +02:00
Ludovic Vielle
26c5002932 Add identity-scoped OAuth token management
Let users create, list, and revoke manual bearer tokens from
/me/oauth-tokens, scoped to their identity rather than an
organization. Manual tokens store a null client_id and are
authorized with a self-manage IAM policy.

Wire Connect GraphQL on Identity (list, create, revoke), add
console UI with scoped create flow and credentials dialog, and
cover the flow in e2e tests. Fix list pagination ordering and
keep the Relay connection in sync after create.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-18 20:08:49 +02:00
Ludovic Vielle
3ebb221a9b Add OAuth2 API scope registration and enforcement
Register v1 API scopes in coredata, advertise them in OIDC discovery
and protected-resource metadata, show them on the consent screen, and
enforce scope-to-action mapping in the IAM Authorizer before policy
evaluation.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-18 19:07:25 +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
Bryan Frimin
2c8ae26ea1 Open OIDC child session when assuming organization
OIDC login dropped organization_id before the provider redirect, so
callbacks with an existing matching root session never created an org
child session. Persist organization_id in OIDC state, open the child
session on callback, and forward the parameter from the sign-in UI.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-18 12:11:01 +02:00
Émile Ré
579a382947 Remove tmp modifications
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-18 11:44:14 +02:00