De Ce Această Amploare

Pentru proiectul meu de licență, am ales deliberat ceva ambițios. Nu o aplicație CRUD cu o pagină de autentificare - ci o platformă de e-commerce completă, la nivel de producție. Genul în care trebuie să te gândești la securitatea plăților, livrabilitatea emailurilor, optimizarea imaginilor, controlul accesului multi-rol și ce se întâmplă când Stripe trimite același webhook de trei ori.

Rezultatul este trei aplicații care lucrează împreună:

  • Storefront pentru Clienți - Next.js 14 cu Material-UI pentru navigarea produselor, gestionarea coșului și finalizarea comenzii
  • Panou de Administrare - Next.js 14 cu Tailwind CSS pentru gestionarea produselor, procesarea comenzilor, analiză și generarea facturilor
  • API Backend - Express.js cu Sequelize, care gestionează logica de business, autentificarea JWT, integrarea Stripe și trimiterea emailurilor

Integrarea Stripe: Unde Se Ascund Detaliile

API-ul Stripe este proiectat impecabil. Documentația este excelentă. Și totuși, implementarea are capcane care apar abia în producție.

Sesiuni de Checkout

Fluxul: storefront-ul trimite articolele din coș către API. API-ul creează o Sesiune de Checkout Stripe cu articolele de plată, URL-urile de succes/anulare și metadate (ID comandă, ID utilizator). Stripe redirectează clientul către formularul de plată găzduit. După plată, Stripe trimite un webhook.

Concluzia esențială: nu te baza niciodată pe redirecționarea côté client. Un client poate fi redirecționat către URL-ul de succes chiar dacă plata eșuează (probleme de rețea, crash de browser). Singurul semnal de încredere este webhook-ul.

Verificarea Webhook-urilor

Fiecare webhook primit este verificat folosind secretul de semnătură al Stripe. Corpul brut al cererii și headerul stripe-signature sunt transmise către stripe.webhooks.constructEvent(). Dacă semnătura nu corespunde, cererea este respinsă. Fără această verificare, oricine ar putea trimite un eveniment fals checkout.session.completed și marca o comandă ca plătită.

Idempotență

Stripe poate livra același webhook de mai multe ori (reîncercări de rețea, livrare de tip „cel puțin o dată"). Handler-ul verifică dacă statusul de plată al comenzii a fost deja actualizat înainte de a procesa evenimentul. Sună evident, dar am văzut codebaze în producție care procesează același eveniment de plată de trei ori, trimitând trei emailuri de confirmare și decrementând inventarul de trei ori.

Emailuri Tranzacționale cu Brevo

Confirmările de comandă, notificările de expediere, linkurile de resetare a parolei - toate trimise prin Brevo (fostul Sendinblue). Fiecare tip de email are un fișier HTML cu șablon în directorul de template-uri email al serverului.

Șabloanele folosesc CSS inline (deoarece clienții de email ignoră foile de stil externe mai des decât nu) și tabele responsive care se degradează elegant în Outlook. Construirea emailurilor HTML care arată bine peste tot este un tip aparte de chin.

Un lucru pe care l-aș schimba: în acest proiect, emailurile sunt trimise sincron în cadrul ciclului de cerere. Dacă API-ul Brevo este lent sau indisponibil, cererea utilizatorului rămâne în așteptare. Într-un sistem de producție, aș pune joburile de email într-o coadă în fundal (BullMQ, de exemplu) și le-aș procesa asincron.

Generarea Facturilor PDF

Când un administrator marchează o comandă ca „expediată", sistemul generează o factură PDF la cerere folosind PDFKit. Factura include:

  • Logo-ul companiei și datele de contact
  • Numele, emailul și adresa de livrare ale clientului
  • Articolele din comandă cu numele produsului, cantitatea, prețul unitar și totalul pe linie
  • Subtotal, defalcarea taxelor și totalul general
  • Metoda de plată și referința tranzacției
  • Data comenzii și numărul facturii

PDF-ul este generat în memorie și transmis direct browserului administratorului - nu este necesară stocarea fișierelor. Dacă trebuie regenerat ulterior (cerere client, audit), aceeași funcție rulează din nou cu datele comenzii. Fără stare și previzibil.

Construirea layout-ului PDF a necesitat mai mult efort decât mă așteptam. PDFKit oferă poziționare absolută, ceea ce înseamnă că trebuie să calculezi manual coordonatele x/y pentru fiecare element. Anteturi, coloane, înălțimi de rânduri, întreruperi de pagină - toate manuale. Am ajuns să construiesc un mic renderer de tabele care gestionează lățimile coloanelor, fundalurile alternative ale rândurilor și întreruperile automate de pagină când conținutul depășește limita.

Securitate: Mai Mult Decât bcrypt

Construirea unei platforme de e-commerce înseamnă gestionarea fluxurilor de carduri de credit, datelor personale și banilor reali. Stiva de securitate:

  • Bcrypt pentru hash-uirea parolelor cu runde de sare configurabile (12 în producție)
  • JWT cu token-uri de acces cu durată scurtă (15 minute) și rotație a token-urilor de reîmprospătare. Fiecare token de reîmprospătare este de unică folosință - utilizarea lui emite o pereche nouă și invalidează token-ul vechi
  • Helmet.js pentru headere de securitate (Content-Security-Policy, X-Frame-Options etc.)
  • Rate limiting pe endpoint-urile de autentificare - 5 încercări de autentificare pe minut, 3 cereri de resetare a parolei pe oră
  • Interogări parametrizate prin Sequelize - toată intrarea utilizatorului este parametrizată, niciodată concatenată în SQL
  • CORS cu lista albă strictă de origini - doar URL-urile storefront-ului și ale panoului de administrare sunt permise
  • Validarea datelor de intrare pe fiecare endpoint - schemele Joi validează corpurile cererilor înainte ca orice logică de business să ruleze

Schema Bazei de Date

Modelele Sequelize definesc o schemă relațională complexă:

  • Utilizatori cu roluri (client, administrator), adrese și preferințe
  • Produse cu categorii (ierarhice), materiale, pietre prețioase și imagini
  • Comenzi cu articole, status plată, status expediere și metadate Stripe
  • Coș cu urmărirea articolelor per utilizator și gestionarea cantității
  • Recenzii cu evaluări stele și status de moderare

Sistemul de categorii ierarhice merită menționat: categoriile au o cheie externă parentId, permițând structuri imbricate precum „Bijuterii > Inele > Inele de Logodnă." Storefront-ul redă aceasta ca o navigare breadcrumb, iar panoul de administrare o afișează ca un arbore.

Două Frontend-uri, Un Singur API

Storefront-ul pentru clienți și panoul de administrare sunt aplicații Next.js complet separate. Ele partajează același API Express, dar au fluxuri de autentificare diferite, layout-uri diferite și seturi de funcționalități diferite.

Storefront-ul folosește Material-UI pentru un design rafinat, prietenos cu clienții. Paginile de produse au galerii de imagini, selectoare de dimensiuni și butoane „Adaugă în Coș". Fluxul de checkout se integrează cu pagina de plată găzduită de Stripe.

Panoul de administrare folosește Tailwind CSS pentru un layout dens, orientat spre date. Include tabele de date cu sortare și filtrare, gestionarea comenzilor cu tranziții de status, CRUD pentru produse cu încărcare imagini și un dashboard de analiză care afișează veniturile, volumul comenzilor și produsele populare.

Strategia de Testare

Trei niveluri:

  • Teste unitare - testarea funcțiilor pure pentru calcule de prețuri, logica de reduceri, reguli de validare
  • Teste de integrare - testarea endpoint-urilor API cu Supertest, folosind o bază de date de test populată înainte de fiecare suită
  • Teste E2E - fluxuri complete de utilizator cu Selenium: navigarea produselor, adăugarea în coș, finalizarea comenzii, verificarea creării comenzii

Testele de integrare au fost cele mai valoroase. Au depistat cazuri limită pe care testele unitare le-au ratat: operațiuni concurente pe coș, condiții de cursă la verificările inventarului și eșecuri de creare a comenzilor care ar trebui să anuleze golirea coșului.

Ce M-a Învățat Acest Proiect

Construirea unei platforme de e-commerce end-to-end este o lecție magistrală în problemele care nu apar în proiectele mai mici:

  1. Securitatea plăților nu înseamnă doar HTTPS. Verificarea webhook-urilor, idempotența și crearea sesiunilor côté server sunt toate esențiale. Bazarea pe redirecționările côté client este o rețetă pentru fraudă.
  2. Emailul este o problemă rezolvată care nu e niciodată rezolvată. Redarea HTML în clienții de email, livrabilitatea, configurarea SPF/DKIM și gestionarea respingerilor sunt fiecare propriul labirint.
  3. PDF-urile sunt mai grele decât par. Fără un motor de layout de nivel înalt, faci calcule de pixeli. Merită să construiești un mic strat de abstractizare.
  4. Accesul multi-rol este o decizie de la prima zi. Retrofitarea rutelor doar pentru administratori pe un sistem proiectat pentru un singur rol este dureroasă. Planifică-o din timp.
  5. Testează punctele de integrare. Webhook-urile Stripe, trimiterea emailurilor și generarea PDF-urilor sunt locurile unde se ascund bug-urile. Testarea unitară a logicii de business este necesară, dar nu suficientă.

Cod sursă: gitlab.com/licenta4785538/jewelry-store

Înapoi la Articole