Recap
What you built
Section titled “What you built”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.
The two paths: read and write
Section titled “The two paths: read and write”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.
Module-by-module recap
Section titled “Module-by-module recap”The table below maps each of the twelve build modules to what you actually practised and the Learn Hub course it adapts.
| Module | What you practiced | Learn Hub course it adapts |
|---|---|---|
| 1 · Setup & Tooling | Scaffolding a monorepo, tooling, and a Docker Compose skeleton | Node · Docker |
| 2 · Data Modeling | Designing MongoDB schemas for posts, tags, users, and comments | MongoDB |
| 3 · Backend Foundations | Structuring NestJS modules and providers with config and a global exception filter | Node · Design Patterns |
| 4 · Authentication | bcrypt + JWT/Passport auth with roles and guards | Node |
| 5 · GraphQL API | Code-first resolvers, pagination, and a @ResolveField author | GraphQL |
| 6 · Content Workflow | Unique slugs, a draft→publish transition, and a named refactoring pass | Refactoring · Design Patterns |
| 7 · Comments | A comment model with a pre-moderation approve/reject flow | MongoDB · GraphQL |
| 8 · Frontend Foundations | A Next.js App Router project and a typed gqlFetch client | Next.js · React |
| 9 · Public Blog | An ISR public blog with Markdown rendering, SEO, RSS, and a sitemap | Next.js |
| 10 · Admin Dashboard | An authenticated dashboard with a Markdown editor and comment moderation | Next.js · React |
| 11 · Testing | Jest + mongodb-memory-server on the backend, Vitest + RTL on the frontend | — |
| 12 · Docker & Compose | Multi-stage images and the full docker compose up stack | Docker |
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 →