Projects Integration with Supabase - Setup Guide
This guide explains how to configure and populate the projects integration with Supabase (Postgres + Auth + Storage).
📋 What was implemented
1. TypeScript types
- Arquivo:
src/app/types/project.ts - Full definition of the
Projectinterface ProjectInputtype for create/update- Listing filters and result type
2. Server functions
src/app/server/projects/get-all-projects.ts: Busca todos os projetos com filtrossrc/app/server/projects/get-project-by-slug.ts: Busca projeto por slug
3. Server Actions (CRUD)
src/app/actions/projects/create-project.ts: Criar projetosrc/app/actions/projects/update-project.ts: Atualizar projetosrc/app/actions/projects/delete-project.ts: Deletar projeto (soft/hard delete)src/app/actions/projects/toggle-project-active.ts: Alternar status ativo
4. Updated components
-
src/app/components/projects/projects-grid.tsx:- Consumes projects from the server
- Category filter (mobile, front-end, back-end, full-stack, ai)
- Stack/technology filter
- Empty state when there are no results
-
src/app/[locale]/(pages)/projetos/page.tsx:- Fetches Supabase projects on the server
- Passes data to the ProjectsGrid component
5. Translations
Added translation keys in EN, PT, and ES:
Projects.stackFilter.title: “Filtrar por tecnologia”Projects.stackFilter.clear: “Limpar filtro”Projects.emptyState: “Nenhum projeto encontrado com os filtros selecionados”
6. Seeding
- Use
npm run db:seedto populate local data (optional)
🚀 Next steps
1. Create indexes in Postgres (Supabase)
Create indexes that match your filter/sort queries (e.g., slug, created_at).
You can define indexes directly in the Supabase SQL migrations.
Option B: Create manually
Open the Supabase Dashboard and create the necessary indexes: https://app.supabase.com
Recommended indexes for the projects table:
- isActive (ASC) + order (ASC) - Default ordering
- isActive (ASC) + createdAt (DESC) - Sort by newest
- isActive (ASC) + isFeatured (DESC) + order (ASC) - Featured projects
- isActive (ASC) + category (ASC) + order (ASC) - Category filters
- isActive (ASC) + stack (ARRAY_CONTAINS) + order (ASC) - Stack filters
2. Populate the database
Run the seed to populate sample projects (optional):
npm run db:seedThe seed should:
- Read projects from
src/app/data/projects.ts - Insert rows into the
projectstable - Extract technologies into the
stackarray for filters - Check for duplicate slugs
- Add timestamps and metadata
3. projects record structure (Supabase)
{
"slug": "luminall-ai",
"title": "luminall-ai",
"description": "luminall-ai",
"badge": "luminall-ai",
"category": "ai",
"tech": ["Next.js", "OpenAI GPT-4", "TypeScript", "Supabase", "Tailwind"],
"link": "https://www.luminall.me",
"image": "/assets/images/projects/front-end/luminall-demo.png",
"imagePath": "/assets/images/projects/front-end/luminall-demo.png",
"stack": ["Next.js", "OpenAI GPT-4", "TypeScript", "Supabase", "Tailwind"],
"isActive": true,
"isFeatured": false,
"order": 0,
"createdAt": "2025-01-XX...",
"updatedAt": "2025-01-XX..."
}Note: The title, description, and badge fields are translation IDs. The component looks them up in messages/[locale].json using Projects.items.{slug}.{field}.
🔍 How the stack filter works
ProjectsGridextracts the unique technologies from every project’sstackarray- Renders a button for each technology
- Clicking a technology filters projects that include it in their
stackarray - Works alongside the category filter
🎨 Customization
Add new projects programmatically
- Use a action
createProject:
import { createProject } from "@/app/actions/projects/create-project";
const result = await createProject({
slug: "meu-novo-projeto",
title: "meu-novo-projeto", // Translation ID
description: "meu-novo-projeto", // Translation ID
badge: "meu-novo-projeto", // Translation ID
category: "front-end",
tech: ["React", "Next.js", "TypeScript"],
link: "https://exemplo.com",
stack: ["React", "Next.js", "TypeScript"],
isActive: true,
isFeatured: false,
order: 10,
});- Add translations in
src/i18n/messages/[locale].json:
{
"Projects": {
"items": {
"meu-novo-projeto": {
"title": "My New Project",
"description": "Project description...",
"badge": "Project badge"
}
}
}
}Manage project ordering
Projects are ordered by the order field (ascending). To reorder:
import { updateProject } from "@/app/actions/projects/update-project";
await updateProject(firestoreId, { order: 5 });🐛 Troubleshooting
Error: “The query requires an index”
- Create the necessary indexes in Postgres (Supabase)
Projects do not appear on the page
- Make sure you ran the migration script
- Confirm the projects have `isActive: true
- Check server logs for connection errors
Filters are not working
- Verify the indexes exist
- Ensure the
stackfield is populated correctly