React 18 Node.js & Express PostgreSQL JWT Auth

CLARES

Compliance License & Asset Reminder Engine System

A full-stack web portal for tracking and managing expiry dates of SSL certificates, licenses, certificates, and any custom asset type — with smart automated email reminders that calculate exact send dates based on per-item settings.

Core Features

Everything you need to stay on top of compliance deadlines, licenses, and certificate renewals.

📊

Smart Dashboard

Grouped urgency sections — Expired, Critical ≤14d, Warning ≤30d, and Upcoming ≤90d — with summary stat cards per catalog type. Auto-refreshes on load.

📚

Flexible Catalogs

Built-in types for Certificates, Licenses, and SSL Certs. Add unlimited custom catalog types from the sidebar. Catalog-level admins can manage entries without being global admins.

📧

Smart Email Reminders

Per-item reminder settings: toggle, days-before, and repeat count. The system calculates exact send dates by evenly spacing repeats (e.g. 30 days / 3 repeats = reminders at 30, 20, and 10 days before expiry). Emails show “reminder 2 of 3” for clarity.

Automatic Daily Scheduler

Enable automatic reminders from Admin Settings. A background scheduler fires daily at the configured hour (server time). A reminder_logs table prevents duplicates. Missed reminders are caught up automatically on the next run.

👥

User & Permission Management

Create user accounts with Admin or Viewer roles. Per-catalog permission matrix: No Access, View, or Admin. Activate/deactivate accounts with clear login messages.

📄

Bulk CSV Upload

Download a CSV template, fill in your data, and upload up to 500 rows at once. Perfect for initial data migration or batch imports.

🔒

Secure by Default

JWT authentication with 8-hour expiry. Passwords hashed with bcrypt. Role-based access control on every API endpoint. Case-insensitive login. Inactive account detection.

Dashboard at a Glance

Instantly see which items need attention across all your catalogs.

⚠ Expired
Items past their expiry date
⏱ Critical
Expiring within 14 days
⚠️ Warning
Expiring within 30 days
📅 Upcoming
Expiring within 90 days

How It Works

A simple, secure workflow from login to email reminders.

1

Authenticate

Users log in with username and password. The server validates credentials, checks if the account is active, and issues a JWT token (8h expiry) stored in browser session storage. Deactivated accounts receive a clear error message.

2

Dashboard Overview

On login, the Dashboard automatically fetches all renewal items and groups them by urgency: Expired, Critical (≤14d), Warning (≤30d), and Upcoming (≤90d). Summary cards show counts per catalog.

3

Manage Catalogs

The sidebar lists catalogs the user can access. Click a catalog to view, add, edit, or delete entries. Users with catalog-level Admin permission can manage entries without being global admins. Bulk CSV upload supports up to 500 rows.

4

Granular Permissions

Global admins see everything. Other users are assigned per-catalog roles: No Access, View (read-only), or Admin (full CRUD). Permissions are enforced on both the frontend UI and every backend API call.

5

Configure Email

Admins set up SMTP on the settings page (host, port, TLS, credentials, sender). Test Connection verifies the config and Send Test Email confirms end-to-end delivery before going live.

6

Automated & Manual Reminders

Each item has its own reminder config: days before expiry and repeat count. The system calculates exact send dates by evenly spacing repeats within the window (e.g. 30 days / 3 repeats → days 30, 20, 10 before expiry). Admins can trigger reminders manually, or enable the automatic daily scheduler which fires at a configurable hour. A reminder_logs table prevents duplicate sends and catches up missed reminders.

Architecture

A clean separation between the React frontend, Express API, and PostgreSQL database.

🎨 React 18
Vite + React Router v6
⚙ Express API
Node.js + JWT
🗃 PostgreSQL
Azure / Local
📧 Nodemailer
SMTP Email
⚙ Express API
Reminder Engine

Tech Stack

Modern, battle-tested technologies powering every layer.

React 18
Frontend UI
Vite
Build Tool
🔌
React Router v6
Client Routing
🔷
Node.js
Runtime
🚀
Express 4
API Framework
🗃
PostgreSQL
Database (Azure)
🔒
JWT + bcrypt
Authentication
📧
Nodemailer
Email Delivery

API Endpoints

RESTful API with role-based access control on every route.

MethodEndpointAuthDescription
POST /api/auth/login Public Login, returns JWT
GET /api/renewals Required All renewals
GET /api/renewals/type/:type Required Renewals by catalog type
POST /api/renewals Admin Create renewal
PUT /api/renewals/:id Admin Update renewal
DELETE /api/renewals/:id Admin Delete renewal
POST /api/renewals/bulk Admin Bulk create (max 500 rows)
GET /api/catalog-types Required List catalog types
POST /api/catalog-types Admin Add custom catalog type
DELETE /api/catalog-types/:slug Admin Delete custom catalog type
GET /api/admin/smtp Admin Get SMTP config
PUT /api/admin/smtp Admin Save SMTP config
POST /api/admin/smtp/test Admin Test SMTP connection
POST /api/admin/smtp/test-email Admin Send test email
POST /api/admin/send-reminders Admin Send email reminders
GET /api/admin/users Admin List users
POST /api/admin/users Admin Create user
PUT /api/admin/users/:id Admin Update user
GET /api/admin/users/:id/permissions Admin Get user catalog permissions
PUT /api/admin/users/:id/permissions Admin Set user catalog permissions

Getting Started

Up and running in under five minutes.

1

Clone & Install

Clone the repository and install dependencies.

git clone https://github.com/DevOpsArts/clares.git cd clares npm install
2

Configure Environment

Create a .env file with your PostgreSQL, JWT, and SMTP settings.

PGHOST=your-db-host PGDATABASE=your-database JWT_SECRET=your_secret_key PORT=3002
3

Set Up Database

Run the idempotent migration script. It creates all tables and seeds a default admin user (admin / admin).

npm run setup-db # Default login → admin / admin # Change the password after first login!
4

Start Development

Launch both frontend and backend in parallel.

npm run dev # Frontend → localhost:5174 # API → localhost:3002

Deployment

Docker & Helm for production-ready Kubernetes deployments.

💫

Docker

Multi-stage Dockerfile: Stage 1 builds the React frontend with Vite, Stage 2 runs Express with production dependencies. Supports multi-arch (amd64/arm64).

# Build & run locally docker build -t clares-engine . docker run -p 3002:3002 --env-file .env clares-engine # Multi-arch push to registry docker buildx build --platform linux/amd64,linux/arm64 \ -t devopsart1/clares-engine:latest --push .

Helm Chart

Full Helm chart at helm/clares-engine/ with Deployment, Service, ConfigMap, Secret, and optional Ingress templates.

# Fresh install (minikube) helm install clares ./helm/clares-engine \ -f ./helm/clares-engine/values-minikube.yaml \ --namespace clares --create-namespace # Upgrade to new version helm upgrade clares ./helm/clares-engine \ --set image.tag=v1.0.18 \ --namespace clares

Helm Chart Structure

helm/clares-engine/
├── Chart.yaml              # Chart metadata
├── values.yaml             # Default config
├── values-minikube.yaml    # Local dev overrides
├── values-prod.yaml        # Production overrides
└── templates/
    ├── configmap.yaml       # DB_HOST, DB_PORT, SSL_MODE, etc.
    ├── secret.yaml          # DB_PASSWORD, JWT_SECRET
    ├── deployment.yaml      # App pods
    ├── service.yaml         # ClusterIP service
    └── ingress.yaml         # Optional ingress

Key Helm Values

image.repository: devopsart1/clares-engine image.tag: v1.0.18 env.DB_HOST: your-db-host env.DB_NAME: clares env.SSL_MODE: "true" env.JWT_EXPIRES_IN: "8h" secrets.DB_PASSWORD: your-password secrets.JWT_SECRET: your-secret
🗃

PostgreSQL on K8s

For local dev, deploy PostgreSQL via Bitnami:

helm repo add bitnami https://charts.bitnami.com/bitnami helm install clares-postgres bitnami/postgresql \ --set auth.database=clares \ --set auth.username=clares \ --namespace clares
🛠

Initialize Database

After first install, create tables & seed admin user (admin / admin):

# Wait for pod to be ready kubectl rollout status deployment/clares-clares-engine \ -n clares # Create tables & seed admin kubectl exec deployment/clares-clares-engine \ -n clares -- node server/setup.js

Only needed on first install. Safe to re-run (idempotent).

🌐

Access Locally

# Port-forward kubectl port-forward svc/clares-clares-engine \ 3002:80 -n clares # Open http://localhost:3002 # Or use minikube service minikube service clares-clares-engine -n clares

Project Structure

Clean separation of frontend and backend concerns.

├── index.html
├── package.json
├── vite.config.js
│
├── server/                     # Express API
│   ├── index.js                # Entry point
│   ├── db.js                   # PostgreSQL pool
│   ├── setup.js                # DB migration script
│   ├── middleware/
│   │   ├── authenticate.js     # JWT verification
│   │   └── requireAdmin.js     # Admin-only guard
│   └── routes/
│       ├── auth.js             # Login / profile
│       ├── renewals.js         # CRUD + bulk import
│       ├── catalog-types.js    # Catalog categories
│       └── admin.js            # SMTP, reminders, users
│
└── src/                        # React frontend
    ├── main.jsx
    ├── App.jsx                 # Route definitions
    ├── components/
    │   ├── ClaresLogo.jsx      # Shield logo SVG
    │   ├── Layout.jsx          # App shell
    │   ├── Sidebar.jsx         # Left navigation
    │   ├── Login.jsx           # Login page
    │   └── ProtectedRoute.jsx  # Auth guard
    ├── pages/
    │   ├── HomePage.jsx        # Dashboard
    │   ├── CatalogPage.jsx     # Per-catalog CRUD
    │   ├── AdminPage.jsx       # SMTP + reminders
    │   └── UserManagementPage.jsx
    └── services/
        └── api.js              # API client