Add a many-to-many relationship between measures and third parties,
surfaced as a measures tab on the third party detail page and a third
parties tab on the measure detail page. Each side gets a paginated
list with a link/unlink dialog.
Also remove the right-hand drawer on the measure detail page and
expose the state as a badge in the page header, mirroring how the
compliance page surfaces its active flag.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Introduce a self-referential many-to-many relation table so a
third party can have child third parties. Each relation is
directional (parent to child); both directions can coexist as
independent rows.
Add a first_level boolean on third_parties (default true) with
a filter on the list page that defaults to showing only
first-level third parties.
Frontend adds a "Third Parties" tab on the detail page where
users can link existing third parties or create new ones from
the common third party catalog (created as non-first-level).
The list page gets a First Level/All toggle filter.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
The previous cleanup deleted every isExtensionCaller() site, including
the one in cookie/storage detectors that did fire reliably for the
residual case: page-world extensions (MV3 main world, userscripts with
@grant none) whose stack contains a chrome-/moz-/safari-web-extension
frame at the synchronous write. Recover that signal for free by
returning fromExtension from getInitiatorURL (it already walks the
stack and discards extension frames via continue), and have the cookie
and storage detectors report source: "extension" instead of "script"
when the flag is set.
End-to-end plumbing reuses the existing source column: extend the
cookie_source Postgres enum with EXTENSION, add the CookieSourceExtension
constant with a doc block describing each bucket's actual semantics,
add the handler.go switch cases, expose EXTENSION on the GraphQL and
MCP CookieSource enums, and add the Extension option to the console
source filter.
Update bestSource in the pattern analysis worker so a glob merging
only extension-attributed exact patterns is no longer silently rolled
up to PRE_EXISTING. New precedence is SCRIPT > EXTENSION > PRE_EXISTING,
matching the upsert SQL's "page-script wins" rule and the asymmetric
signal strength of each bucket.
Out of scope: any behavioural use of EXTENSION (auto-exclusion,
denylist classification, dashboard surfacing) -- that belongs in the
follow-up backend denylist plan.
Signed-off-by: Émile Ré <emile@probo.com>
Audited pkg/server/api/console/v1 for resolvers that touched tenant
data without calling r.authorize, batchAuthorize, or Permission. Closed
every gap so every data-bearing field goes through IAM (and produces an
audit log entry when an organization_id is present).
* High-severity reads now authorize: accessSourceResolver.Connector and
ConnectionStatus, controlResolver.Regulatory/Contractual/RiskAssessment,
electronicSignatureResolver.CertificateFileURL/Events,
commonThirdPartyResolver.LogoURL, and the proper
accessSourceResolver/accessReviewCampaignResolver/auditLogEntryResolver
Organization resolvers (authorize + dataloader load, fixing the latent
empty-name bug from the previous force-resolver no-op implementations).
* TotalCount/DetectedCount aggregates now authorize the matching list
action across access review, audit log, statement of applicability,
detected tracker, tracker pattern, and tracker resource connections.
* queryResolver.CommonThirdParties authorizes against the principal's
identity via the new identity-scoped CommonThirdPartyCatalogPolicy.
* Add ActionCommonThirdPartyGet/List, ActionElectronicSignatureGet probo
action constants; wire ActionElectronicSignatureGet into ViewerPolicy
and AuditorPolicy.
* Implement AuthorizationAttributes on CommonThirdParty (no org) and
ElectronicSignature (organization_id) so the authorizer can resolve
attributes for the new actions.
* Delete the dead "type AccessReview" GraphQL type (no Go constructor,
no frontend reference) and drop its orphan resolver bundle.
Signed-off-by: Bryan Frimin <bryan@probo.com>
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>
Each scope card now shows a flowchart of its nodes, processes, and
threats, with a distinct shape per type: stadium for entities,
hexagon for boundaries, rectangle for assets, cylinder for data, and
a red hexagon for threats attached via dashed edges to their process
target. The Mermaid source is built on the backend and exposed as a
new `mermaid` field on RiskAssessmentScope; the frontend just renders
it via @probo/ui's MermaidDiagram and shows a copy button + legend.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Introduce a hierarchical risk assessment model with six entity types:
- Risk Assessment: top-level container scoped to an organization
- Risk Assessment Scope: sub-container for scoping threat modeling
exercises within an assessment
- Risk Assessment Node: DFD elements typed as ENTITY, BOUNDARY,
ASSET, or DATA within a scope
- Risk Assessment Process: directed data flows between two nodes
- Risk Assessment Threat: descriptive threats attached to a process
with a free-text category (e.g. Confidentiality, Integrity)
- Risk Scenario: thin join linking a threat to a risk from the
register, carrying only a name and description
Risk scoring (likelihood, impact, treatment) remains on the existing
Risk entity. Threats are purely descriptive. Risk Scenarios connect
the threat model to the risk register without duplicating scores.
Backend: migration with PG enum for node types, coredata structs,
service layer with full CRUD and validation, GraphQL schema with
18 mutations and paginated connections, authorization actions and
policies, and base_resolvers.go Node dispatch for all entity types.
Frontend: Risk Assessments list page with create dialog, detail page
showing scopes as cards with nodes/processes/threats tables, inline
create/edit/delete actions on all entities, and a Scenarios tab on
the Risk detail page linking threats to risks. Existing RiskGraph.ts
hook file removed in favor of colocated queries in page files.
E2E tests cover CRUD for all entity types, RBAC, and tenant
isolation.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
- Require CLIENT_SECRET for new access-review connectors
- Use Heroku account UUID as ExternalID
- Bump GitHub orgs picker to per_page=100
- Drop Snyk, Ramp, Lever, Deel access-review providers
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Renames the user-facing 'vendor' concept to 'third party' across the
entire codebase. The shared common_third_parties reference table is
unchanged.
Migration. Renames the vendor_category enum, the vendors and
vendor_<entity> tables (contacts, services, compliance_reports,
business_associate_agreements, data_privacy_agreements,
risk_assessments) and their vendor_id columns, the asset_vendors /
data_vendors / processing_activity_vendors junction tables,
generated_documents.vendors_document_id, the webhook_event_type
'vendor:<verb>' values, and the snapshots_type 'VENDORS' value.
Backend. Renames coredata models and SQL queries, probo services,
GraphQL / MCP API surface, console / trust / webhook resolvers and
types, the CLI (prb vendor* -> prb third-party*; pkg/cmd/vendormgmt
-> pkg/cmd/thirdpartymgmt), the document generator, vetting agent
prompts, and the common-third-parties-import command.
Frontend, packages, n8n, e2e. Renames apps/console pages, components,
hooks, routes, dialogs, and tabs; the shared @probo/vendors package
(now @probo/third-parties); the @probo/ui Vendors atoms (now
ThirdParties, VendorLogo -> ThirdPartyLogo); the n8n community node
actions/vendor folder (now actions/thirdParty); and the e2e Go test
suite (console and MCP). Filesystem and URL paths use kebab-case
(third-parties), GraphQL fields and TypeScript identifiers use
camelCase (thirdParty / thirdParties), Go types use PascalCase
(ThirdParty), and human-facing text uses 'third party' with a space.
Co-authored-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
The consent mode is now determined dynamically by the visitor's
country and its applicable regulation. The configured consent_mode
column is dropped from cookie_banners and added to
cookie_consent_records to persist the geo-derived mode at
consent-recording time. When no regulation matches, the default
is OPT_OUT.
Signed-off-by: Émile Ré <emile@getprobo.com>
The description field was never surfaced in the UI and added no value.
Drop it from the database, Go structs, GraphQL schema, import tool,
frontend fragment, and vendor seed data.
Signed-off-by: Émile Ré <emile@getprobo.com>
Fetch favicons at import time instead of calling Google's favicon
service per page load. Logos are stored as public files in S3 and
served through the existing /api/files/v1/{id} endpoint.
Signed-off-by: Émile Ré <emile@getprobo.com>
The CreateVendorDialog previously loaded the entire @probo/vendors
JSON bundle client-side and used MiniSearch for fuzzy search. This
replaces it with a GraphQL query against the common_third_parties
database table, searched server-side via ILIKE filtering.
Backend: adds CommonThirdParty GraphQL type, a pkg/thirdparty
service, and a commonThirdParties(name) root query. Frontend:
splits into CommonThirdPartyCombobox (display) and an @inline
fragment read on selection via readInlineData.
Signed-off-by: Émile Ré <emile@getprobo.com>
A registered service worker is a URL-shaped artifact (origin+path of
the worker script), so it goes in tracker_resources as a new
SERVICE_WORKER resource type. A Cache Storage bucket is an opaque
named string with no URL, so it goes in detected_trackers as a new
CACHE_STORAGE tracker type.
Frontend:
- StorageDetector wraps caches.open() and enumerates caches.keys()
on start to surface pre-existing buckets that pre-date the SDK
load (service workers commonly populate caches eagerly on
install).
- ThirdPartyDetector wraps navigator.serviceWorker.register() and
enumerates getRegistrations() on start.
Both wrappers degrade silently on insecure contexts where these APIs
are unavailable.
Signed-off-by: Émile Ré <emile@getprobo.com>
ThirdPartyDetector previously only saw <script src> and <iframe src>
because it scanned the DOM and watched mutations. Add a single
PerformanceObserver({type:'resource', buffered:true}) that picks up
everything the browser actually loaded:
- tracking pixels (<img>, <picture>, srcset)
- cross-origin stylesheets and web fonts
- fetch / XHR / sendBeacon / ping calls (SDK call-homes)
- video, audio, embed, object media
initiatorType is mapped to six new tracker_resource_type enum values
(IMAGE, STYLESHEET, FONT, BEACON, FETCH, MEDIA) and the existing
upsert path in tracker_resources picks them up unchanged.
Closes a real gap with headless cookie scanners: most SDKs phone home
via beacons after their script is gone, and the DOM scan never saw it.
Signed-off-by: Émile Ré <emile@getprobo.com>
Add the full GraphQL surface for the new tracker_resources table:
- TrackerResourceType enum (SCRIPT, IFRAME), TrackerResource node type
with connection/edge/order/filter, fields on CookieBanner
(uncategorisedTrackerResources) and CookieCategory (trackerResources).
- Mutations: createTrackerResource, updateTrackerResource,
deleteTrackerResource, moveTrackerResourceToCategory with
inputs and payloads.
- Resolvers for all mutations, connection fields, field resolvers
(cookieCategory, permission), and totalCount.
- IAM actions: core:tracker-resource:{get,list,create,update,delete}.
Signed-off-by: Émile Ré <emile@getprobo.com>
Move resource tracking (scripts, iframes) out of the pattern-based
tracker_patterns/detected_trackers machinery into its own
tracker_resources table keyed by (banner, type, origin, path).
- Add migration that creates the tracker_resource_type enum, the
tracker_resources table with a unique index, drops existing
SCRIPT/IFRAME rows (not yet in production), and recreates the
tracker_type enum without those values.
- Add TrackerResource coredata model with full CRUD, Upsert (bumps
last_detected_at on conflict), list/count/move operations, filter,
and order field support.
- Register TrackerResourceEntityType (91) in the entity type registry.
- Drop TrackerTypeScript/TrackerTypeIframe from TrackerType enum.
- Update handler to use TrackerResourceType for resource detection.
- Temporarily stub out resource ingestion in ReportDetectedTrackers
pending the service-layer wiring in the next commit.
- Drop SCRIPT/IFRAME from the GraphQL TrackerType enum.
Signed-off-by: Émile Ré <emile@getprobo.com>
The displayName field was always predictable from pattern + matchType
and allowing edits added unnecessary complexity. Remove displayName
from UpdateTrackerPatternInput across all surfaces (GraphQL, MCP, CLI,
n8n) and make the frontend show it as non-editable text.
Signed-off-by: Émile Ré <emile@getprobo.com>
Add proper enum types for Regulation and CountryCode in GraphQL
(with @goModel/@goEnum directives) and MCP (as standalone reusable
schemas with $ref). Update CLI, console UI, and n8n to include
the new fields.
Signed-off-by: Émile Ré <emile@getprobo.com>
Move cookie banner types (CookieItem, Category, Regulation, BannerConfig,
etc.) into a dedicated types.ts file. Add a coredata.Regulation type with
parsing, JSON marshaling, and database scanning methods. Hardcode the
geoloc-import data directory since the submodule path is fixed.
Signed-off-by: Émile Ré <emile@getprobo.com>
Source fetch failures stay surfaced on the source fetch (status and
last error) instead of failing the entire campaign, so reviewers can
proceed on the sources that succeeded.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Microsoft 365's native SCIM endpoint is unreliable, so mirror the
Google Workspace bridge over Microsoft Graph: a new MICROSOFT_365
OAuth2 connector, a SCIM bridge provider listing /v1.0/users with
$select pagination, and an access review driver that derives admin
status from /directoryRoles members. Refactor the bridge runner to
share OAuth2 plumbing across providers and surface the new bridge
type, scopes, UI card, and bootstrap env wiring.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
Delete coredata.CookiePattern and all associated CRUD methods,
rename shared types (CookiePatternOrderField, CookiePatternFilter,
CookiePatternMatchType) to TrackerPattern equivalents, and migrate
all API surfaces (GraphQL, MCP, CLI, n8n) to tracker_pattern naming.
The worker was already migrated in the base branch; this commit
completes the removal by dropping the old GraphQL schema/resolvers,
service methods, CLI commands, and n8n operations that operated on
the legacy cookie_patterns table.
Signed-off-by: Émile Ré <emile@getprobo.com>
Exclude the UNCATEGORISED category at the SQL level so
the admin cookie/display/translations pages only see
consent-relevant categories. Removes dead client-side
UNCATEGORISED filters that are no longer needed.
Signed-off-by: Émile Ré <emile@getprobo.com>
Backend for the cookie banner detection page: a new
uncategorisedPatterns connection on CookieBanner with
sortable (NAME, LAST_MATCHED_AT, UPDATED_AT, SOURCE)
and filterable (text ILIKE on name/description, source
enum) paginated results. COALESCE handles NULL-first
ordering for last_matched_at.
Signed-off-by: Émile Ré <emile@getprobo.com>
Add lastMatchedAt to the CookiePattern GraphQL type, MCP schema,
CLI view/list commands, and n8n get/getAll operations. Run
codegen to regenerate gqlgen models and MCP types.
Signed-off-by: Émile Ré <emile@getprobo.com>
Replace the old snapshot-based system for risks with the publish
document system, mirroring the prior vendor / processing activity / DPIA
/ TIA migration. Includes the GraphQL mutation, MCP tool, CLI command,
n8n operation, frontend publish dialog, e2e tests, and a prosemirror
register template covering name, description, category, treatment,
owner, inherent and residual scoring, and notes.
The risk register lives as a generated DocumentTypeRegister document on
the organization, reused across publishes (the major version bumps on
every republish). Approvers can be passed in to create a draft pending
approval; otherwise the version is published immediately. The frontend
Risks page exposes a Publish button and a Document link button when the
document exists, and pre-fills the previous default approvers.
Risks was the last remaining snapshot type, so this commit also removes
the entire snapshot system: drop snapshotId from the Risk GraphQL type
and RiskFilter; remove RiskSnapshotter, Risks.Snapshot,
InsertRiskSnapshots, and the SnapshotID/SourceID fields on Risk; delete
Snapshot, ControlSnapshot, SnapshotsType, SnapshotOrderField,
Snapshottable, the SnapshotService, the Snapshot console resolvers and
GraphQL schema, the Snapshot MCP types and operations
(list/get/take/listControlSnapshots), the snapshot CLI (prb snapshot),
the snapshot frontend pages, routes, banner, LinkedSnapshotsCard,
SnapshotGraph, snapshot helpers, and the snapshot n8n resource and
control link/unlink snapshot operations. The snapshot_id columns remain
in the database but are now filtered out with snapshot_id IS NULL.
Add Get/Upsert/Clear GeneratedDocumentID methods on Risk backed by a new
risks_document_id column on generated_documents, matching the
ProcessingActivity/Finding/Vendor pattern. The migration command
migrate-risk-snapshots-to-documents uses raw SQL queries instead of the
Go snapshot types, since those are gone.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Expose excluded on the CookiePattern type and accept it as
an optional input on UpdateCookiePatternInput so the console
can toggle pattern exclusion inline.
Signed-off-by: Émile Ré <emile@getprobo.com>
Replace the free-form duration TEXT column with a nullable
max_age_seconds INTEGER on both cookies and cookie_patterns
tables. The SDK detector now sends raw seconds instead of
humanized strings, eliminating locale-dependent comparisons
in the pattern merge worker. Humanization happens at display
time in the widget and console UI.
Signed-off-by: Émile Ré <emile@getprobo.com>
The console now manages CookiePattern entities instead of raw
Cookie rows. The frontend queries cookiePatterns on each category
and uses createCookiePattern, updateCookiePattern,
deleteCookiePattern, and moveCookiePatternToCategory mutations.
The entire Cookie GraphQL surface (type, connection, mutations,
inputs, payloads, resolvers, Go types) is removed since the
backing struct already lost description and cookieCategoryID.
Signed-off-by: Émile Ré <emile@getprobo.com>
Add CookiePattern type, connection, and mutations to the GraphQL schema
with full resolver implementations. Add service methods for pattern
CRUD, category movement, listing, and counting. This enables the console
to manage cookie patterns instead of individual cookies.
Signed-off-by: Émile Ré <emile@getprobo.com>
Cookies set by browser extensions are not the website operator's
compliance responsibility. This adds stack-trace inspection to
filter out extension-originated document.cookie writes, and
annotates pre-existing cookies with a source field so operators
can triage them separately.
Introduces a CookieSource enum (SCRIPT / PRE_EXISTING) across
the full stack: PostgreSQL, coredata, service, HTTP handler, and
GraphQL schema. On conflict, source is upgraded from PRE_EXISTING
to SCRIPT when a page script is later observed setting the cookie.
Signed-off-by: Émile Ré <emile@getprobo.com>
Replace the old snapshot-based system for vendors with the publish
document system, mirroring the prior processing activity / DPIA / TIA
migration. Includes the GraphQL mutation, MCP tool, CLI command, n8n
operation, frontend publish dialog, e2e tests, and a prosemirror
register template covering vendor profile fields plus per-vendor
sections for services, contacts, risk assessments, compliance reports,
BAA and DPA agreements.
The vendor register lives as a generated DocumentTypeRegister document
on the organization, reused across publishes (the major version bumps
on every republish). Approvers can be passed in to create a draft
pending approval; otherwise the version is published immediately. The
frontend Vendors page exposes a Publish button and a Document link
button when the document exists, and pre-fills the previous default
approvers.
Remove snapshot mode entirely from vendors and their sub-entities: drop
snapshotId/sourceId from GraphQL Vendor type and VendorFilter; remove
SnapshotsTypeVendors from the snapshot registry and delete
Vendors.Snapshot, VendorSnapshotter interface and all
*.InsertVendorSnapshots methods on contacts, services, risk
assessments, compliance reports, BAA and DPA. Drop the snapshot routes
and banner from the frontend. The snapshot_id columns remain in the
database but are now filtered out with snapshot_id IS NULL.
Add Get/Upsert/Clear GeneratedDocumentID methods on Vendor backed by a
new vendors_document_id column on generated_documents, matching the
ProcessingActivity/Finding/Obligation pattern.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Replace the old PDF/snapshot-based exports for processing activities,
Data Protection Impact Assessments and Transfer Impact Assessments with
the publish document system. Includes GraphQL mutations, MCP tools, CLI
commands, n8n operations, frontend publish dialogs, e2e tests, and
prosemirror register templates that mirror the previous PDF layouts.
Each register lives as a generated DocumentTypeRegister document on the
organization, reused across publishes (the major version bumps on every
republish). Approvers can be passed in to create a draft pending
approval; otherwise the version is published immediately. The frontend
ProcessingActivities page exposes a Publish dropdown per register and a
Document link button per active tab, pre-fills the previous default
approvers, and navigates to the published document on success.
Remove snapshot mode entirely from these three entities: drop snapshotId
and sourceId from GraphQL schemas, types, filters, resolvers, MCP spec,
frontend routes and pages; remove SnapshotsTypeProcessingActivities from
the snapshot registry and delete the ProcessingActivities.Snapshot,
ProcessingActivitySnapshotter interface and *.InsertProcessingActivitySnapshots
methods. The snapshot_id columns remain in the database but are now
filtered out with snapshot_id IS NULL.
Add Get/Upsert/Clear GeneratedDocumentID methods on each entity type
(ProcessingActivity, DataProtectionImpactAssessment,
TransferImpactAssessment) backed by new columns in the generated_documents
table, matching the Finding/Obligation pattern.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Display record attributes and parsed consent data with
per-category consent state and cookies from the banner
version snapshot. The page lives outside the config layout
with its own breadcrumb navigation.
Signed-off-by: Émile Ré <emile@getprobo.com>
Replace the opaque cookieBannerVersionId filter with an
integer version filter. The SQL filter now resolves the
version number via a subquery against cookie_banner_versions.
Also fix the CookieBannerVersion resolver on consent records
to load the full version from the database instead of
returning a stub with only the ID set (which caused the
version to always display as 0).
Signed-off-by: Émile Ré <emile@getprobo.com>
Exposes the cookie consent record audit trail through a new
"Consent Records" tab on the cookie banner configuration page.
The full stack includes: extended coredata filter (visitor ID,
banner version), GraphQL schema/types/resolvers, and a React
page with SortableTable (size 50) and three compliance filters
(action, visitor ID, banner version).
Signed-off-by: Émile Ré <emile@getprobo.com>
Replace the old snapshot-based approach with the new publish document
system for findings and obligations. Includes GraphQL mutations, MCP
tools, CLI commands, e2e tests, frontend publish dialogs, and
snapshot-to-document migration tools.
Remove snapshot mode entirely from findings and obligations: drop
snapshotId from GraphQL schemas, filters, resolvers, MCP spec, frontend
routes, pages, and helpers. The snapshot_id column remains in the
database but is now filtered out with snapshot_id IS NULL.
Remove auditor's ability to publish SoA.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Replace the --active boolean flag with two explicit filters:
--state (ACTIVE/INACTIVE) and --contract-ended (true/false).
Also add state filter support to the console GraphQL API.
Signed-off-by: Émile Ré <emile@getprobo.com>
Add the profile state attribute (ACTIVE/INACTIVE) to the MCP
Profile schema so listUsers and getUser tools expose it, and
add a state filter to listUsers.
Rename excludeContractEnded to contractEnded across the entire
stack (MCP, GraphQL, CLI, frontend). The new boolean is two-way:
true returns only users with ended contracts, false returns only
users with active or no contract, and null returns all.
Signed-off-by: Émile Ré <emile@getprobo.com>
Introduce a required cookie_policy_url alongside the existing
privacy_policy_url (now optional) so banners can link directly to a
dedicated cookie policy — a compliance best practice recommended by
CNIL, ICO, and the EDPB. Existing rows are seeded from their current
privacy_policy_url value.
Both {{cookie_policy_link}} and {{privacy_policy_link}} placeholders
are supported independently in banner description translations.
Signed-off-by: Émile Ré <emile@getprobo.com>
Origin is a fundamental identity property of a banner tied to consent
records for a specific site. Changing it would break the audit trail
and violate GDPR consent specificity requirements.
Signed-off-by: Émile Ré <emile@getprobo.com>