
Author Bio
Greetings! I'm an accomplished front-end developer driven by a profound passion for crafting highly efficient web applications. My journey in web development spans a wide spectrum, encompassing a mastery of technologies such as HTML, CSS, JavaScript, TypeScript, and frameworks like VueJS (including Vuex) and React (including Redux). I also wield expertise in design systems like Bootstrap and Tailwind CSS, and I'm proficient in utilizing build tools like Gulp, Webpack, and version control with Git.
My academic background is grounded in Computer Engineering, where I obtained a Bachelor's degree. Additionally, I've expanded and refined my skill set through immersive learning experiences. This includes completing a five-month frontend development course at Beetroot Academy and undergoing specialized training in the Vue.js framework at InventorSoft where since January 2022, I have been actively engaged in various web development projects.
With these formidable tools at my disposal, I specialize in creating captivating and responsive web applications. My goal is to breathe life into sleek interfaces and facilitate seamless user interactions, consistently striving to deliver extraordinary digital experiences.
Latests Posts
Building Simple CRM with Vue: Crafting Layouts and Navigation
Now that we've successfully completed the preliminary installations, it's time to embark on the exciting journey of building our CRM with Vue. The question is, where do we begin? The answer lies in the fundamentals — navigation, headers, and layouts. These essential elements will form the cornerstone of our main "Dashboard" page, seamlessly integrated into our router configuration. Let's outline a concise plan to guide us through the next steps:1.Layouts: Unveiling the What, Why, and How: Delve into the significance of layouts – what purpose they serve, why they matter, and how to craft them effectively.2. Initiate the "Dashboard" Page:Start by creating the foundational "Dashboard" page, setting the stage for our CRM's central hub.3. CRM Navigation: Crafting a Sidebar: Explore the intricacies of CRM navigation, focusing on the creation of a user-friendly sidebar.As we progress through each step, we'll unravel the art of crafting layouts and navigation in Vue, ensuring a robust foundation for our Simple CRM. Stay tuned for practical insights and step-by-step guidance as we navigate the world of Vue.js development.1. Layouts: What and Why do We Need Layouts?A layout in web development refers to the structural arrangement of visual elements on a webpage, defining the positioning and organization of content. It establishes the overall framework, including the placement of headers, footers, navigation bars, and other components, ensuring a cohesive and user-friendly design.In simple words, a layout is a web page background where we position all elements. For example with our simple CRM, we will need two layouts: the first or main layout for all our pages which will contain a header, sidebar, menu, and maybe a footer; the second one, an empty layout for the login page and maybe a 404 page.1.1 How to add layout to Vue project?It will be clearer when we create and use layouts in practice. So let's do it:Inside our project create a "layouts" folder and a "MainLayout.vue" file. It will be the layout for our main app pages, so we need to add "Header" for start, and "RouterView" (the place where our 'children' routes will be rendering). Also, inside the "components" folder create another folder "navigation" and add a "Header" file with some empty template. That's it:<template> <main> <Header /> <RouterView /> </main> </template> <script> import { RouterView } from 'vue-router'; import Header from '@/components/navigation/Header.vue'; export default { name: 'MainLayout', components: { Header, } }; </script> Now, we need to update our main "App.vue" file. Remove "Router" because all routes control is inside the layout and import our "MainLayout" into the App component.<template> <MainLayout /> </template> <script> import MainLayout from '@/layouts/MainLayout.vue'; export default { name: 'App', components: { MainLayout } } </script> We need to improve our route configurations, we will add the first route and nested routes as its children.import { createRouter, createWebHistory } from 'vue-router'; import Dashboard from '../views/Dashboard.vue'; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', children: [ { path: '', component: Dashboard, }, ] }, ] }) export default router If you need to get more details about "Vue Router" you can check my articles about that.Now, we can launch our development server (npm run dev) and check the result:
Full-Stack Blogging CMS: A 17-Part Journey
In this summary, we revisit our step-by-step journey in developing a full-stack blogging CMS from scratch using React.js and Node.js. Across 17 detailed parts, each tutorial piece builds upon the previous one, guiding you through everything from setting up the initial project architecture to implementing advanced features like authentication, CORS configuration, and process management with PM2. This series not only demonstrates modern web development best practices but also delivers practical insights into creating a secure and scalable content management platform. Below, you will find a detailed breakdown of each tutorial part, along with direct links to explore the individual articles.1. Let's Develop a Fullstack Blogging CMS from Scratch using React.js and Node.jsIn this article, we kick off a new series by laying the groundwork for building a dynamic blogging CMS using React.js and Node.js. The post outlines our project vision, covering everything from design exploration and project structure to selecting a technology stack featuring React, Redux, Express, and MongoDB. You’ll discover how thoughtful planning and carefully selected libraries can streamline both frontend and backend development. Whether you're enhancing your portfolio or sharpening your development skills, this introductory guide sets the primary stage for a modern web development.2. Build Content Management System with React and Node: Beginning Project SetupIn this article, we set the stage by installing and configuring all the essential dependencies for our project. You'll learn how to quickly scaffold the front-end with Vite, integrating React, Redux, React Router, Sass, and Material UI for a solid user interface foundation. On the back-end, we launch a Node.js server with Express and Nodemon for seamless development. This guide ensures that your development environment is fully prepped and functional.3. Building a React CMS: Fonts, SCSS Resets, and Layout ImplementationIn this article, we enhance our React CMS by setting up custom fonts, implementing SCSS resets, and constructing main layout. We start by importing and configuring 'Roboto' fonts from Google Fonts to ensure consistent typography, followed by applying reset styles to neutralize browser defaults. Next, we build a reusable layout that features a dynamic header and sidebar, facilitating streamlined routing and navigation across CMS pages. With these foundational elements in place, the stage is set for integrating more advanced features in our upcoming posts.4. Structuring the Server: Node.js, MongoDB, and User Models for Our CMSIn this article, we focus on structuring our Node.js backend and establishing a solid connection to MongoDB for our CMS project. We begin by organizing our server-side code into clear modules, including routes, controllers, models, and schemas, ensuring a scalable and maintainable foundation. Next, we demonstrate how to set up a basic user model with an associated schema and create the necessary routes to manage user-related operations. Finally, we illustrate the process of connecting our server to a MongoDB database.5. Building a Complete User Registration System with React and Node.jsIn this article, we build a complete user registration system for our Blog CMS, starting with designing an elegant registration page using a custom empty layout for authentication routes. We guide you through setting up a responsive registration form in React and establishing API communication with the Node.js backend. On the server side, the tutorial covers encrypting passwords using bcrypt, creating new user records, and ensuring unique email registrations while generating secure tokens. This guide lays a foundation for user management in our CMS and sets the stage for integrating login functionality in upcoming posts.6. Login Logic: Building User Authentication for Your CMSIn this article, we implement a secure login system for our CMS by building a responsive login form in React and developing corresponding authentication endpoints in Node.js. The tutorial walks through capturing user credentials, verifying them against stored data, and leveraging JWT for secure session management on the backend. We detail every step from integrating API communication on the frontend to encrypting and validating credentials on the server. This guide not only complements our previous registration process but also provides a strong foundation for user authentication within our CMS.7. Redux Integration: Enhancing Your Node.js and React CMSIn this article, we integrate Redux into our CMS project to enhance state management and streamline data flow across our React application. We start by setting up Redux utilities, including a helper for creating actions and structuring a dedicated store for authentication data. The tutorial walks through establishing action types, reducers, actions, and selectors, followed by integrating the Redux store with our React app via the Provider. Finally, we demonstrate how to dispatch actions—in this case, updating user state during the login process—illustrating Redux’s role in managing complex UI states for our growing CMS.8. Enhancing User Experience: Implementing Notifications, Modals and Loaders in a React-based CMSIn this article, we enhance our CMS's user experience by implementing new UI components, including a dynamic notification system and a sleek loader. The tutorial details setting up Redux to manage global notifications and modals, providing instant feedback with success, error, or warning messages. We then build a reusable modal system to flexibly display various interactive elements and integrate a loader component that offers visual cues during asynchronous operations. These improvements significantly boost CMS's interface usability and responsiveness.9. React and Node.js CMS Series: Implementing Post Lists with Advanced Table FeaturesIn this tutorial, we transform the static Posts page of our CMS into an interactive data management interface by building a feature-rich posts table in React. We walk through crafting a dynamic table component complete with post details, pagination, and actions such as edit, preview, and status changes, as well as setting up frontend data fetching and Redux state management. On the backend, we create the necessary API routes and controllers in Node.js to efficiently return post data from our database. This approach provides a solution for managing and displaying posts, and defining the way for future enhancements like sorting and filtering.10. Content Management System: Building a Post Creation System from Scratch with Node jsIn this guide, we build the core backend functionality for post creation in our CMS by setting up a MongoDB schema and the necessary API infrastructure using Node.js and Express. We outline the process of designing a flexible post model, developing a service layer for saving posts, and establishing secure API endpoints to handle post creation requests. The tutorial also details the creation of a controller with proper error handling to ensure a smooth data flow between the frontend and the database. With this strong backend foundation in place, the stage is set for integrating an intuitive post creation interface on the frontend in the next article.11. React Post Creation Form: Building the Frontend for Your Content Management SystemIn this guide, we build a React-based post creation interface that integrates with our CMS backend. We start by configuring a dedicated route and crafting a user-friendly posts action section with clear navigation, then dive into designing a detailed post form that covers all essential fields from our MongoDB schema. The tutorial covers dynamic form handling including text inputs, meta fields, and a versatile body section with a rich text editor and image uploader placeholders. Although advanced media handling will be enhanced in future articles, this setup lays the groundwork for a full-featured post editor.12. Integrating Quill Editor and Image Upload Functionality in a React CMSIn this article, we integrate powerful content creation tools into our React-based CMS by implementing a rich text editor and a custom image uploader. We start with Quill Editor, setting up a dedicated component with custom toolbar configurations and dynamic event handling to support flexible formatting. Next, we build a reusable ImageUploader that features both drag-and-drop and click-to-upload functionalities, complete with image previews and metadata support. These components are designed for reusability across the entire CMS and lay the foundation for advanced post-editing capabilities in future updates.13. Node.js Image Upload System: File Handling, Storage, and Database IntegrationIn this tutorial, we build a server-side image management system using Node.js to complement our client-side image upload functionality in our CMS. We begin by setting up routes, controllers, and configuring Multer for handling multipart/form-data, ensuring that images are properly stored and their metadata managed. Next, we implement an endpoint for image deletion, allowing removal of uploaded files from the server. Finally, we integrate these endpoints into our frontend workflow, modifying the post creation process to handle main and additional image uploads, thereby providing a solution for image handling in the CMS.14. React and Node.js CMS Series: Implementing Advanced Post Editing FunctionalityIn this tutorial, we continue developing our React + Node.js CMS by implementing post-editing functionality. We'll start by setting up new backend routes and controllers to fetch, update, and remove posts using a "slug" identifier. Then, we'll enhance the frontend by integrating an edit button in the post list, redirecting users to a dynamic post form that fetches and pre-fills post data. Using Redux, we'll track changes and manage post updates. By the end, our CMS will support post modifications, making content management more flexible and user-friendly.15. CMS Development: Adding Post Preview and Status Management in React and Node.jsIn this article, we enhance our CMS by adding a dynamic post preview mechanism and a status management system. The new preview feature allows content creators to review posts in detail before publication, ensuring their content appears exactly as intended. Simultaneously, the status control system provides precise management over post visibility, allowing activation or deactivation of content through a partial update mechanism. Together, these features not only improve user experience but also lay the foundation for further extensible enhancements in our CMS architecture.16. Smart Content Management: Integrating Search, Filters, and Pagination with React and Node.jsIn this tutorial, we've enhanced our CMS by adding advanced search, filtering, and pagination functionalities. The backend has been updated to handle dynamic queries, enabling the retrieval of posts based on search keywords, filters like status and language, and controlled pagination. On the frontend, integration with Redux and the MUI TablePagination component ensures user interaction with these new features. Together, these improvements transform our CMS into a more user-friendly platform, demonstrating how modern technologies can be used to streamline content management.17. React and Node.js CMS Series: Finish LineIn the final chapter of our CMS journey, we bring together advanced backend configurations and production-readiness features to complete our full-stack application. This article details how to implement essential security and deployment enhancements, including CORS for controlled domain access, authentication middleware to safeguard routes, and environment management with dotenv. Additionally, we set up PM2 to manage our Node.js server processes, ensuring our app runs smoothly in production environments. This guide not only reinforces modern web development practices but also provides a blueprint for deploying secure, scalable, and resilient applications.This series guiding you from basic project architecture to a feature-rich, production-ready CMS. Each step built meaningful skills—from integrating rich content editors and dynamic image handling to ensuring security and scalability with advanced middleware and process management. The journey not only highlights modern JavaScript best practices but also lays a blueprint for creating secure, efficient, and user-friendly web applications. We hope this series inspires you to keep innovating and expanding your development toolkit.Thank you for being with us on this journey; see you in the next tutorials.
React and Node.js CMS Series: Finish Line
We've reached the culmination of our journey—a full-stack Content Management System built with React and Node.js. Through a series of carefully crafted tutorials, we've transformed conceptual ideas into a feature-rich application that not only demonstrates web development techniques but also serves as a showcase of modern JavaScript ecosystem capabilities. What began as a series of incremental steps has now evolved into a platform that integrates complex functionalities like CRUD operations, post management, search, filtering, and pagination.In this article, we still have some jobs to do, we will configure CORS, PM2, and auth protection middleware.1. Fortifying Our Application: CORSCORS (Cross-Origin Resource Sharing) is a security feature in web browsers that restricts web pages from requesting a domain different from the one that served them unless explicitly allowed by the server. It is implemented via HTTP headers, enabling servers to control which origins, methods, and headers are permitted for cross-origin requests.Luckily we have CORS module.- open our "server" folder, and use "npm i cors" to install new module;- create new "cors.js" file inside the "server" folder;- create an array "whiteList" for example, that will store our allowed domains;- add a new "CorsOptions" checker that will run at each request and dynamically compare domain with "whiteList" and return the result;var whitelist = [ 'http://localhost:5173', ] var corsOptions = { origin: function (origin, callback) { if (whitelist.indexOf(origin) !== -1) { callback(null, true) } else { callback(new Error('Not allowed by CORS')) } } } module.exports = corsOptions; - export "CorsOptions" ;- inside the "app.js" file import "CorsOptions", and "cors";const corsOptions = require('./cors'); const cors = require('cors'); - apply the CORS policy to all incoming requests, ensuring only allowed requests pass through;app.use(cors(corsOptions)); Great, now we can control the allowed domains.2. Fortifying Our Application: Auth Protection MiddlewareWe added CORS protection, to secure our app from external requests, but also we would like to protect our data from unauthorized users, for that task, we will create an "auth" checker middleware.- create a new "auth.js" file inside the "middleware" folder;- import the "jwt" module, and our "users" model;const jwt = require('jsonwebtoken'); const usersModel = require('../models/users/users.model'); - export "protect" checker, which will get the token from the request, verify it, then check the user from the database (for example if the user has permission), and return some response (usually allowing to use of data or not);exports.protect = async (req, res, next) => { let token; if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { token = req.headers.authorization.split(' ')[1]; } if (!token) { return res.status(401).json({ message: "You are not logged in! Please log in to get access" }); } const decoded = jwt.verify(token, process.env.JWT_SECRET); const currentUser = await usersModel.findUserById(decoded.id); if (!currentUser) { return res.status(401).json({ message: "The user belonging to this email does not exist" }); } req.user = currentUser; next(); }; - import our "protector" middleware into the routes folder and add this after the route name, to protect that route;const { protect } = require('../../middleware/auth'); postsRouter.get('/', protect, postsController.getPostsList); postsRouter.get('/:slug', protect, postsController.getPostBySlug); postsRouter.post('/create', protect, postsController.createNewPost); postsRouter.post('/update', protect, postsController.updatePost); postsRouter.post('/post-image', protect, postsController.uploadPostImage); postsRouter.post('/remove-image', protect, postsController.deletePostImage); postsRouter.post('/remove', protect, postsController.removePost); Nice, we configured an additional protector for our routes, next we will set a process manager.3. Fortifying Our Application: dotenv"dotenv" is a Node.js package that loads environment variables from a .env file into process.env, allowing you to store sensitive configuration details like API keys, database URLs, and ports securely. This helps keep credentials out of the source code, making applications more secure and easier to configure across different environments. It is commonly used in applications to manage environment-specific settings, and we will implement "dotenv" into our app also.- use the "npm i dotenv dotenv-safe" command in our "server" folder;- import and use "dotenv" options inside the "server.js" file;require('dotenv').config(); - inside the "app.js" file import "dotenv", and check the application environment, if "production" we will return one type of configs, and if "development" then another;if (process.env.NODE_ENV === 'production') { dotenv.config({ path: path.resolve(__dirname, '../.env.production'), example: path.resolve(__dirname, '../.env.example'), allowEmptyValues: true, }); } else { dotenv.config({ path: path.resolve(__dirname, '../.env.development'), example: path.resolve(__dirname, '../.env.example'), allowEmptyValues: true, }); } - we need to create 2 files: ".env.development" and ".env.production" which will store variables for different environments; For example:ENVIRONMENT=production PORT=8443 Let's move on.4. Preparing for Production: PM2PM2 is a process manager for Node.js applications that allows you to run, monitor, and manage multiple Node.js processes with features like automatic restarts, logging, and clustering. In other words, it's a "nodemon" but more complicated (it will run your server all the time, in few threads, and will not stop if there are errors, "simple errors").- use the "npm i pm2" command in the server console, to install PM2 module;- open the "package.json" config file, and add new scripts to control the PM2 services; "start-dev": "pm2 start src/server.js --env development", "start": "pm2 start src/server.js --env production", "stop": "pm2 stop src/server.js", "restart": "pm2 reload src/server.js" - we need to modify our "server.js" file;const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; // cluster: Enables the server to use multiple CPU cores by creating worker processes. // http: Creates an HTTP server (instead of HTTPS). // os.cpus().length: Gets the number of CPU cores available to fork worker processes require('dotenv').config(); const app = require('./app'); const mongo = require('./services/mongo'); const PORT = process.env.PORT || 8443; // dotenv.config(): Loads environment variables from a .env file into process.env. // app: Imports the Express application. // mongo: Imports the MongoDB connection service. // PORT: Reads the port number from the .env file or defaults to 8443 if (cluster.isMaster) { console.log(`Master ${process.pid} is running`); for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.process.pid} died`); }); // if (cluster.isMaster): - Runs only in the master process. - Forks worker processes equal to the number of CPU cores using cluster.fork(), allowing the server to handle multiple requests concurrently. - Listens for worker exits and logs when a worker dies. } else { async function startServer() { await mongo.mongoConnect(); const server = http.createServer(app); server.listen(PORT, () => { console.log(`Worker ${process.pid} listening on :${PORT}...`); }); } startServer(); // Each worker process: - Connects to MongoDB using mongo.mongoConnect(). - Creates an HTTP server using http.createServer(app), making the Express app handle requests. - Starts listening on PORT, logging the worker process ID. } In simple words: we are checking the CPU cores and threads and listening to the events at each worker process to handle incoming requests, while the master process manages and restarts workers if they fail.- use the "npm run start" command to start the PM2 server in the background, and check the console, where you'll see a forks table, something like this:
Expertise
Project Collection
Pinia.org - A Culinary Hub
Pinia.org offers a seamless culinary experience, enabling users to register, log in, create, and edit recipes, alongside maintaining their personal cooking blogs. The platform fosters a sense of community through recipe sharing, liking, and commenting, enriching the culinary journey for all.
Key Features:
- User-Centric Profiles: Users can customize their profiles, showcase personal recipes, liked dishes, and update their information.
- Recipe and Blogging: Crafting and editing recipes is a breeze, while personal cooking blogs let users share their culinary passion.
- Interactive Recipe Pages: Engaging recipe pages feature images and step-by-step instructions for an immersive cooking experience.
- Content Creation: Create and edit recipes and blog posts seamlessly.