Techfluenced logoTechfluenced
← Dream Tracker

Field notes

How it's made

A private journal that turns what you remember of a dream into a watercolor painting. Here's the stack underneath it, and the six bugs that stood between working code and a working demo.

Claude CodeAuth0VercelSupabaseOpenAI gpt-image-1Next.js 16 · App RouterTypeScriptTailwind CSS v4

Components

Login

Email and password via Auth0, so a dream journal is only ever visible to the person who wrote it.

Profile

An Auth0 Progressive Profiling Action asks new users for their name once, after their first login.

Storage

Entries live in a Supabase Postgres table, scoped to the logged-in user on every read and write.

Illustration

Each entry's text is sent to OpenAI's gpt-image-1, which paints it as a watercolor and the result is saved to Supabase Storage.

Bugs & fixes

In the order they were found.

01

Image upload rejected by Supabase

Fixed
Invalid key: auth0|6a99f8492d4c5cfff4bc5ce5/…png
Cause
Auth0 user IDs contain a “|”, which Supabase Storage won't allow in an object key.
Fix
Sanitize the user ID to auth0_6a99f849… before building the storage path.
02

New table invisible to the API

Fixed
PGRST205 — Could not find the table 'public.dream_entries' in the schema cache
Cause
PostgREST caches the schema and doesn't always notice a table created moments earlier via the SQL editor.
Fix
Reload the cache — the dashboard's “Reload schema cache” button, or notify pgrst, 'reload schema';
03

Row Level Security was off

Fixed
Cause
Supabase's own project-wide anon key — unused by this app, but issued by default — could read or write every dream in the table if it were ever exposed.
Fix
Enabled RLS with zero policies (default-deny for anon/authenticated). The app's own service_role key bypasses RLS by design, so nothing else changed.
04

One login shouldn't be able to break every page

Fixed
Cause
Next.js 16 renamed middleware.ts to proxy.ts, and Auth0's request handler ran on every route by default — so a misconfigured Auth0 client could take the whole site down, not just this demo.
Fix
Migrated to proxy.ts and narrowed its route matcher to just this demo's own paths.
05

The name claim that wasn't there

Fixed
Cause
The Progressive Profiling Action correctly wrote the user's name and set it as a custom ID token claim — confirmed deployed, confirmed running — yet the session never had it. Turned out @auth0/nextjs-auth0 silently strips any claim outside a fixed default allowlist before saving the session, unless told otherwise.
Fix
Added a beforeSessionSaved hook that keeps the SDK's default filtering and explicitly re-adds this one custom claim.
06

Editing a dream left the old painting

Fixed
Cause
Each entry's image lives at a fixed path — same user, same entry, same file — so a regenerated image reused the exact same URL. Browsers cache by URL, so the stale picture kept being served.
Fix
Append ?v=<timestamp> to the URL on every regeneration, so a new painting is never mistaken for the old one.