Files
lumina-nextjs-template/.claude/skills/supabase-storage/SKILL.md
2025-12-23 04:19:57 +01:00

3.5 KiB

name, description
name description
supabase-storage Supabase Storage fuer Datei-Upload und Download. Nutze diesen Skill fuer Bucket-Erstellung, File Upload, Download, Signed URLs und Storage Policies. Aktiviert bei Begriffen wie "Upload", "Download", "Datei", "File", "Bild hochladen", "Storage", "Bucket", "S3", "Bilder", "Avatar", "Dokumente".

Supabase Storage Skill

Dieser Skill hilft bei allen Storage-Operationen mit Supabase.

Bucket erstellen

// Server-side mit Admin Client
const { data, error } = await supabaseAdmin.storage.createBucket('avatars', {
  public: true,
  fileSizeLimit: 1024 * 1024 * 2, // 2MB
  allowedMimeTypes: ['image/png', 'image/jpeg', 'image/webp']
});

Oder via SQL:

INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
VALUES (
  'avatars',
  'avatars',
  true,
  2097152,
  ARRAY['image/png', 'image/jpeg', 'image/webp']
);

File Upload

async function uploadFile(file: File, bucket: string, path: string) {
  const { data, error } = await supabase.storage
    .from(bucket)
    .upload(path, file, {
      cacheControl: '3600',
      upsert: false // true = ueberschreiben erlaubt
    });

  if (error) throw error;

  // Public URL holen
  const { data: urlData } = supabase.storage
    .from(bucket)
    .getPublicUrl(path);

  return urlData.publicUrl;
}

File Download

// Als Blob
const { data, error } = await supabase.storage
  .from('documents')
  .download('path/to/file.pdf');

// Public URL (oeffentliche Buckets)
const { data } = supabase.storage
  .from('avatars')
  .getPublicUrl('user123/avatar.jpg');

// Signed URL (private Buckets, zeitlich begrenzt)
const { data, error } = await supabase.storage
  .from('private-docs')
  .createSignedUrl('secret.pdf', 3600); // 1 Stunde

File Management

// Liste Dateien
const { data, error } = await supabase.storage
  .from('bucket')
  .list('folder/', {
    limit: 100,
    sortBy: { column: 'created_at', order: 'desc' }
  });

// Loeschen
const { error } = await supabase.storage
  .from('bucket')
  .remove(['path/file1.jpg', 'path/file2.jpg']);

// Verschieben
const { error } = await supabase.storage
  .from('bucket')
  .move('old/path.jpg', 'new/path.jpg');

Storage Policies (RLS)

-- User koennen eigene Dateien hochladen
CREATE POLICY "Users upload own files"
ON storage.objects FOR INSERT
TO authenticated
WITH CHECK (
  bucket_id = 'user-files' AND
  (storage.foldername(name))[1] = auth.uid()::text
);

-- User koennen eigene Dateien lesen
CREATE POLICY "Users read own files"
ON storage.objects FOR SELECT
TO authenticated
USING (
  bucket_id = 'user-files' AND
  (storage.foldername(name))[1] = auth.uid()::text
);

-- User koennen eigene Dateien loeschen
CREATE POLICY "Users delete own files"
ON storage.objects FOR DELETE
TO authenticated
USING (
  bucket_id = 'user-files' AND
  (storage.foldername(name))[1] = auth.uid()::text
);

-- Oeffentlicher Lesezugriff
CREATE POLICY "Public read"
ON storage.objects FOR SELECT
USING (bucket_id = 'public-assets');

React Upload Component

Siehe templates/FileUpload.tsx fuer eine fertige Component.

Best Practices

  1. Ordnerstruktur: {user_id}/{type}/{filename}
  2. File Size Limits setzen
  3. MIME Types einschraenken
  4. Signed URLs fuer private Dateien
  5. Unique Filenames (z.B. mit Timestamp)