Recent am închis un proiect care mi-a mâncat ultimele trei luni: un dashboard intern pentru o agenție de marketing cu vreo 15 angajați și peste 60 de clienți activi. Problema lor? Tot tracking-ul se făcea în Google Sheets. Aveau tabele peste tabele, scripturi de Apps Script care crăpau random și oameni care pierdeau cam 10-12 ore pe săptămână doar mutând date din Facebook Ads și Google Ads în rapoarte pentru clienți.
Am ales stack-ul clasic de „viteză”: Next.js (App Router), Prisma și NextAuth. Voiam ceva ce pot livra repede, dar care să nu se dezintegreze când adăugăm funcționalități noi.
De ce NextAuth m-a salvat (și unde m-a limitat)
NextAuth (sau Auth.js, cum îi zice mai nou) e genial pentru început. Am setat providerul de Google în 10 minute pentru că toți din agenție foloseau Google Workspace. Partea proastă a apărut când a trebuit să implementez RBAC (Role-Based Access Control) mai serios.
Clientul voia trei niveluri: Admin, Account Manager și Viewer (clienții lor). Am sfârșit prin a extinde manual sesiunea în callbacks ca să car role-ul peste tot. E un trade-off sincer: câștigi viteză la setup, dar pierzi flexibilitate dacă ai nevoie de permisiuni granulare pe resurse specifice. Dacă proiectul crește și mai mult, probabil va trebui să trec pe ceva mai robust sau să-mi scriu propriul middleware de autorizare.
Prisma și coșmarul agregărilor
Prisma e dragostea oricărui dev care urăște să scrie SQL cu mână, dar la proiectul ăsta mi-a arătat limitele. Când ai de calculat ROAS (Return on Ad Spend) pe 3 luni, combinând date din trei tabele diferite cu mii de rânduri, prisma.aggregate devine extrem de limitat.
Am avut un query care dura 4 secunde în Prisma. L-am rescris în SQL pur folosind prisma.$queryRaw și a scăzut la sub 400ms. Lecția învățată? Folosește Prisma pentru CRUD-ul de zi cu zi, dar nu te teme de SQL când vine vorba de raportare grea. Am economisit cam 30% din timpul de execuție al paginilor de analytics doar prin optimizarea asta.
API-urile externe: Adevăratul inamic
Cea mai mare provocare n-a fost codul meu, ci rate limiting-ul de la Meta și Google. Am făcut un sistem de sync care rulează ca un cron job (folosind Inngest, apropo, recomand maxim pentru background jobs în serverless).
La început, încercam să fac fetch la date „on-demand” când intra userul pe pagină. Eroare de începător. La 8-10 useri simultani, API-ul Meta ne dădea 429 imediat. Am trecut pe un model de tip cache: aducem datele noaptea, le procesăm, le salvăm în Postgres-ul nostru (un Supabase self-hosted), iar dashboard-ul doar citește din DB. Viteza de încărcare a crescut enorm, iar userii nu mai văd loadere infinite.
Ce a ieșit la final?
După 3 luni, am redus timpul de generare a rapoartelor lunare de la 2 zile de muncă manuală la... un click. Agenția estimează că a economisit cam 15 ore de muncă pe săptămână per Account Manager.
Stack-ul de Next.js cu Server Components a fost un pariu bun. Am reușit să ținem bundle-ul de JS mic pe client, lăsând logica grea de procesare pe server. Totuși, dacă aș lua-o de la capăt, aș investi mai mult timp de la început într-o structură de baza de date mai orientată spre analytics (poate un ClickHouse în paralel) decât să încerc să storc totul dintr-un Postgres clasic.
Voi cum gestionați raportările complexe în Next.js? Mergeți pe SQL pur din prima sau vă bazați pe ORM până când „scârțâie”?