Skip to content

A full-stack web application for managing home nursing care services, built with React and Express.js. This platform provides comprehensive functionality for service management, job applications, contact forms, and an admin dashboard for managing applications.

Notifications You must be signed in to change notification settings

arnobt78/Professional-Home-Nursing-Services-Platform--React-FullStack

Repository files navigation

Sernitas Care | Professional Home Nursing Services Platform - React, Express.js, MongoDB FullStack Project

A full-stack web application for managing home nursing care services, built with React and Express.js. This platform provides comprehensive functionality for service management, job applications, contact forms, and an admin dashboard for managing applications.

Screenshot 2025-06-07 at 02 30 46 Screenshot 2025-07-30 at 12 34 22 Screenshot 2025-07-30 at 12 34 42 Screenshot 2025-07-30 at 12 34 52 Screenshot 2025-07-30 at 12 35 06 Screenshot 2025-07-30 at 12 35 17 Screenshot 2025-07-30 at 12 35 54 Screenshot 2025-07-30 at 12 36 07 Screenshot 2025-07-30 at 12 49 54 Screenshot 2025-07-30 at 12 37 01 Screenshot 2025-07-30 at 12 37 31 Screenshot 2025-07-30 at 12 38 03 Screenshot 2025-07-30 at 12 38 43 Screenshot 2025-07-30 at 12 38 57 Screenshot 2025-07-30 at 12 39 18 Screenshot 2025-07-30 at 12 39 46 Screenshot 2025-07-30 at 12 40 13 Screenshot 2025-07-30 at 12 40 49 Screenshot 2025-07-30 at 12 41 37 Screenshot 2025-07-30 at 12 43 02 Screenshot 2025-07-30 at 12 43 21 Screenshot 2025-07-30 at 12 44 56 Screenshot 2025-07-30 at 12 45 09 Screenshot 2025-07-30 at 12 45 53 Screenshot 2025-07-30 at 12 46 17 Screenshot 2025-07-30 at 12 47 06

πŸ“‹ Table of Contents


🎯 Project Overview

Sernitas Care is a modern, responsive web application designed for a professional home nursing care service provider. The platform enables clients to learn about services, submit job applications, request consultations, and contact the organization. Administrators can manage applications through a secure dashboard.

Key Highlights

  • Modern Frontend: React 18 with Vite for fast development and optimized builds
  • RESTful Backend: Express.js API with MongoDB database
  • Type-Safe Database: Prisma ORM for type-safe database queries
  • Email Notifications: Automated email system using Nodemailer
  • Admin Dashboard: Secure admin panel for managing applications
  • Responsive Design: Mobile-first design with Tailwind CSS
  • Form Validation: Client and server-side validation with Zod
  • State Management: React Query for efficient data fetching and caching

✨ Features

User-Facing Features

  1. Service Information Pages

    • Detailed service descriptions (Grundpflege, Behandlungspflege, etc.)
    • Service cards with modal views
    • Responsive service listings
  2. Job Application System

    • Comprehensive application form with validation
    • Real-time form validation using Zod schema
    • Automatic email notifications on submission
  3. Contact & Consultation

    • Contact form with email notifications
    • Home consultation request form
    • Callback request functionality
  4. Content Management

    • Blog system (Pflege-Blog)
    • Guide system (Pflege-Ratgeber)
    • FAQ section
    • Downloads section
    • News/Updates section (Aktuelles)
  5. About & Information

    • Team information
    • Company mission (Leitbild)
    • Partnership network
    • Legal pages (Imprint, Privacy Policy, General Terms)
  6. Career Pages

    • Career information
    • Job application submission (Bewerben)

Admin Features

  1. Secure Authentication

    • Admin login with bcrypt password hashing
    • Session management
  2. Application Management

    • View all applications
    • Update application status
    • Delete applications
    • View detailed applicant information
    • Pagination support
  3. Dashboard

    • Overview of all applications
    • Status filtering
    • Search functionality

πŸ›  Technology Stack

Frontend

  • React 18.3.1 - UI library
  • Vite 5.4.1 - Build tool and dev server
  • React Router DOM 7.4.1 - Client-side routing
  • TanStack React Query 5.72.2 - Server state management
  • Tailwind CSS 3.4.12 - Utility-first CSS framework
  • Framer Motion 11.18.2 - Animation library
  • React Hook Form 7.55.0 - Form handling
  • Zod 3.24.2 - Schema validation
  • Axios 1.8.4 - HTTP client (optional, fetch API also used)
  • React Icons 5.3.0 - Icon library

Backend

  • Node.js 20+ - Runtime environment
  • Express.js 5.1.0 - Web framework
  • MongoDB - NoSQL database
  • Prisma 6.6.0 - ORM for database access
  • Nodemailer 6.10.0 - Email sending
  • bcrypt 5.1.1 - Password hashing
  • CORS 2.8.5 - Cross-origin resource sharing
  • dotenv 16.4.7 - Environment variable management

Development Tools

  • ESLint 9.9.0 - Code linting
  • PostCSS - CSS processing
  • Autoprefixer - CSS vendor prefixing

Deployment

  • Docker - Containerization
  • Netlify - Frontend hosting
  • Coolify/VPS - Backend hosting (Hetzner VPS)
  • MongoDB - Database hosting (self-hosted)

πŸ“ Project Structure

sernitas-care/
β”œβ”€β”€ src/                          # Frontend source code
β”‚   β”œβ”€β”€ components/               # React components
β”‚   β”‚   β”œβ”€β”€ AboutUs/             # About us page components
β”‚   β”‚   β”œβ”€β”€ Accordion/           # Accordion component
β”‚   β”‚   β”œβ”€β”€ Admin/               # Admin dashboard components
β”‚   β”‚   β”œβ”€β”€ ApplicationForm/     # Job application form
β”‚   β”‚   β”œβ”€β”€ Cards/               # Service cards
β”‚   β”‚   β”œβ”€β”€ Contact/             # Contact form
β”‚   β”‚   β”œβ”€β”€ Footer/              # Footer components
β”‚   β”‚   β”œβ”€β”€ HomePage/            # Homepage sections
β”‚   β”‚   β”œβ”€β”€ Karriere/            # Career pages
β”‚   β”‚   β”œβ”€β”€ Navbar/              # Navigation bar
β”‚   β”‚   β”œβ”€β”€ ServicesPage/        # Service pages
β”‚   β”‚   β”œβ”€β”€ TestimonialSection/  # Testimonials
β”‚   β”‚   β”œβ”€β”€ ui/                  # Reusable UI components
β”‚   β”‚   └── WissenswertesPage/   # Knowledge/Info pages
β”‚   β”œβ”€β”€ assets/                  # Static assets (images, icons)
β”‚   β”œβ”€β”€ App.jsx                  # Main app component with routes
β”‚   β”œβ”€β”€ main.jsx                 # Application entry point
β”‚   β”œβ”€β”€ reactQueryClient.js      # React Query configuration
β”‚   β”œβ”€β”€ index.css                # Global styles
β”‚   └── utility/                 # Utility functions
β”œβ”€β”€ server/                      # Backend source code
β”‚   β”œβ”€β”€ applicationRoutes.js     # Application CRUD endpoints
β”‚   └── emailRoutes.js           # Email sending endpoints
β”œβ”€β”€ prisma/                      # Database schema
β”‚   └── schema.prisma            # Prisma schema definition
β”œβ”€β”€ public/                      # Public static files
β”œβ”€β”€ dist/                        # Build output (generated)
β”œβ”€β”€ node_modules/                # Dependencies (generated)
β”œβ”€β”€ .env                         # Environment variables (create this)
β”œβ”€β”€ .env.example                 # Example env file (if exists)
β”œβ”€β”€ Dockerfile                   # Docker configuration
β”œβ”€β”€ netlify.toml                 # Netlify deployment config
β”œβ”€β”€ package.json                 # Dependencies and scripts
β”œβ”€β”€ vite.config.js               # Vite configuration
β”œβ”€β”€ tailwind.config.js           # Tailwind CSS configuration
└── README.md                    # This file

πŸš€ Getting Started

Prerequisites

Before you begin, ensure you have the following installed:

  • Node.js (v20 or higher) - Download
  • npm (comes with Node.js) or yarn
  • MongoDB (local or remote instance)
  • Git - Download

Recommended Tools

  • VS Code - Code editor
  • MongoDB Compass - MongoDB GUI (optional)
  • Postman or Insomnia - API testing (optional)

πŸ” Environment Variables

The project uses environment variables to manage configuration. Create a .env file in the root directory.

Frontend Environment Variables (VITE_ prefix)

These variables are accessible in the browser and must be prefixed with VITE_:

# Frontend API URLs
VITE_API_BASE_URL_LOCAL=http://localhost:5000
VITE_API_BASE_URL_RENDER=https://your-backend-url.com

Important: Only variables prefixed with VITE_ are exposed to the frontend. Never put sensitive data (passwords, secrets) in VITE_ variables.

Backend Environment Variables (No VITE_ prefix)

These are server-side only and should never be prefixed with VITE_:

# Database Configuration
DATABASE_URL="mongodb://username:password@host:port/database?authSource=database&replicaSet=rs0"

# Email Configuration (SMTP)
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false

# HR Email (receives notifications)
HR_USER=hr-email@gmail.com

# Admin Configuration
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your-secure-password
ADMIN_PASSWORD_HASH=$2b$10$...your-bcrypt-hash...

# JWT Secret (for future authentication)
JWT_SECRET=your-very-long-random-secret-string

# Server Port (optional, defaults to 5000)
PORT=5000

Generating Password Hash

To generate a bcrypt hash for ADMIN_PASSWORD_HASH:

  1. Set ADMIN_PASSWORD in your .env file
  2. Run the password hash generator:
node hashPassword.js
  1. Copy the generated hash and update ADMIN_PASSWORD_HASH in .env

Gmail App Password Setup

If using Gmail SMTP:

  1. Enable 2-Factor Authentication on your Google account
  2. Go to Google App Passwords
  3. Generate an app password for "Mail"
  4. Use this app password as EMAIL_PASS (not your regular Gmail password)

Complete .env Example

# ============================================
# FRONTEND ENVIRONMENT VARIABLES (VITE_ prefix)
# ============================================
VITE_API_BASE_URL_LOCAL=http://localhost:5000
VITE_API_BASE_URL_RENDER=https://your-backend-url.com

# ============================================
# BACKEND ENVIRONMENT VARIABLES (No VITE_ prefix)
# ============================================

# Database Connection
DATABASE_URL="mongodb://user:password@localhost:27017/sernitas_care_db?authSource=sernitas_care_db&replicaSet=rs0"

# Email Configuration
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false

HR_USER=hr-email@gmail.com

# Admin Configuration
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your-secure-password
ADMIN_PASSWORD_HASH=$2b$10$generated-hash-here

JWT_SECRET=your-very-long-random-secret-string

PORT=5000

πŸ“¦ Installation & Setup

1. Clone the Repository

git clone https://github.com/your-username/sernitas-care.git
cd sernitas-care

2. Install Dependencies

# Install all dependencies (frontend + backend)
npm install

This will install both frontend and backend dependencies, and automatically run prisma generate due to the postinstall script.

3. Set Up Environment Variables

Create a .env file in the root directory:

# Copy the example (if available) or create manually
cp .env.example .env  # If .env.example exists
# Or create .env manually with the variables from the Environment Variables section

4. Set Up MongoDB

Option A: Local MongoDB

  1. Install MongoDB locally
  2. Start MongoDB service
  3. Create database and user:
mongosh
use sernitas_care_db
db.createUser({
  user: "sernitas_care_user",
  pwd: "your-password",
  roles: [{ role: "readWrite", db: "sernitas_care_db" }]
})
  1. Update DATABASE_URL in .env

Option B: MongoDB Atlas (Cloud)

  1. Create account at MongoDB Atlas
  2. Create a cluster
  3. Get connection string
  4. Update DATABASE_URL in .env

5. Generate Prisma Client

npm run prisma:generate

This generates the Prisma Client based on prisma/schema.prisma.

6. Push Prisma Schema to Database (Optional)

For MongoDB, you typically use prisma db push instead of migrations:

npx prisma db push

This syncs your schema with the database without creating migration files.


πŸƒ Running the Project

Development Mode

Start Backend Server

# Start the Express.js backend server
npm start

# Or run directly
node server.js

The backend will run on http://localhost:5000 (or the PORT specified in .env).

Start Frontend Development Server

Open a new terminal window:

# Start Vite dev server
npm run dev

The frontend will run on http://localhost:5173 (Vite default port).

Production Build

Build Frontend

npm run build

This creates an optimized production build in the dist/ directory.

Preview Production Build

npm run preview

Run Backend in Production

npm start

Make sure NODE_ENV=production is set in your production environment.


πŸ”Œ API Endpoints

Application Endpoints

POST /api/admin/login

Admin authentication endpoint.

Request Body:

{
  "email": "admin@example.com",
  "password": "your-password"
}

Response (200 OK):

{
  "message": "Login successful"
}

Response (401 Unauthorized):

{
  "error": "Invalid email or password"
}

GET /api/applications

Fetch all job applications.

Response (200 OK):

[
  {
    "id": "507f1f77bcf86cd799439011",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "status": "Pending",
    "createdAt": "2024-01-15T10:30:00.000Z",
    ...
  }
]

POST /api/applications

Create a new job application.

Request Body:

{
  "firstName": "John",
  "lastName": "Doe",
  "birthDate": "1990-01-01",
  "gender": "Male",
  "email": "john@example.com",
  "telephone": "1234567890",
  "streetName": "Main Street",
  "houseNumber": "123",
  "postalCode": "12345",
  "city": "Berlin",
  "occupation": "Nurse",
  "emergencyContactName": "Jane Doe",
  "emergencyContactNumber": "0987654321",
  "identificationType": "Passport",
  "privacyConsent": true
}

Response (201 Created):

{
  "id": "507f1f77bcf86cd799439011",
  "firstName": "John",
  "lastName": "Doe",
  "status": "Pending",
  "createdAt": "2024-01-15T10:30:00.000Z",
  ...
}

PATCH /api/applications/:id/status

Update application status.

URL Parameters:

  • id - Application ID (MongoDB ObjectId)

Request Body:

{
  "status": "Approved"
}

Response (200 OK):

{
  "id": "507f1f77bcf86cd799439011",
  "status": "Approved",
  ...
}

DELETE /api/applications/:id

Delete an application.

URL Parameters:

  • id - Application ID (MongoDB ObjectId)

Response (200 OK):

{
  "message": "Application deleted successfully"
}

Email Endpoints

POST /api/send-email

Send contact form email.

Request Body:

{
  "fullname": "John Doe",
  "email": "john@example.com",
  "phone": "1234567890",
  "message": "Hello, I'm interested in your services."
}

Response (200 OK):

{
  "message": "Email sent successfully to both recipients"
}

POST /api/send-application-notification

Send application submission notification email.

Request Body:

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john@example.com",
  "phone": "1234567890",
  "age": 34,
  "gender": "Male"
}

POST /api/send-home-consultation-email

Send home consultation request email.

Request Body:

{
  "fullname": "John Doe",
  "phone": "1234567890",
  "consent": true
}

POST /api/send-job-application

Send job application email.

Request Body:

{
  "firstname": "John",
  "lastname": "Doe",
  "gender": "Male",
  "degree": "Bachelor",
  "company": "Company Name",
  "country": "Germany",
  "email": "john@example.com",
  "phone": "1234567890",
  "linkedin": "linkedin.com/in/johndoe",
  "subject": "Application Subject",
  "message": "Application message"
}

POST /api/send-comment

Send blog comment email.

Request Body:

{
  "fullname": "John Doe",
  "email": "john@example.com",
  "comment": "Great article!"
}

Health Check Endpoint

GET /health

Health check endpoint for monitoring.

Response (200 OK):

{
  "status": "Healthy",
  "service": "Sernitas Care Backend"
}

GET /

Root endpoint.

Response (200 OK):

Sernitas Care Backend is Running!

πŸ›£ Frontend Routes

The application uses React Router for client-side routing. All routes are defined in src/App.jsx.

Public Routes

  • / - Homepage
  • /services/* - Services pages (nested routes)
    • /services/grundpflege - Basic care services
    • /services/behandlungspflege - Treatment care services
    • /services/verhinderungspflege - Respite care services
    • /services/betreuung-entlastung - Support and relief services
    • /services/rufbereitschaft - 24-hour emergency service
  • /about-us/* - About us pages (nested routes)
    • /about-us/wir-sind-sernitas - Who we are
    • /about-us/team - Team information
    • /about-us/leitbild - Mission statement
    • /about-us/kooperationsnetzwerk - Partnership network
    • /about-us/mitgliedschaft-bap - BAP membership
  • /wissenswertes/* - Information pages (nested routes)
    • /wissenswertes/faq - Frequently asked questions
    • /wissenswertes/aktuelles - News and updates
    • /wissenswertes/pflege-blog - Care blog
    • /wissenswertes/pflege-ratgeber - Care guide
    • /wissenswertes/downloads - Downloads
  • /pflege-ratgeber - Care guide listing
  • /pflege-ratgeber/:id - Individual care guide article
  • /pflege-blog - Blog listing
  • /pflege-blog/:id - Individual blog post
  • /contact - Contact form
  • /application-form - Job application form
  • /karriere - Career information
  • /karriere/bewerben - Job application page
  • /imprint - Legal imprint
  • /privacy-policy - Privacy policy
  • /general-terms - General terms and conditions

Admin Routes

  • /admin - Admin dashboard (requires authentication)

Error Routes

  • * - 404 Page Not Found (catch-all route)

🧩 Key Components

Layout Components

Navbar

Main navigation component with dropdown menus.

Location: src/components/Navbar/Navbar.jsx

Features:

  • Responsive design (mobile hamburger menu)
  • Dropdown navigation for services, about us, and information sections
  • Active route highlighting
  • Smooth scroll behavior

Usage:

import Navbar from "./components/Navbar/Navbar";

function App() {
  return (
    <>
      <Navbar />
      {/* Other content */}
    </>
  );
}

Footer

Footer component with links and partner information.

Location: src/components/Footer/Footer.jsx

Features:

  • Partner logos section
  • Affiliate links
  • Legal page links
  • Social media links

Usage:

import Footer from "./components/Footer/Footer";

function App() {
  return (
    <>
      {/* Main content */}
      <Footer />
    </>
  );
}

Form Components

ApplicationForm

Comprehensive job application form with validation.

Location: src/components/ApplicationForm/ApplicationForm.jsx

Features:

  • Zod schema validation
  • React Hook Form integration
  • Multi-step form fields
  • Success/error messaging
  • Automatic email notifications
  • Database persistence

Usage:

import ApplicationForm from "./components/ApplicationForm/ApplicationForm";

function ApplicationPage() {
  return <ApplicationForm />;
}

Validation Schema Example:

const ApplicationFormSchema = z.object({
  firstName: z.string().min(2, "Vorname muss mindestens 2 Zeichen lang sein"),
  lastName: z.string().min(2, "Nachname muss mindestens 2 Zeichen lang sein"),
  email: z.string().email("UngΓΌltige E-Mail-Adresse"),
  telephone: z
    .string()
    .regex(/^\d+$/, "Telefonnummer darf nur Ziffern enthalten"),
  privacyConsent: z.boolean().refine((val) => val, {
    message: "Sie mΓΌssen der DatenschutzerklΓ€rung zustimmen",
  }),
});

Contact

Contact form component.

Location: src/components/Contact/Contact.jsx

Features:

  • Form validation
  • Email sending via API
  • Success/error feedback

UI Components

Button

Reusable button component.

Location: src/components/ui/button.jsx

Usage:

import { Button } from "./components/ui/button";

<Button type="submit" className="custom-class" disabled={isLoading}>
  Submit
</Button>;

Input

Reusable input component.

Location: src/components/ui/input.jsx

Usage:

import { Input } from "./components/ui/input";

<Input
  type="text"
  placeholder="Enter text"
  {...register("fieldName")}
  className="custom-class"
/>;

Textarea

Reusable textarea component.

Location: src/components/ui/textarea.jsx

Usage:

import { Textarea } from "./components/ui/textarea";

<Textarea placeholder="Enter message" {...register("message")} rows={5} />;

Admin Components

Admin

Admin dashboard wrapper component.

Location: src/components/Admin/Admin.jsx

Features:

  • Login page
  • Protected routes
  • Dashboard layout

AdminDashboard

Application management dashboard.

Location: src/components/Admin/AdminDashboard.jsx

Features:

  • Application listing
  • Status filtering
  • Pagination
  • Delete functionality
  • Status updates

AdminLogin

Admin authentication component.

Location: src/components/Admin/AdminLogin.jsx

Features:

  • Email/password authentication
  • Error handling
  • Session management

Utility Components

CachedImage

Image component with caching support.

Location: src/components/CachedImage.jsx

Usage:

import CachedImage from "./components/CachedImage";

<CachedImage src="/path/to/image.jpg" alt="Description" />;

ScrollToTop

Component that scrolls to top on route changes.

Location: src/components/ScrollToTop.jsx

Usage: Automatically used in App.jsx


Loading

Loading spinner component.

Location: src/components/Loading/Loading.jsx

Usage:

import Loading from "./components/Loading/Loading";

{
  isLoading && <Loading />;
}

Custom Hooks

usePersistedQuery

Custom React Query hook with localStorage persistence.

Location: src/components/usePersistedQuery.js

Usage:

import { usePersistedQuery } from "./components/usePersistedQuery";

const { data, isLoading, error } = usePersistedQuery({
  queryKey: ["applications"],
  queryFn: async () => {
    const response = await fetch(`${apiBaseUrl}/api/applications`);
    if (!response.ok) throw new Error("Failed to fetch");
    return response.json();
  },
  options: {
    staleTime: 1000 * 60 * 5, // 5 minutes
  },
});

βš™οΈ Core Functionalities

Form Handling with React Hook Form + Zod

The application uses React Hook Form for form management and Zod for schema validation.

Example: Contact Form

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const ContactSchema = z.object({
  fullname: z.string().min(2, "Name is required"),
  email: z.string().email("Invalid email"),
  message: z.string().min(10, "Message must be at least 10 characters"),
});

function ContactForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: zodResolver(ContactSchema),
  });

  const onSubmit = async (data) => {
    // Handle form submission
    const response = await fetch("/api/send-email", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("fullname")} />
      {errors.fullname && <p>{errors.fullname.message}</p>}
      {/* More fields */}
    </form>
  );
}

Data Fetching with React Query

React Query is used for efficient data fetching and caching.

Example: Fetching Applications

import { useQuery } from "@tanstack/react-query";

function AdminDashboard() {
  const apiBaseUrl = import.meta.env.VITE_API_BASE_URL_RENDER;

  const { data, isLoading, error, refetch } = useQuery({
    queryKey: ["applications"],
    queryFn: async () => {
      const response = await fetch(`${apiBaseUrl}/api/applications`);
      if (!response.ok) throw new Error("Failed to fetch");
      return response.json();
    },
    staleTime: 1000 * 60 * 5, // Cache for 5 minutes
  });

  if (isLoading) return <Loading />;
  if (error) return <div>Error: {error.message}</div>;

  return <div>{/* Render applications */}</div>;
}

Mutations with React Query

For creating, updating, or deleting data:

import { useMutation, useQueryClient } from "@tanstack/react-query";

function ApplicationForm() {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: async (data) => {
      const response = await fetch("/api/applications", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
      });
      if (!response.ok) throw new Error("Failed to submit");
      return response.json();
    },
    onSuccess: () => {
      // Invalidate and refetch applications
      queryClient.invalidateQueries({ queryKey: ["applications"] });
    },
  });

  const onSubmit = (data) => {
    mutation.mutate(data);
  };

  return <form onSubmit={handleSubmit(onSubmit)}>{/* Form fields */}</form>;
}

Database Operations with Prisma

Prisma provides type-safe database access.

Example: Creating an Application

// server/applicationRoutes.js
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

router.post("/api/applications", async (req, res) => {
  try {
    const application = await prisma.application.create({
      data: {
        ...req.body,
        status: "Pending",
      },
    });
    res.status(201).json(application);
  } catch (error) {
    res.status(500).json({ error: "Failed to save application" });
  }
});

Example: Fetching All Applications

router.get("/api/applications", async (req, res) => {
  try {
    const applications = await prisma.application.findMany({
      orderBy: { createdAt: "desc" },
    });
    res.status(200).json(applications);
  } catch (error) {
    res.status(500).json({ error: "Failed to fetch applications" });
  }
});

Email Sending with Nodemailer

The application uses Nodemailer to send emails via SMTP.

Example: Sending Email

// server/emailRoutes.js
import nodemailer from "nodemailer";

router.post("/api/send-email", async (req, res) => {
  const { fullname, email, phone, message } = req.body;

  // Configure transporter
  let transporter = nodemailer.createTransport({
    host: process.env.SMTP_HOST,
    port: process.env.SMTP_PORT,
    secure: process.env.SMTP_SECURE === "true",
    auth: {
      user: process.env.EMAIL_USER,
      pass: process.env.EMAIL_PASS,
    },
  });

  // Email options
  const mailOptions = {
    from: `"Sernitas Care" <${process.env.EMAIL_USER}>`,
    to: `${process.env.EMAIL_USER}, ${process.env.HR_USER}`,
    subject: `New Message from ${fullname}`,
    text: `Name: ${fullname}\nEmail: ${email}\nPhone: ${phone}\nMessage: ${message}`,
  };

  // Send email
  await transporter.sendMail(mailOptions);
  res.status(200).json({ message: "Email sent successfully" });
});

Password Hashing with bcrypt

Admin passwords are hashed using bcrypt for security.

Generating Hash:

// hashPassword.js
import bcrypt from "bcrypt";

const password = process.env.ADMIN_PASSWORD;
const saltRounds = 10;

bcrypt.hash(password, saltRounds, (err, hash) => {
  console.log(hash); // Use this in ADMIN_PASSWORD_HASH
});

Verifying Password:

// server/applicationRoutes.js
import bcrypt from "bcrypt";

const isPasswordValid = await bcrypt.compare(
  password,
  process.env.ADMIN_PASSWORD_HASH
);

πŸ”„ Reusing Components

Using UI Components in Other Projects

The UI components (Button, Input, Textarea) are designed to be reusable.

Step 1: Copy Component Files

Copy the component files from src/components/ui/ to your project.

Step 2: Install Dependencies

npm install tailwindcss  # If using Tailwind CSS

Step 3: Import and Use

import { Button } from "./components/ui/button";
import { Input } from "./components/ui/input";

function MyForm() {
  return (
    <form>
      <Input type="text" placeholder="Enter name" />
      <Button type="submit">Submit</Button>
    </form>
  );
}

Using Form Validation Pattern

The Zod + React Hook Form pattern can be reused in any React project.

Step 1: Install Dependencies

npm install react-hook-form @hookform/resolvers zod

Step 2: Create Validation Schema

import { z } from "zod";

const MyFormSchema = z.object({
  name: z.string().min(2, "Name is required"),
  email: z.string().email("Invalid email"),
});

Step 3: Use in Component

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: zodResolver(MyFormSchema),
  });

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name")} />
      {errors.name && <p>{errors.name.message}</p>}
      <button type="submit">Submit</button>
    </form>
  );
}

Using React Query Pattern

React Query can be used for any data fetching needs.

Basic Setup:

// reactQueryClient.js
import { QueryClient } from "@tanstack/react-query";

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5,
      cacheTime: 1000 * 60 * 5,
    },
  },
});

Using in Components:

import { useQuery } from "@tanstack/react-query";

function DataComponent() {
  const { data, isLoading } = useQuery({
    queryKey: ["data"],
    queryFn: fetchData,
  });

  if (isLoading) return <div>Loading...</div>;
  return <div>{/* Render data */}</div>;
}

Using Prisma ORM Pattern

Prisma can be used in any Node.js project with MongoDB, PostgreSQL, MySQL, etc.

Step 1: Initialize Prisma

npx prisma init

Step 2: Define Schema

// prisma/schema.prisma
model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  name  String
  email String @unique
}

Step 3: Generate Client

npx prisma generate

Step 4: Use in Code

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const users = await prisma.user.findMany();

πŸš€ Deployment

Frontend Deployment (Netlify)

  1. Build the project:

    npm run build
  2. Configure Netlify:

    • Connect your GitHub repository
    • Build command: npm run build
    • Publish directory: dist
    • Add environment variables in Netlify dashboard (only VITE_ prefixed variables)
  3. Deploy:

    • Netlify will automatically deploy on push to main branch
    • Or deploy manually via Netlify CLI

Backend Deployment (Docker/Coolify)

The project includes a Dockerfile for containerized deployment.

Build Docker Image:

docker build -t sernitas-care-backend .

Run Container:

docker run -p 5000:5000 --env-file .env sernitas-care-backend

Deploy to Coolify:

  1. Push code to GitHub
  2. Create new application in Coolify
  3. Connect GitHub repository
  4. Select Dockerfile as build pack
  5. Configure environment variables
  6. Deploy

Environment Variables in Production

Frontend (Netlify):

  • Only add VITE_ prefixed variables
  • Do NOT add backend secrets

Backend (Coolify/VPS):

  • Add all backend environment variables
  • Do NOT prefix with VITE_
  • Keep sensitive data secure

🏷 Keywords

  • React
  • Express.js
  • MongoDB
  • Prisma
  • Full-stack
  • Web application
  • Home nursing care
  • Job application system
  • Admin dashboard
  • Email notifications
  • Form validation
  • React Query
  • Tailwind CSS
  • Vite
  • Docker
  • RESTful API
  • Type-safe database
  • Responsive design
  • German healthcare
  • Pflegedienst

πŸ“ Conclusion

Sernitas Care is a comprehensive full-stack web application demonstrating modern web development practices. It combines a responsive React frontend with a robust Express.js backend, showcasing:

  • Modern React Patterns: Hooks, context, custom hooks, error boundaries
  • Form Management: React Hook Form with Zod validation
  • State Management: React Query for server state
  • Database Integration: Prisma ORM with MongoDB
  • Email Functionality: Nodemailer for automated emails
  • Security: Password hashing, environment variables, CORS
  • Deployment: Docker containerization, CI/CD ready

This project serves as an excellent learning resource for understanding:

  • Full-stack JavaScript development
  • React best practices
  • RESTful API design
  • Database modeling with Prisma
  • Email integration
  • Form validation patterns
  • Production deployment strategies

Happy Coding! πŸŽ‰

Feel free to use this project repository and extend this project further!

If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://arnob-mahmud.vercel.app/.

Enjoy building and learning! πŸš€

Thank you! 😊


About

A full-stack web application for managing home nursing care services, built with React and Express.js. This platform provides comprehensive functionality for service management, job applications, contact forms, and an admin dashboard for managing applications.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages