143 lines
3.5 KiB
Markdown
143 lines
3.5 KiB
Markdown
---
|
|
name: supabase-storage
|
|
description: 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
|
|
|
|
```typescript
|
|
// 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:
|
|
```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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
// 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)
|
|
|
|
```sql
|
|
-- 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)
|