Loading


Created for Week 4 of Shared Minds at NYU ITP (Fall 2024), Read & Leave (notes.lan.codes) is an ephemeral message-sharing application that measures a note's lifespan not by wall-clock time, but by how many times it is read.
Most web applications persist every database row indefinitely. Read & Leave treats attention as a finite resource:
Unlimited, or 1 through 5 reads), generating a shareable capability URL (https://notes.lan.codes/<uuid>)./${uuid} triggers a force-dynamic Next.js Server Component (getNoteAndUpdate) that queries the Supabase notes table and decrements readTimes on every view.readTimes === 1, the server immediately deletes the row from PostgreSQL (supabase.from('notes').delete().eq('uuid', uuid)) as the final reader views the warning: "This is the last time you can view this note. It will not be available after you close this page." Subsequent requests return 404 Not Found.
Notes are stored in a Supabase PostgreSQL table (notes) keyed by id and uuid, tracking created_at, text, and a nullable readTimes counter (NULL for unlimited views, or an integer countdown).

export const dynamic = 'force-dynamic';
async function getNoteAndUpdate(uuid: string): Promise<Note | null> {
const supabase = createClient();
const { data: note, error } = await supabase
.from('notes')
.select('*')
.eq('uuid', uuid)
.single();
if (error || !note) return null;
if (note.readTimes === 1) {
await supabase.from('notes').delete().eq('uuid', uuid);
} else if (note.readTimes !== null && note.readTimes > 1) {
await supabase
.from('notes')
.update({ readTimes: note.readTimes - 1 })
.eq('uuid', uuid);
}
return note as Note;
}