* feat: add YouTube social link to user profiles
- Add youtube_url column to auth_users schema
- Add DB migration for the new column
- Update updateProfile action with YouTube URL validation
- Update getUserProfile and getPublicProfile to include youtubeUrl
- Add YouTube input field to settings page
- Display YouTube icon on public profile pages
* fix: use drizzle-kit generate for youtube_url migration
Replaces manually created migration with proper drizzle-kit generated
migration that includes meta snapshot and journal entry.
---------
Co-authored-by: Anton Pascal <anton-pascal@users.noreply.github.com>
* feat: enhance feedback form with image upload, user/project context, and scene graph
- Add invisible drag-and-drop zone that reveals on hover+drag with dashed border overlay
- Multi-image upload (max 5, max 5MB each) to Supabase Storage feedback-images bucket
- Subtle attach button + thumbnail previews with remove on hover
- Auto-capture authenticated user email/name from Better Auth session
- Pass projectId from editor context
- Snapshot scene graph (nodes + rootNodeIds) on submit
- DB migration adds user_email, user_name, project_id, images (jsonb), scene_graph (jsonb) columns
- Storage bucket + RLS policies for public read / service role write
* refactor: use existing user_id FK instead of denormalized email/name columns
Removed user_email and user_name — the user_id already links to the users table.
Simpler schema, no data duplication.
* fix: guard against undefined in removeImage
* refactor: direct Supabase Storage upload via signed URLs
Bypass Vercel's 4.5MB serverless body-size limit by uploading images
directly from the client to Supabase Storage.
- New createImageUploadUrls server action generates signed upload URLs
- Client PUTs files directly to Supabase (no bytes through Vercel)
- submitFeedback now receives only image paths, not FormData with files
- No migration changes needed (existing RLS policies support signed URLs)
* fix: remove relative class that broke dialog centering
twMerge was replacing the Dialog's fixed positioning with relative,
pushing the dialog to the bottom of the viewport.
---------
Co-authored-by: Anton Pascal <anton-pascal@users.noreply.github.com>
- Removed 9 stale branch-specific env vars on Vercel that were locked
to the deleted feat/refactor-supabase-setup branch
- Added runtime warning when a preview deployment detects it's using
the production Supabase instance (branching skipped/misconfigured)
The root issue: Supabase branching only creates preview branches for
PRs that include migration changes. PRs without migrations get SKIPPED
and fall through to the generic env vars, which include 'preview' in
their targets and point to production Supabase.
To fully fix: configure Supabase branching to always create preview
branches, or remove 'preview' from generic Supabase env var targets
on Vercel (requires branching to be working first).
Co-authored-by: Anton Pascal <anton-pascal@users.noreply.github.com>
* fix: reduce autosave function invocation spam (25x anomaly)
Root cause: useProjectScene() was mounted in BOTH editor/index.tsx
AND project-dropdown.tsx, creating duplicate zustand subscriptions
that each independently triggered saveProjectModel() server actions.
Combined with a 2-second debounce and the fact that each server
action also calls getSession() (another function invocation), active
editing was generating ~120+ invocations/minute.
Changes:
- Remove duplicate useProjectScene() from project-dropdown.tsx
- Increase autosave debounce from 2s to 10s
- Skip auto-save on initial scene load from server (was saving the
scene right back after loading it)
- Add pending-save coalescing: changes during in-flight saves get
batched into one follow-up save instead of queuing concurrently
* fix: flush unsaved scene to cloud on page exit / unmount
Adds two safety nets so the 10s debounce doesn't lose data:
- beforeunload listener: fires saveProjectModel() when the user
closes the tab or navigates away externally
- cleanup flush on unmount: fires when navigating within the SPA
(e.g. switching projects, going to settings)
Both are fire-and-forget — if the browser kills the request,
localStorage still has the data and will sync on next load.
* style: fix biome import ordering in project-dropdown
---------
Co-authored-by: Anton Pascal <anton-pascal@users.noreply.github.com>
- /terms — Terms of Service for editor + pascal.app platform
- /privacy — Privacy Policy (data collection, third parties, user rights)
- Email notification toggle in Settings (new column + migration)
- Sign-in consent text linking to terms/privacy
- Effective date: February 20, 2026
Co-authored-by: Anton Pascal <anton-pascal@users.noreply.github.com>
- Add show_scans_public and show_guides_public columns to projects table
- Add visibility toggles to editor sidebar settings panel (auto-save)
- Add visibility toggles to project settings dialog (auto-save)
- Propagate settings to community viewer (hide scans/guides for non-owners)
- Add updateProjectVisibility server action
- Fix username onboarding dialog stuck after DB reset (validate update affected rows)
- Add error handling to UsernameGate for stale sessions
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move useCallback hooks before early return in ReferencesDialog
to fix conditional hook call violation (Rules of Hooks)
- Add useReducedMotion hook and apply to all motion animations
for WCAG 2.3.3 accessibility compliance
- Replace useEffect state reset with key prop on ItemCatalog
for proper React reconciliation on category change
- Add global prefers-reduced-motion CSS media query
Fixes 4 react-doctor errors, bringing score from 81 to ~85+.
Validates all required env vars at runtime with zod schemas.
Skips validation during build via SKIP_ENV_VALIDATION flag.
Replaces scattered process.env access with typed env imports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Turbo was stripping env vars during build on Vercel. Added all required
vars to turbo.json build task. Also hardened Supabase and BetterAuth
init with fallback placeholders for build-time safety.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses Next.js instrumentation.ts to ensure the Supabase "avatars"
bucket exists on first boot — no manual setup needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Avatar upload to Supabase Storage with pencil overlay in settings
- Show username initials as avatar fallback (instead of name initials)
- Round avatar in navbar (rounded-full with natural shadow)
- Connected Accounts section in settings showing Google status
- Connect Google directly from settings without signing out
- Add Vercel Analytics, Speed Insights, and Toolbar
- Update page title to "Pascal Editor"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move account linking config out of Google conditional so it's always active
- Trust both 'google' and 'email' providers for automatic account linking
- Add lastLoginMethod plugin to track how users last signed in
- Show "Last signed in with Google/email link" hint in sign-in dialog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Defer database client creation until first use via Proxy so Next.js
builds succeed without POSTGRES_URL and SUPABASE_URL env vars present.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Google OAuth sign-in alongside magic link authentication
- Username onboarding: require username selection after first sign-in
- Public profile pages at /u/[username] with social links (GitHub, X)
- Settings page for managing username and social links
- Viewer header: unified floating card with project name, @username, breadcrumb
- Guest CTA on viewer page prompting sign-in
- Show owner avatar + username on community project cards
- Redesigned project cards (larger preview, avatar + stats row below)
- Consistent navbar across hub and profile pages with GitHub link
- Footer with links to GitHub repo and npm packages
- Borderless design with natural shadows throughout
- Apple corner smoothing (squircle) progressive enhancement
- cursor:pointer globally on buttons and links
- DB migrations: username, github_url, x_url columns on auth_users
- Root-level db:generate/migrate/push/studio scripts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previous runs had NODE_AUTH_TOKEN set to a garbage placeholder
because we removed the env var from publish steps. Now properly
passing secrets.NPM_TOKEN as NODE_AUTH_TOKEN.