Skip to content

Feature/dpp theme refactor#126

Open
rafmevis wants to merge 16 commits intomainfrom
feature/dpp-theme-refactor
Open

Feature/dpp theme refactor#126
rafmevis wants to merge 16 commits intomainfrom
feature/dpp-theme-refactor

Conversation

@rafmevis
Copy link
Collaborator

@rafmevis rafmevis commented Mar 9, 2026

Summary by cubic

Refactored DPP theming into a single Passport JSON per brand and wired it through the DB, TRPC, and the editor. Added a server-side Google Maps Static API proxy, moved the app shell to system fonts, and shipped small UX improvements.

  • Refactors

    • Replaced legacy theme styles/config with a single passport JSON across DB, brand.theme.get/update, and the editor; save action now builds a Passport stylesheet and normalizes image paths before upload.
    • Switched to Passport types and buildPassportStylesheet from @v1/dpp-components; kept Google Fonts URL generation.
    • Resolved Passport section images and normalized storage paths; renamed image util to resolvePassportImageUrls and added normalizePassportImagePathsForStorage.
    • Added /api/google-maps/static proxy and moved the app shell to a system font stack (removed geist).
    • Behavior updates: require a verified custom domain for GS1 QR export and auto-publish variants after save when the product is already published.
  • Migration

    • Apply Supabase migration 20260308104741_aberrant_ares (adds brand_theme.passport, drops theme_styles and theme_config).
    • Backfill brand_theme.passport for existing brands before enabling the new editor.
    • Ensure buckets dpp-assets and dpp-themes exist and that normalized image URLs resolve.

Written for commit 02bad8d. Summary will update on new commits.

@supabase
Copy link

supabase bot commented Mar 9, 2026

Updates to Preview Branch (feature/dpp-theme-refactor) ↗︎

Deployments Status Updated
Database Tue, 10 Mar 2026 21:02:05 UTC
Services Tue, 10 Mar 2026 21:02:05 UTC
APIs Tue, 10 Mar 2026 21:02:05 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Tue, 10 Mar 2026 21:02:13 UTC
Migrations Tue, 10 Mar 2026 21:02:16 UTC
Seeding Tue, 10 Mar 2026 21:02:17 UTC
Edge Functions Tue, 10 Mar 2026 21:02:18 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@greptile-apps
Copy link

greptile-apps bot commented Mar 9, 2026

Greptile Summary

This PR is a significant refactor of the DPP (Digital Product Passport) theme system, consolidating the previous dual-field approach (themeStyles + themeConfig) into a single unified Passport JSON document (v2) stored per brand. The change touches the database schema, API routes, the design editor context, the dpp-components package, and the DPP app.

Key changes:

  • New Passport type — a versioned document containing tokens (colors, typography, custom fonts), fixed layout components (header, productImage, modal, footer), and ordered sidebar/canvas section arrays, each with their own styles and content.
  • Simplified CSS generationbuildThemeStylesheet replaced by buildPassportStylesheet; the CSS layer now only emits design token variables and @font-face rules; component styling moves to inline styles via resolveStyles.
  • Single save path — the design editor's saveDrafts now calls saveThemeAction with the full passport instead of two separate saves for styles and config.
  • Database migration (20260308104741_aberrant_ares.sql) — adds passport column, drops theme_styles and theme_config.

Issues found:

  • The migration drops theme_styles and theme_config without any UPDATE statement to migrate existing brand theme data into the new passport column — this will silently wipe all existing theme customisations for every brand in the database.
  • Fifteen pre-existing migration snapshot files under apps/api/supabase/migrations/meta/ were reformatted (JSON array style), which conflicts with the convention of never editing existing migration files.
  • saveThemeAction persists the full passport (including section image URLs) directly via Supabase without calling normalizePassportImagePathsForStorage, unlike the tRPC brand.theme.update route which does normalise paths. This inconsistency means image URLs saved via the design editor are stored as full public URLs rather than portable storage paths.

Confidence Score: 2/5

  • Not safe to merge — the migration will irreversibly destroy all existing brand theme data.
  • The destructive migration (drop without data migration) is a production data-loss risk. The refactor itself is well-structured, but this one issue is a blocker.
  • apps/api/supabase/migrations/20260308104741_aberrant_ares.sql requires an UPDATE step before DROP. apps/app/src/actions/design/save-theme-action.ts needs image path normalisation.

Important Files Changed

Filename Overview
apps/api/supabase/migrations/20260308104741_aberrant_ares.sql Destructive migration that drops theme_styles and theme_config columns and adds passport, with no data migration step — all existing brand theme data will be wiped.
apps/api/supabase/migrations/meta/20260122175801_snapshot.json Existing migration snapshot file was reformatted (JSON array style), violating the custom instruction not to edit existing migration files in apps/api/supabase/migrations/.
apps/app/src/actions/design/save-theme-action.ts Now saves the full passport (including content/images) directly to DB via Supabase without calling normalizePassportImagePathsForStorage — image URLs are stored as full public URLs rather than storage paths.
apps/api/src/utils/theme-config-images.ts Refactored to resolve/normalize image paths in the new passport structure; covers header.logoUrl and section images (banner, imageCards, textImage) across sidebar/canvas zones. Logic is correct and idempotent.
apps/api/src/trpc/routers/brand/theme.ts Cleanly migrated from themeStyles+themeConfig dual-field approach to a single passport field; correctly normalizes image paths before persisting via updatePassport.
packages/db/src/schema/brands/brand-theme.ts Schema correctly updated to replace themeStyles + themeConfig with a single passport JSONB column; consistent with the generated migration.
packages/db/src/queries/brand/theme.ts Query layer correctly updated; getBrandTheme now selects passport, and updateBrandThemeConfig was renamed to updatePassport accepting the new shape.
packages/dpp-components/src/types/passport.ts New Passport type definition: a well-structured v2 document with tokens, header, productImage, modal, footer, sidebar[], and canvas[]; clear and complete.
packages/dpp-components/src/lib/css-generator.ts Greatly simplified — now generates only design token CSS variables (colors + typography) and @font-face rules. Component-level styling moved to inline styles via resolveStyles.
packages/dpp-components/src/lib/defaults/passport.ts Default passport definition assembles section defaults from the registry; clean and concise approach using structuredClone for each section.
apps/app/src/contexts/design-editor-provider.tsx Refactored to a unified passportDraft state; saveDrafts now calls saveThemeAction with the full passport. ActiveTarget type added for precise component targeting.

Sequence Diagram

sequenceDiagram
    participant Client as Design Editor (Client)
    participant SA as saveThemeAction (Server Action)
    participant TR as brand.theme.update (tRPC)
    participant DB as brand_theme (DB)
    participant API as brand.theme.get (tRPC)

    Note over Client,DB: Save flow (saveDrafts)
    Client->>SA: passport (full public image URLs)
    SA->>SA: buildPassportStylesheet(tokens)
    SA->>SA: upload stylesheet to dpp-themes bucket
    SA->>DB: UPDATE brand_theme SET passport = passport (full URLs stored — NOT normalised)

    Note over Client,DB: Save via tRPC update (e.g. admin app)
    Client->>TR: passport (may contain full URLs or storage paths)
    TR->>TR: normalizePassportImagePathsForStorage(passport)
    TR->>DB: UPDATE brand_theme SET passport = normalised passport (storage paths stored)

    Note over Client,DB: Read flow
    Client->>API: brand.theme.get
    API->>DB: SELECT passport, googleFontsUrl, updatedAt
    DB-->>API: passport row
    API->>API: resolvePassportImageUrls(supabase, passport)
    Note right of API: normalizeBucketValue handles both<br/>full URLs and storage paths
    API-->>Client: passport (resolved public URLs)
Loading

Comments Outside Diff (1)

  1. apps/api/supabase/migrations/meta/20260122175801_snapshot.json, line 1 (link)

    Existing migration snapshot files have been modified

    Fifteen pre-existing snapshot files in apps/api/supabase/migrations/meta/ have been reformatted (JSON arrays changed from multi-line to single-line style). The project convention is to never edit existing migration files — the only file that should be added/modified is the new migration and its corresponding snapshot.

    The same pattern appears in all pre-existing snapshots:

    • apps/api/supabase/migrations/meta/20260122175801_snapshot.json
    • apps/api/supabase/migrations/meta/20260122221153_snapshot.json
    • apps/api/supabase/migrations/meta/20260123173930_snapshot.json
    • apps/api/supabase/migrations/meta/20260127160524_snapshot.json
    • apps/api/supabase/migrations/meta/20260220182427_snapshot.json
    • apps/api/supabase/migrations/meta/20260221134703_snapshot.json
    • apps/api/supabase/migrations/meta/20260224173000_snapshot.json
    • apps/api/supabase/migrations/meta/20260225201723_snapshot.json
    • apps/api/supabase/migrations/meta/20260228155219_snapshot.json
    • apps/api/supabase/migrations/meta/20260228170015_snapshot.json
    • apps/api/supabase/migrations/meta/20260228221145_snapshot.json
    • apps/api/supabase/migrations/meta/20260304101925_snapshot.json
    • apps/api/supabase/migrations/meta/20260306101056_snapshot.json
    • apps/api/supabase/migrations/meta/20260306111521_snapshot.json
    • apps/api/supabase/migrations/meta/20260306125055_snapshot.json

    If these were automatically reformatted by the Drizzle toolchain as a side effect of bun db:push, that is worth confirming — otherwise they should be reverted to their original formatting to keep the diff minimal and avoid touching files that should be immutable.

    Rule Used: Never edit existing migration files in apps/api/su... (source)

    Learnt From
    Avelero/avelero#37

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/api/supabase/migrations/meta/20260122175801_snapshot.json
    Line: 1
    
    Comment:
    **Existing migration snapshot files have been modified**
    
    Fifteen pre-existing snapshot files in `apps/api/supabase/migrations/meta/` have been reformatted (JSON arrays changed from multi-line to single-line style). The project convention is to never edit existing migration files — the only file that should be added/modified is the new migration and its corresponding snapshot.
    
    The same pattern appears in all pre-existing snapshots:
    - `apps/api/supabase/migrations/meta/20260122175801_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260122221153_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260123173930_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260127160524_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260220182427_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260221134703_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260224173000_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260225201723_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260228155219_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260228170015_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260228221145_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260304101925_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260306101056_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260306111521_snapshot.json`
    - `apps/api/supabase/migrations/meta/20260306125055_snapshot.json`
    
    If these were automatically reformatted by the Drizzle toolchain as a side effect of `bun db:push`, that is worth confirming — otherwise they should be reverted to their original formatting to keep the diff minimal and avoid touching files that should be immutable.
    
    **Rule Used:** Never edit existing migration files in apps/api/su... ([source](https://app.greptile.com/review/custom-context?memory=0a02f99b-35ab-4bd1-8c3e-cd35f51e90e1))
    
    **Learnt From**
    [Avelero/avelero#37](https://github.com/Avelero/avelero/pull/37)
    
    How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: e4b7455

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 290 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/api/supabase/migrations/20260308104741_aberrant_ares.sql">

<violation number="1" location="apps/api/supabase/migrations/20260308104741_aberrant_ares.sql:2">
P1: This migration drops `theme_styles` without migrating existing data into `passport`, causing irreversible data loss.</violation>
</file>

<file name="apps/app/src/components/forms/passport/variant-form.tsx">

<violation number="1" location="apps/app/src/components/forms/passport/variant-form.tsx:375">
P2: Publishing failures in edit mode are treated as save failures. If publish throws, the catch block shows "Failed to save variant" even though `submit()` already saved the overrides, which is misleading. Handle publish as best-effort (like create mode) and report a partial failure instead of failing the save.</violation>
</file>

<file name="apps/app/src/actions/design/save-theme-action.ts">

<violation number="1" location="apps/app/src/actions/design/save-theme-action.ts:33">
P2: Guard `passport.tokens` before calling `buildPassportStylesheet` (or validate the passport shape). As written, a null/invalid passport will throw when dereferencing `tokens`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

🚀 Preview Deployment Summary

App: https://avelero-4ocuip3va-avelero.vercel.app
API: https://pr-126-avelero-api.fly.dev
Web: https://avelero-website-5afi715l7-avelero.vercel.app
Admin: https://avelero-admin-cebb2b9i6-avelero.vercel.app
DPP: https://avelero-passport-12ju7ppkk-avelero.vercel.app
Jobs: Deployed to Trigger.dev

Preview environments will auto-delete when PR closes.

@github-actions
Copy link

🚀 Preview Deployment Summary

App: https://avelero-3ma5dal6w-avelero.vercel.app
API: https://pr-126-avelero-api.fly.dev
Web: https://avelero-website-ouo63kcra-avelero.vercel.app
Admin: https://avelero-admin-ps6dq7ywv-avelero.vercel.app
DPP: https://avelero-passport-82ogh6g59-avelero.vercel.app
Jobs: Deployed to Trigger.dev

Preview environments will auto-delete when PR closes.

@github-actions
Copy link

🚀 Preview Deployment Summary

App: https://avelero-czecbr9do-avelero.vercel.app
API: https://pr-126-avelero-api.fly.dev
Web: https://avelero-website-llchblh4h-avelero.vercel.app
Admin: https://avelero-admin-3sx7gigrr-avelero.vercel.app
DPP: https://avelero-passport-2h7lkguvu-avelero.vercel.app
Jobs: Deployed to Trigger.dev

Preview environments will auto-delete when PR closes.

@github-actions
Copy link

🚀 Preview Deployment Summary

App: https://avelero-a7voq0zxx-avelero.vercel.app
API: https://pr-126-avelero-api.fly.dev
Web: https://avelero-website-2g66isf1s-avelero.vercel.app
Admin: https://avelero-admin-3fkcvk2rl-avelero.vercel.app
DPP: https://avelero-passport-e73cvs9yu-avelero.vercel.app
Jobs: Deployed to Trigger.dev

Preview environments will auto-delete when PR closes.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/dpp-components/src/components/modals/impact-modal.tsx">

<violation number="1" location="packages/dpp-components/src/components/modals/impact-modal.tsx:352">
P1: Synchronize `activeTab` with `metrics` updates; otherwise the modal can show no comparisons after async metric changes (e.g., water-only data loaded after initial render).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}
}

const [activeTab, setActiveTab] = useState<MetricCategory>(
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Synchronize activeTab with metrics updates; otherwise the modal can show no comparisons after async metric changes (e.g., water-only data loaded after initial render).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/dpp-components/src/components/modals/impact-modal.tsx, line 352:

<comment>Synchronize `activeTab` with `metrics` updates; otherwise the modal can show no comparisons after async metric changes (e.g., water-only data loaded after initial render).</comment>

<file context>
@@ -1,65 +1,376 @@
+    }
+  }
+
+  const [activeTab, setActiveTab] = useState<MetricCategory>(
+    availableCategories[0]?.category ?? "carbon",
+  );
</file context>
Fix with Cubic

@github-actions
Copy link

🚀 Preview Deployment Summary

App: https://avelero-e6bp74euj-avelero.vercel.app
API: https://pr-126-avelero-api.fly.dev
Web: https://avelero-website-o1j104m2y-avelero.vercel.app
Admin: https://avelero-admin-gm5lyovbl-avelero.vercel.app
DPP: https://avelero-passport-ildcn1w4r-avelero.vercel.app
Jobs: Deployed to Trigger.dev

Preview environments will auto-delete when PR closes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant