FluentStack

Persisting User Data

Mode tersedia: dark, light, paper
MasukDaftar
Advanced · Level 11: Production Next.jsAdvanced70 menitBahasa Indonesia

Persisting User Data

Membaca dan menyimpan data user-owned melalui flow async yang mengambil identity server-side, membatasi payload, serta memberi state sukses atau error.

StatusMemuat progres
ProgresMemuat...

...

Memuat progres

Menyiapkan langkah berikutnya

Tujuan belajar

  • Membaca urutan identity check, payload validation, query, dan UI state
  • Menentukan user_id dari auth claims, bukan form payload
  • Memahami kapan upsert dapat dipakai untuk satu data per user
  • Menampilkan success/error state yang tidak menyembunyikan kegagalan operasi
Next.jsSupabasePersistenceServer ActionsAsync UI

Isi lesson

5 blok
  1. 1.
    Persistensi adalah flow, bukan satu tombol SaveBelum selesaiWajib
  2. 2.
    Server Action menyimpan catatan user saat iniBelum selesaiWajib
  3. 3.
    Coding practiceBelum selesaiWajib
  4. 4.
    Checklist Local Next.js AppBelum selesaiWajib
  5. 5.
    RingkasanBelum selesaiWajib

Persistensi adalah flow, bukan satu tombol Save

Wajib

Untuk menyimpan data milik user, urutannya penting: ambil input, validasi bentuk dan batasnya, verifikasi identity di server, susun payload yang menyertakan user_id dari claims, jalankan query, lalu kembalikan state sukses atau error yang dapat dipahami UI. Jangan menerima user_id tersembunyi dari form sebagai sumber kebenaran.

Contoh sederhana adalah satu learning note per user. Jika tabel memiliki unique constraint untuk user_id, upsert dapat membuat row bila belum ada atau memperbaruinya bila sudah ada. Ini bukan alasan untuk mengirim seluruh object form ke database. Pilih kolom yang memang boleh diubah dan biarkan RLS menegakkan ownership sebagai lapisan tambahan.

Bagian ini memengaruhi progres lesson.

Server Action menyimpan catatan user saat ini

Wajib
tsx
"use server";

import { createClient } from "@/lib/supabase/server";

export async function saveLearningNote(formData: FormData) {
  const content = String(formData.get("content") ?? "").trim();

  if (content.length < 1 || content.length > 500) {
    return { status: "error", message: "Catatan harus berisi 1-500 karakter." };
  }

  const supabase = await createClient();
  const { data: claimsData, error: claimsError } =
    await supabase.auth.getClaims();
  const userId = claimsData?.claims.sub;

  if (claimsError || !userId) {
    return { status: "error", message: "Masuk kembali sebelum menyimpan catatan." };
  }

  const { error } = await supabase
    .from("learning_notes")
    .upsert({ user_id: userId, content }, { onConflict: "user_id" });

  if (error) {
    return { status: "error", message: "Catatan belum bisa disimpan." };
  }

  return { status: "success", message: "Catatan tersimpan." };
}

Action memvalidasi content sebelum query, lalu menentukan user_id dari claims server-side. upsert hanya cocok bila onConflict mengarah ke unique constraint yang memang ada pada tabel. Pesan yang kembali ke UI tidak membeberkan detail database. Dalam project nyata, tampilkan pending state saat action berjalan dan simpan detail error aman untuk debugging server-side.

Bagian ini memengaruhi progres lesson.

Coding practice

WajibDibuka di workspace khusus

Plan user data persistence flow

Susun langkah persistence untuk learning note mulai dari validasi input hingga state sukses atau error tanpa mengambil user_id dari form browser.

Tujuan awal: Fokus di tab TSX.

Practice ini dibuka di workspace khusus. Buka practice untuk memakai editor, preview, dan cek otomatis.

Tombol selesai aktif setelah semua validasi wajib lolos.

5 cek otomatis5 checklist
Belum selesaiBuka practice

Checklist Local Next.js App

Wajib

Saat kamu mulai mengintegrasikan Supabase di project lokal, cek secara manual:

  • Browser tidak menerima service role key atau session secret.
  • Server Action atau Route Handler mengambil identity dari auth context yang diverifikasi.
  • Tabel user-owned memiliki RLS dan policy untuk operasi yang benar-benar dibutuhkan.
  • Submit menampilkan pending, success, dan error state yang jelas.
  • Coba akses data dengan dua akun uji bila setup sudah tersedia.

FluentStack tidak dapat mengakses project atau dashboard Supabase kamu. Jangan menandai checklist ini sebagai bukti integrasi sebelum kamu benar-benar menguji app lokal.

Bagian ini memengaruhi progres lesson.

Ringkasan

Wajib
  • Flow persistence mengambil input, memvalidasi, memverifikasi identity, lalu menjalankan query dengan payload terbatas.
  • user_id pada row user-owned berasal dari claims server-side.
  • upsert memerlukan unique constraint yang sesuai dengan onConflict.
  • UI perlu state pending, success, dan error; local integration tetap perlu diuji sendiri.
  • Berikutnya, kamu akan memisahkan auth user dari data profile aplikasi.

Bagian ini memengaruhi progres lesson.

Langkah berikutnya

Selesaikan bagian penting lesson ini

Lanjutkan blok wajib berikutnya: Persistensi adalah flow, bukan satu tombol Save.