From 4d91925fadba7f79ab8143c209cbe6836e7cbde5 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 7 Nov 2025 00:01:52 +0800 Subject: [PATCH] feat: add design persistence functionality with Auth0 and Supabase integration - Implemented `useDesignPersistence` composable for managing design records. - Enhanced `useSlipmatDesigner` to support loading designs from JSON. - Created global authentication middleware for route protection. - Added Supabase client plugin for database interactions. - Developed API endpoints for fetching, saving, and retrieving designs. - Introduced utility functions for Auth0 token verification and Supabase client retrieval. - Updated Nuxt configuration to include Auth0 and Supabase environment variables. - Added necessary dependencies for Auth0 and Supabase. - Enhanced TypeScript configuration for improved type support. --- .env.example | 14 ++ README.md | 48 +++- app/components/designer/DesignerPreview.vue | 37 +++ app/pages/auth/callback.vue | 35 +++ app/pages/index.vue | 244 +++++++++++++++++++- composables/useDesignPersistence.ts | 153 ++++++++++++ composables/useSlipmatDesigner.ts | 23 ++ middleware/auth.global.ts | 44 ++++ middleware/auth.ts | 44 ++++ nuxt.config.ts | 24 ++ package-lock.json | 193 +++++++++++++++- package.json | 7 + plugins/auth0.client.ts | 48 ++++ plugins/supabase.client.ts | 27 +++ server/api/designs/[id].get.ts | 47 ++++ server/api/designs/index.get.ts | 39 ++++ server/api/designs/index.post.ts | 115 +++++++++ server/utils/auth0.ts | 82 +++++++ server/utils/supabase.ts | 34 +++ tsconfig.json | 3 + 20 files changed, 1242 insertions(+), 19 deletions(-) create mode 100644 .env.example create mode 100644 app/pages/auth/callback.vue create mode 100644 composables/useDesignPersistence.ts create mode 100644 middleware/auth.global.ts create mode 100644 middleware/auth.ts create mode 100644 plugins/auth0.client.ts create mode 100644 plugins/supabase.client.ts create mode 100644 server/api/designs/[id].get.ts create mode 100644 server/api/designs/index.get.ts create mode 100644 server/api/designs/index.post.ts create mode 100644 server/utils/auth0.ts create mode 100644 server/utils/supabase.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c9bacc8 --- /dev/null +++ b/.env.example @@ -0,0 +1,14 @@ +# Auth0 configuration +AUTH0_DOMAIN= +AUTH0_CLIENT_ID= +AUTH0_CLIENT_SECRET= +AUTH0_AUDIENCE= +AUTH0_SCOPE=openid profile email +AUTH0_BASE_URL=http://localhost:3000 +AUTH0_REDIRECT_URI=http://localhost:3000/auth/callback + +# Supabase configuration +SUPABASE_URL= +SUPABASE_ANON_KEY= +SUPABASE_SERVICE_ROLE_KEY= +SUPABASE_STORAGE_BUCKET=designs diff --git a/README.md b/README.md index 78ff831..d890534 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,55 @@ Nuxt 4 single-page experience for creating custom slipmat artwork. Users pick a - Template presets for popular vinyl diameters with bleed & safe-zone guides - Fabric.js-powered editor: drag, scale, rotate, and stack elements inside a clipped circular canvas - Tools for adding text, circles, rectangles, and uploading artwork -- Live preview card with instant web-resolution snapshot +- Live preview card with instant web-resolution snapshot and turntable mockup - One-click export that produces both preview and print PNGs and offers direct downloads +- Auth0-protected workspace with Supabase-backed “Save to Library” persistence ## 🚀 Quick Start ```bash +cp .env.example .env # set Auth0 + Supabase credentials npm install npm run dev ``` -Visit [http://localhost:3000](http://localhost:3000) to start designing. +Visit [http://localhost:3000](http://localhost:3000) to start designing. Authentication is required for every route except the Auth0 callback. + +### Auth0 & Supabase configuration + +1. **Auth0 application** + - Create a SPA application and note the domain, client ID, and client secret. + - Add `http://localhost:3000` to the allowed callback, logout, and web origins. + - If you plan to call custom APIs, configure an audience and scope (defaults to `openid profile email`). + +2. **Supabase project** + - Create a storage bucket named `designs` (or change `SUPABASE_STORAGE_BUCKET`). + - Create a Postgres table for persisted projects: + + ```sql + create table public.designs ( + id uuid primary key default gen_random_uuid(), + user_id text not null, + name text not null, + template_id text not null, + preview_path text not null, + preview_url text, + design_json jsonb not null, + notes text, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() + ); + + create index designs_user_id_updated_at_idx + on public.designs (user_id, updated_at desc); + ``` + + - Grant read/write access to the AUTH0 users via Row Level Security (example policy: `user_id = auth.jwt()->>'sub'`). + - Generate an anon key and service role key; place them in `.env` along with the project URL. + +3. **Environment** + - Populate `.env` using `.env.example` as a guide. + - Restart the dev server after changes. ## 🛠️ Production Builds @@ -37,17 +75,19 @@ Nuxt outputs the server bundle into `.output/`. You can serve it with `node .out - _Web preview_: 1024×1024 PNG suitable for the storefront and checkout review. - _Print-ready PNG_: Exact template resolution (e.g. 3600×3600 for a 12" slipmat at 300 DPI) for production. -High-res exports remain client-side (no upload yet). Wire the `exportDesign` / `productionBlob` values into your backend to submit orders. +Saving a project now serializes the Fabric.js canvas, uploads the preview PNG to Supabase Storage, and stores metadata within the `designs` table for quick retrieval. ## 📦 Tech Stack - [Nuxt 4](https://nuxt.com/) + Vite - [Fabric.js 6](http://fabricjs.com/) for canvas editing - Tailwind CSS (via `@tailwindcss/vite`) for styling utilities +- [Auth0 Vue SDK](https://auth0.com/docs/libraries/auth0-vue) for authentication +- [Supabase](https://supabase.com/) (Postgres + Storage) for persistence ## 🧭 Next Ideas -- Persist projects (auth + cloud storage) +- Project version history and “duplicate design” shortcuts - CMYK color profile previews & bleed handling - 3D platter preview using Three.js - Admin dashboard for incoming print jobs diff --git a/app/components/designer/DesignerPreview.vue b/app/components/designer/DesignerPreview.vue index 4f614a1..bf174dd 100644 --- a/app/components/designer/DesignerPreview.vue +++ b/app/components/designer/DesignerPreview.vue @@ -4,12 +4,17 @@ const props = defineProps<{ templateLabel: string; productionPixels: number; isExporting: boolean; + projectName: string; + isSaving: boolean; + canSave: boolean; }>(); const emit = defineEmits<{ (e: "download-preview"): void; (e: "download-production"): void; (e: "export"): void; + (e: "update:projectName", value: string): void; + (e: "save"): void; }>(); const viewMode = ref<"flat" | "turntable">("flat"); @@ -23,6 +28,14 @@ const handleSelectView = (mode: "flat" | "turntable") => { const handleExport = () => emit("export"); const handleDownloadPreview = () => emit("download-preview"); const handleDownloadProduction = () => emit("download-production"); +const handleProjectNameInput = (event: Event) => { + const target = event.target as HTMLInputElement; + emit("update:projectName", target.value); +}; +const handleSave = () => emit("save"); +const isSaveDisabled = computed( + () => !props.previewUrl || props.isSaving || !props.canSave +);