Skip to content

Recap

You started with an empty repository and finished with a headless CMS that a real content team could recognise: authors sign in, write Markdown posts, tag and publish them, and moderate the comments readers leave — and the public reads a fast, cached, SEO-friendly blog that never touches the database directly. Along the way you didn’t just wire features together; you practised the decisions that separate a toy from something shippable.

On the backend, you stood up a NestJS application with typed configuration and a global AllExceptionsFilter, modelled posts, tags, users, and comments as Mongoose documents, and layered the code into modules and providers instead of one file that does everything. You added real authentication — bcrypt-hashed passwords, JWT issued and verified through Passport, roles and guards deciding who may do what — and then exposed the whole thing as a code-first GraphQL API, with resolvers for posts, tags, and comments, pagination, and a @ResolveField author that resolves each post’s writer on demand. You gave content a genuine workflow: unique slugs generated by a SlugService, a draft→publish transition, pre-moderated comments, and a named refactoring pass that left the code better than you found it.

On the frontend, you built a Next.js App Router application with a typed gqlFetch client, an ISR public blog that renders Markdown and ships SEO metadata, RSS, and a sitemap, and an authenticated admin dashboard with a Markdown editor and a comment-moderation queue. You covered the stack with Jest and mongodb-memory-server on the backend and Vitest with React Testing Library on the frontend, and finally packaged all three services into multi-stage Docker images that come up together with a single docker compose up.

If you remember one thing about DevBlog’s shape, make it this: there are two paths through the system, and they are deliberately different.

The write path is authenticated and goes through GraphQL mutations. An author logs in, the API issues a JWT, and every subsequent createPost, publishPost, addTag, or comment-moderation call carries that token past a guard that checks the author’s role before the resolver ever runs. This path is dynamic by nature — it changes state, it must be protected, and it is used by a handful of people. Correctness and access control matter more than raw speed here.

The read path is anonymous and optimised for cache. A reader never authenticates and never issues a mutation; they hit a Next.js page that was pre-rendered and is revalidated on a schedule (ISR), which fetches published content from the same GraphQL API through server-side queries. Because published posts change rarely relative to how often they are read, the read path can be cached hard and served fast to everyone, while the write path stays dynamic for the few who author. The GraphQL schema is the single contract sitting between the two — the same typed API the admin dashboard mutates against is the one the public blog reads from — which is exactly why decoupling authoring from delivery was worth the extra moving parts.

The table below maps each of the twelve build modules to what you actually practised and the Learn Hub course it adapts.

ModuleWhat you practicedLearn Hub course it adapts
1 · Setup & ToolingScaffolding a monorepo, tooling, and a Docker Compose skeletonNode · Docker
2 · Data ModelingDesigning MongoDB schemas for posts, tags, users, and commentsMongoDB
3 · Backend FoundationsStructuring NestJS modules and providers with config and a global exception filterNode · Design Patterns
4 · Authenticationbcrypt + JWT/Passport auth with roles and guardsNode
5 · GraphQL APICode-first resolvers, pagination, and a @ResolveField authorGraphQL
6 · Content WorkflowUnique slugs, a draft→publish transition, and a named refactoring passRefactoring · Design Patterns
7 · CommentsA comment model with a pre-moderation approve/reject flowMongoDB · GraphQL
8 · Frontend FoundationsA Next.js App Router project and a typed gqlFetch clientNext.js · React
9 · Public BlogAn ISR public blog with Markdown rendering, SEO, RSS, and a sitemapNext.js
10 · Admin DashboardAn authenticated dashboard with a Markdown editor and comment moderationNext.js · React
11 · TestingJest + mongodb-memory-server on the backend, Vitest + RTL on the frontend
12 · Docker & ComposeMulti-stage images and the full docker compose up stackDocker

DevBlog is a headless CMS plus a public blog, and its defining shape is two paths over one GraphQL contract: an authenticated write path through mutations for the few who author, and an anonymous, cache-first ISR read path for the many who read. You practised document data modelling, layered NestJS architecture, real auth with roles and guards, a typed code-first GraphQL API, content and moderation workflows, a Next.js App Router frontend for both audiences, tests across the whole stack, and a one-command Docker Compose deployment. The next lesson gives you ways to push each of those further.

Next: Extension exercises →