
Case study
Fullstack Developer
Medium-clone
Medium-clone
Medium-clone is a personal fullstack project that reimagines how people create, share, and explore articles online. The project focuses on building a seamless web experience with user authentication, article management, and content categorization, all powered by a modern React and Node.js stack.
Medium-clone is a personal fullstack project that reimagines how people create, share, and explore articles online. The project focuses on building a seamless web experience with user authentication, article management, and content categorization, all powered by a modern React and Node.js stack.
Tech stack
Frontend: React, Tailwind CSS, Axios, Markdown-to-JSX
Backend: Node.js, Express.js, Sequelize ORM, JWT, Bcrypt.js
Database: MySQL
My role
Fullstack Developer
Tools
VS Code
Completed
May, 2023
Why I did it
Why I did it
Medium Clone was my first fullstack project, marking the transition from architecture student to software engineer. This project is not just a showcase of my coding skills, but also a demonstration of my ability to tackle a complex project, research and select the right tools, libraries, and solutions to build a functional and maintainable web application.
Medium Clone was my first fullstack project, marking the transition from architecture student to software engineer. This project is not just a showcase of my coding skills, but also a demonstration of my ability to tackle a complex project, research and select the right tools, libraries, and solutions to build a functional and maintainable web application.
What Medium
Clone shows
What Medium
Clone shows
The project provides a complete CRUD system, enabling users to interact with each other through likes, follows, and comments on articles. Articles are displayed in a paginated list (3 articles per page) and can be filtered by tags, making it easy for users to find content. Each user has a profile page displaying their bio and image, with the ability to edit personal information such as their name.
The project provides a complete CRUD system, enabling users to interact with each other through likes, follows, and comments on articles. Articles are displayed in a paginated list (3 articles per page) and can be filtered by tags, making it easy for users to find content. Each user has a profile page displaying their bio and image, with the ability to edit personal information such as their name.
Development Process
Development Process
I started by choosing React for the frontend to demonstrate my skills in building modern, component-based interfaces. I used Vite as the build tool since it’s lightweight and faster compared to Create React App, which relies on Webpack. For styling, I chose Tailwind CSS because it allows easy customization without cluttering the project with multiple CSS files.
For the backend, I selected Express.js because it’s one of the most popular frameworks for Node.js, with great documentation and a large community—making it ideal for showcasing my full-stack development capabilities. The additional libraries were chosen based on necessary functionalities such as user authentication and system management.
As for the database, I decided to use MySQL because it’s widely used, well-documented, and easy to learn, which made it a solid choice for this project.
I started by choosing React for the frontend to demonstrate my skills in building modern, component-based interfaces. I used Vite as the build tool since it’s lightweight and faster compared to Create React App, which relies on Webpack. For styling, I chose Tailwind CSS because it allows easy customization without cluttering the project with multiple CSS files.
For the backend, I selected Express.js because it’s one of the most popular frameworks for Node.js, with great documentation and a large community—making it ideal for showcasing my full-stack development capabilities. The additional libraries were chosen based on necessary functionalities such as user authentication and system management.
As for the database, I decided to use MySQL because it’s widely used, well-documented, and easy to learn, which made it a solid choice for this project.
Example feature in action
Example feature in action
Feature: Article Creation
- I built a form that allows users to create and publish articles.
This feature connects to the backend using Axios and provides form validation.
Feature: Article Creation
- I built a form that allows users to create and publish articles.
This feature connects to the backend using Axios and provides form validation.
const onFinish = async (e) => { e.preventDefault(); const body = { title, content, tags: tag }; try { await axios.post("http://localhost:8000/articles/", body); navigate("/"); window.location.reload(); } catch (err) { setError("Title should not contain spaces."); } };
This function represents the bridge between the front-end and back-end — showcasing how I handled asynchronous requests, error management, and user navigation in a clean and reactive way.
This function represents the bridge between the front-end and back-end — showcasing how I handled asynchronous requests, error management, and user navigation in a clean and reactive way.
Frontend: Article Input Section
- To allow users to write and edit their own articles, I implemented a Markdown editor using React’s controlled components and styled it with Tailwind CSS.
Frontend: Article Input Section
- To allow users to write and edit their own articles, I implemented a Markdown editor using React’s controlled components and styled it with Tailwind CSS.
<textarea name="content" value={content} onChange={(e) => setContent(e.target.value)} placeholder="Write your article (in markdown)" required rows={8} className="w-full rounded-md border-0 py-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 px-2.5 focus:ring-2 focus:ring-yellow-600 resize-y" />
This snippet demonstrates how I handled state, validation, and styling directly in JSX using Tailwind CSS. It’s a simple but key part of the article creation feature that brings the writing experience to life.
This snippet demonstrates how I handled state, validation, and styling directly in JSX using Tailwind CSS. It’s a simple but key part of the article creation feature that brings the writing experience to life.
Backend Logic: Article Creation & Tag Management
- This part of the project handles how a new article is created and connected to its related tags. It showcases how I handled data validation, database relations, and asynchronous operations using Express.js and Sequelize.
Backend Logic: Article Creation & Tag Management
- This part of the project handles how a new article is created and connected to its related tags. It showcases how I handled data validation, database relations, and asynchronous operations using Express.js and Sequelize.
const addArticle = async (req, res) => { const { title, content, tags } = req.body; const hashtag = tags.split(","); // Validate: title must not contain spaces if (title.includes(" ")) { return res.status(400).send({ message: "Title should not contain spaces." }); } // Create a new article const newArticle = await db.Article.create({ title, content, user_id: req.user.id, }); // Manage tags and relationships const newTag = await Promise.all( hashtag.map(async (tagName) => { const [tag] = await db.Tag.findOrCreate({ where: { name: tagName } }); const foundTag = await db.ArticleTag.findOne({ where: { article_id: newArticle.id, tag_id: tag.id }, }); if (!foundTag) { await db.ArticleTag.create({ article_id: newArticle.id, tag_id: tag.id, }); } return tag; }) ); newArticle.setDataValue("tags", newTag); res.status(201).send(newArticle); };
This logic handles article creation and tag management in Express and Sequelize, showcasing how I managed validation, relations, and clean database structure.
This logic handles article creation and tag management in Express and Sequelize, showcasing how I managed validation, relations, and clean database structure.
Want to see more code
Want to see more code
Github
Github
Showcase UI
Showcase UI












Let's make
something
meaningful together
wiriya.oran@gmail.com
Open for freelance & collaboration opportunities.
Oran Wiriya
© 2025 All rights reserved.
Let's make something
meaningful together
wiriya.oran@gmail.com
Open for freelance & collaboration opportunities.
Oran Wiriya
© 2025 All rights reserved.