21 Commits

Author SHA1 Message Date
Sacha Al Himdani
4c57d201a4 Make license declarations consistently MIT
The source headers, LICENSE files, and license metadata had drifted
apart. Align the entire project to MIT:

- Convert every source-file header to the MIT text across all comment
  styles (Go, TS, TSX, JS, MJS, SQL, CSS, GraphQL, shell), including
  SPDX-License-Identifier tags
- Set the root and cookie-banner LICENSE files to the MIT text with a
  "MIT License" title line
- Switch the package.json license fields, Docker image label, and
  cookie-banner README to MIT
- Update docs and the genmodels header generator accordingly
- Normalize copyright lines to a single format
  (Copyright (c) <year(s)> Probo Inc <hello@probo.com>.): unify the
  hello@getprobo.com and hello@probo.inc emails to hello@probo.com and
  the comma-separated years to a hyphenated range

Genuine third-party references are intentionally left untouched: the
Lucide icon attributions (Lucide is ISC) and the trivy dependency
license allowlist.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-13 16:21:14 +02:00
Sacha Al Himdani
9ac71f948f Update contact email to hello@probo.com
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-06-09 16:45:23 +02:00
Émile Ré
6e07da9ab2 cookiebanner: add TrackerResource service layer
Wire resource ingestion and add full CRUD + list/count service methods
for the new tracker_resources table.

- reportDetectedResource splits the URL into origin/path and upserts
  into tracker_resources with the uncategorised category.
- CreateTrackerResource, GetTrackerResource, UpdateTrackerResource,
  DeleteTrackerResource, MoveTrackerResourceToCategory mirror the
  tracker-pattern service surface.
- ListTrackerResourcesForCategory, CountTrackerResourcesForCategory,
  ListUncategorisedTrackerResources, CountUncategorisedTrackerResources
  provide paginated access.
- Request structs with Validate() and dedicated error sentinels.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:53 +04:00
Émile Ré
af6e420f54 Remove cookie_patterns legacy, migrate to tracker_patterns
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>
2026-05-06 12:26:12 +04:00
Émile Ré
33abbfbb8f Link detected cookies to existing patterns on conflict
When a cookie pattern already exists for a banner, the insert
conflict caused a continue that silently dropped the detected
cookie instead of linking it to the existing pattern. Load the
existing pattern to obtain its ID and proceed with cookie
insertion.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:13 +04:00
Émile Ré
e5e1119883 Remove dead code from cookiebanner and coredata packages
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:12 +04:00
Émile Ré
9c402058ec Add GraphQL API and service CRUD for cookie patterns
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>
2026-04-30 11:46:10 +04:00
Émile Ré
9fbb716b00 Constrain PostHog consent to one normal category per banner
Add a partial unique index ensuring only one category per banner can
have posthog_consent enabled. Default it to the analytics category on
banner creation, clear the previous mapping before setting a new one,
and restrict the toggle to NORMAL categories in both the service layer
and the console UI.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:12 +04:00
Émile Ré
0b7855243a Remove unused deleteCookieBannerTranslation mutation
The mutation was wired up in the GraphQL schema and resolver
but never called from the console frontend. This removes the
service method, request type, resolver, schema entries, and
two unused error sentinels (ErrTranslationNotFound,
ErrTranslationAlreadyExists).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:11 +04:00
Émile Ré
165b9ad9d3 Add slug to cookie categories for stable consent identifiers
The category slug provides a stable, URL-safe key used as the
data-cookie-consent attribute value and consent data key, replacing
the fragile category name. This prevents breakage when categories
are renamed.

- Add slug column with unique-per-banner constraint and backfill migration
- Add Slug validator (lowercase alphanumeric + hyphens)
- Propagate slug through GraphQL schema, service layer, and snapshot
- Update console UI with slug field in create/edit forms
- Switch cookie-banner widget to use slug as consent data keys

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:10 +04:00
Émile Ré
de47fb0702 Add cookie banner i18n service logic
Seed default English UI strings on banner creation, include
translations in version snapshots, and resolve language at
config-serving time. Add translation CRUD methods and the
language-aware buildBannerConfig helper. Extract default
categories and UI strings into defaults.go.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:08 +04:00
Émile Ré
29c0d55e75 Create a db table for cookies for easiest management
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-21 14:18:32 +04:00
Émile Ré
98487953b9 Fix review
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-21 11:40:23 +04:00
Émile Ré
653b43fc81 Add moveCookieToCategory mutation
Moving a cookie between categories previously required two sequential
updateCookieCategory mutations, which was not atomic and could leave
data in an inconsistent state if the second call failed. This adds a
dedicated moveCookieToCategory mutation that performs both updates in
a single transaction.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-21 11:40:22 +04:00
Émile Ré
7cd8c516b9 Add uncategorised cookie category
Replace the `required` boolean column on cookie_categories with a `kind`
enum (NORMAL, NECESSARY, UNCATEGORISED). The Necessary category remains
undeletable and always-on for consent; the new Uncategorised category is
also undeletable but users can opt out of it.

When a category is deleted, its cookies are merged into the Uncategorised
category (lazy-created for legacy banners that don't have one yet).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-21 11:40:21 +04:00
Émile Ré
30a86a91f1 Add cookie banner public API endpoints
Implement config, consent retrieval, and consent recording
endpoints for the JS SDK. IP addresses are anonymized (last
octet zeroed for IPv4, /48 mask for IPv6) before storage.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:00 +04:00
Émile Ré
d05c3591d3 Handle cookie banner origin validation + unicity
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:20:59 +04:00
Émile Ré
8ba3034828 Add version detection and draft provisioning on publish
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-13 14:52:21 +04:00
Émile Ré
88315f51e1 Add cookie banner versioning with JSONB snapshots
Introduce append-only cookie_banner_versions table with a JSONB
snapshot of consent-relevant configuration (privacy policy URL,
consent mode, expiry, categories and their cookies). Each version
has its own state (DRAFT/PUBLISHED) separate from the banner
lifecycle.

Replace the banner state enum (DRAFT/PUBLISHED/DISABLED) with a
simpler ACTIVE/INACTIVE toggle. Link consent records to the
specific published version the visitor accepted.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-13 14:52:20 +04:00
Émile Ré
2cb58d0e32 Fix lint
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-13 14:50:42 +04:00
Émile Ré
992ab642ea Add cookiebanner client
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-13 14:50:42 +04:00