zaki-ns Platform
Full-Stack Developer32 weeksEn ligneTeam of 1

zaki-ns Platform

PostgreSQL-backed portfolio CMS with admin dashboard, bilingual public site, and schema-driven content

NJNext.js 16R1React 19TypeScriptTypeScriptPrismaPrismaPostgreSQLPostgreSQLNnext-intlTailwind CSSTailwind CSSCCloudinary
Voir en ligneCode source

Intelligence projet

Durée

32 weeks

Technologies

8

Statut

Production

Défi principal

Designing a schema and seed pipeline that scales from static lib/data.ts to PostgreSQL without breaking public pages during migration

Compétences démontrées

Full StackSystem DesignDatabase DesignCMSi18nDevOps

En bref

Built a deployable zaki-ns platform where public pages read from PostgreSQL via Prisma, admin forms persist through Server Actions, and revalidateTag keeps the cached site in sync—covering projects, labs, articles, products, journey, and site settings.

Problème

Mock data in lib/data.ts drifted from admin edits and could not scale to multiple deployable portfolios

Solution

Prisma schema with translation rows, JSON seed pipeline, and cached DB getters with admin Server Actions

Résultat

One codebase deployable per customer with admin-editable content and no localStorage drift

50+

Prisma models

6

DB-backed content types

Résultats clés

10+

Content types

50+

Prisma models

12

Admin routes

Visuels sélectionnés

Screenshot 1
1 / 25

Résultats & impact

Production-grade portfolio CMS that demonstrates full-stack engineering on the site itself.

The platform showcases its own architecture—every project, lab, and article is editable through the admin the visitor can explore.

10+

Editable content areas

0

localStorage content drift

Architecture

Architecture diagram

Public pages are Server Components that call locale-aware getters in lib/*.ts. Each getter uses withDbFallback to read from PostgreSQL via *-db.ts mappers, falling back to lib/data.ts during migration.

Admin client forms call Server Actions that upsert Prisma records—including nested translations, sections, and relations—then revalidate cache tags so the public site reflects edits without redeploying.

Content is modeled with translation tables (project_translation, lab_translation, etc.) and shared content_section rows for long-form lab and article bodies.

Infrastructure & déploiement

Docker Compose for local PostgreSQL, deployable to Vercel with Neon/Supabase. Cloudinary for media. ADMIN_SECRET gates /admin via HMAC session cookie.

Fonctionnalités

Essentiel

Admin CRUD

Full create/read/update/delete for projects, labs, articles, products, experience, skills, and journey.

Essentiel

Cached DB reads

Public getters with unstable_cache and revalidateTag for fast SSR without stale content.

Essentiel

Bilingual routing

next-intl locale segments with translation-ready schema.

Secondaire

Rich case studies

Slides, challenges, architecture, metrics, and screenshots as first-class relations.

Secondaire

Contact inbox

Form submissions stored in DB with optional email notification.

Planifié

Quote calculator

Interactive pricing page with project types, complexity tiers, and add-ons.

Défis & solutions

1

Nested admin saves vs relational schema

Le problème

Project case studies include slides, challenges, screenshots, and translations—naive form posts dropped nested arrays on partial saves.

Comment je l'ai résolu

Server Actions merge nested payloads server-side with explicit delete-and-recreate for child collections inside Prisma transactions.

await prisma.$transaction(async (tx) => {
  await tx.projectSlide.deleteMany({ where: { projectId } })
  await tx.project.update({
    where: { id: projectId },
    data: { slides: { create: slides } },
  })
})
revalidateTag('projects')
2

Migration without downtime on public pages

Le problème

Replacing lib/data.ts imports broke pages before DB seed was ready.

Comment je l'ai résolu

withDbFallback tries Prisma first and falls back to static seed data until counts verify.

3

Locale content strategy

Le problème

Full bilingual body copy for every entity was not ready, but UI chrome needed FR immediately.

Comment je l'ai résolu

Option A: English body from DB, French UI strings from lib/translations.ts; schema supports Option B translation rows when ready.

Leçons apprises

  1. 1

    Seed from version-controlled JSON

    Generating structured content JSON and importing it through lib/data.ts keeps demo portfolios reproducible and reviewable in PRs.

  2. 2

    Translation tables early

    Adding locale columns on translation rows from day one avoids painful schema migrations when bilingual CMS editing arrives.

  3. 3

    Cache tags per aggregate

    Granular revalidateTag keys (projects, labs, site) prevent stale public pages without flushing the entire Next.js cache.

  4. 4

    Domain types before Prisma imports

    UI and admin import Project/Lab types from lib/, never Prisma types—mappers isolate the ORM from React components.

Ce que je ferais différemment

Wire quote calculator settings to the database earlier instead of keeping lib/quote-data.ts hardcoded alongside otherwise DB-backed site content.