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.
-
Live-Demo: https://develop-testing-1.netlify.app/
-
Production-Live: https://sernitas-care.com/
- π― Project Overview
- β¨ Features
- π Technology Stack
- π Project Structure
- π Getting Started
- π Environment Variables
- π¦ Installation & Setup
- π Running the Project
- π API Endpoints
- π£ Frontend Routes
- π§© Key Components
- βοΈ Core Functionalities
- π Reusing Components
- π Deployment
- π· Keywords
- π Conclusion
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.
- 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
-
Service Information Pages
- Detailed service descriptions (Grundpflege, Behandlungspflege, etc.)
- Service cards with modal views
- Responsive service listings
-
Job Application System
- Comprehensive application form with validation
- Real-time form validation using Zod schema
- Automatic email notifications on submission
-
Contact & Consultation
- Contact form with email notifications
- Home consultation request form
- Callback request functionality
-
Content Management
- Blog system (Pflege-Blog)
- Guide system (Pflege-Ratgeber)
- FAQ section
- Downloads section
- News/Updates section (Aktuelles)
-
About & Information
- Team information
- Company mission (Leitbild)
- Partnership network
- Legal pages (Imprint, Privacy Policy, General Terms)
-
Career Pages
- Career information
- Job application submission (Bewerben)
-
Secure Authentication
- Admin login with bcrypt password hashing
- Session management
-
Application Management
- View all applications
- Update application status
- Delete applications
- View detailed applicant information
- Pagination support
-
Dashboard
- Overview of all applications
- Status filtering
- Search functionality
- 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
- 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
- ESLint 9.9.0 - Code linting
- PostCSS - CSS processing
- Autoprefixer - CSS vendor prefixing
- Docker - Containerization
- Netlify - Frontend hosting
- Coolify/VPS - Backend hosting (Hetzner VPS)
- MongoDB - Database hosting (self-hosted)
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 fileBefore 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
- VS Code - Code editor
- MongoDB Compass - MongoDB GUI (optional)
- Postman or Insomnia - API testing (optional)
The project uses environment variables to manage configuration. Create a .env file in the root directory.
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.comImportant: Only variables prefixed with VITE_ are exposed to the frontend. Never put sensitive data (passwords, secrets) in VITE_ variables.
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=5000To generate a bcrypt hash for ADMIN_PASSWORD_HASH:
- Set
ADMIN_PASSWORDin your.envfile - Run the password hash generator:
node hashPassword.js- Copy the generated hash and update
ADMIN_PASSWORD_HASHin.env
If using Gmail SMTP:
- Enable 2-Factor Authentication on your Google account
- Go to Google App Passwords
- Generate an app password for "Mail"
- Use this app password as
EMAIL_PASS(not your regular Gmail password)
# ============================================
# 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=5000git clone https://github.com/your-username/sernitas-care.git
cd sernitas-care# Install all dependencies (frontend + backend)
npm installThis will install both frontend and backend dependencies, and automatically run prisma generate due to the postinstall script.
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- Install MongoDB locally
- Start MongoDB service
- 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" }]
})- Update
DATABASE_URLin.env
- Create account at MongoDB Atlas
- Create a cluster
- Get connection string
- Update
DATABASE_URLin.env
npm run prisma:generateThis generates the Prisma Client based on prisma/schema.prisma.
For MongoDB, you typically use prisma db push instead of migrations:
npx prisma db pushThis syncs your schema with the database without creating migration files.
# Start the Express.js backend server
npm start
# Or run directly
node server.jsThe backend will run on http://localhost:5000 (or the PORT specified in .env).
Open a new terminal window:
# Start Vite dev server
npm run devThe frontend will run on http://localhost:5173 (Vite default port).
npm run buildThis creates an optimized production build in the dist/ directory.
npm run previewnpm startMake sure NODE_ENV=production is set in your production environment.
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"
}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",
...
}
]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",
...
}Update application status.
URL Parameters:
id- Application ID (MongoDB ObjectId)
Request Body:
{
"status": "Approved"
}Response (200 OK):
{
"id": "507f1f77bcf86cd799439011",
"status": "Approved",
...
}Delete an application.
URL Parameters:
id- Application ID (MongoDB ObjectId)
Response (200 OK):
{
"message": "Application deleted successfully"
}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"
}Send application submission notification email.
Request Body:
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "1234567890",
"age": 34,
"gender": "Male"
}Send home consultation request email.
Request Body:
{
"fullname": "John Doe",
"phone": "1234567890",
"consent": true
}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"
}Send blog comment email.
Request Body:
{
"fullname": "John Doe",
"email": "john@example.com",
"comment": "Great article!"
}Health check endpoint for monitoring.
Response (200 OK):
{
"status": "Healthy",
"service": "Sernitas Care Backend"
}Root endpoint.
Response (200 OK):
Sernitas Care Backend is Running!
The application uses React Router for client-side routing. All routes are defined in src/App.jsx.
/- 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- Admin dashboard (requires authentication)
*- 404 Page Not Found (catch-all route)
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 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 />
</>
);
}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 form component.
Location: src/components/Contact/Contact.jsx
Features:
- Form validation
- Email sending via API
- Success/error feedback
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>;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"
/>;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 dashboard wrapper component.
Location: src/components/Admin/Admin.jsx
Features:
- Login page
- Protected routes
- Dashboard layout
Application management dashboard.
Location: src/components/Admin/AdminDashboard.jsx
Features:
- Application listing
- Status filtering
- Pagination
- Delete functionality
- Status updates
Admin authentication component.
Location: src/components/Admin/AdminLogin.jsx
Features:
- Email/password authentication
- Error handling
- Session management
Image component with caching support.
Location: src/components/CachedImage.jsx
Usage:
import CachedImage from "./components/CachedImage";
<CachedImage src="/path/to/image.jpg" alt="Description" />;Component that scrolls to top on route changes.
Location: src/components/ScrollToTop.jsx
Usage: Automatically used in App.jsx
Loading spinner component.
Location: src/components/Loading/Loading.jsx
Usage:
import Loading from "./components/Loading/Loading";
{
isLoading && <Loading />;
}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
},
});The application uses React Hook Form for form management and Zod for schema validation.
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>
);
}React Query is used for efficient data fetching and caching.
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>;
}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>;
}Prisma provides type-safe database access.
// 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" });
}
});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" });
}
});The application uses Nodemailer to send emails via SMTP.
// 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" });
});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
);The UI components (Button, Input, Textarea) are designed to be reusable.
Copy the component files from src/components/ui/ to your project.
npm install tailwindcss # If using Tailwind CSSimport { 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>
);
}The Zod + React Hook Form pattern can be reused in any React project.
npm install react-hook-form @hookform/resolvers zodimport { z } from "zod";
const MyFormSchema = z.object({
name: z.string().min(2, "Name is required"),
email: z.string().email("Invalid email"),
});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>
);
}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>;
}Prisma can be used in any Node.js project with MongoDB, PostgreSQL, MySQL, etc.
npx prisma init// prisma/schema.prisma
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
email String @unique
}npx prisma generateimport { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const users = await prisma.user.findMany();-
Build the project:
npm run build
-
Configure Netlify:
- Connect your GitHub repository
- Build command:
npm run build - Publish directory:
dist - Add environment variables in Netlify dashboard (only
VITE_prefixed variables)
-
Deploy:
- Netlify will automatically deploy on push to main branch
- Or deploy manually via Netlify CLI
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-backendDeploy to Coolify:
- Push code to GitHub
- Create new application in Coolify
- Connect GitHub repository
- Select Dockerfile as build pack
- Configure environment variables
- Deploy
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
- 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
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
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! π

























