feat: operator docs, Gitea push guide, and creatives API scaffold

Unblock ops with marketing@ provisioning steps and start multi-tenant creatives against Supabase RLS.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-21 12:12:57 +02:00
parent 2df3fe6983
commit 6e3d561f4b
5 changed files with 203 additions and 2 deletions

View File

@@ -0,0 +1,66 @@
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/lib/supabase/server';
export async function GET() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { data, error } = await supabase
.from('creatives')
.select('id,title,status,mime_type,bytes,created_at,updated_at')
.order('updated_at', { ascending: false });
if (error) {
// Table may not exist yet — soft message for pre-migration
return NextResponse.json(
{ creatives: [], warning: error.message },
{ status: 200 }
);
}
return NextResponse.json({ creatives: data ?? [] });
}
export async function POST(req: NextRequest) {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const tenantId =
user.app_metadata?.tenant_id || user.user_metadata?.tenant_id || null;
if (!tenantId) {
return NextResponse.json({ error: 'Usuario sin tenant_id' }, { status: 403 });
}
const body = await req.json().catch(() => ({}));
const title = typeof body.title === 'string' ? body.title.trim() : '';
if (!title) {
return NextResponse.json({ error: 'title requerido' }, { status: 400 });
}
const { data, error } = await supabase
.from('creatives')
.insert({
tenant_id: tenantId,
title,
status: 'draft',
created_by: user.id,
})
.select('id,title,status,created_at')
.single();
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ creative: data }, { status: 201 });
}