Skip to content

Latest commit

 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AENS — Automated Email Notification System

Schedule an email once, at exactly the time you want it sent. A background worker watches for due emails, sends them, retries automatically on failure, and keeps a full delivery audit trail — no manual cron jobs, no babysitting.

  • API: Node.js / Express, Postgres, JWT auth, node-cron-driven delivery (no Bull/job-queue library — Redis here is caching/rate-limiting only, not the queue)
  • Customer app: Next.js (App Router, JavaScript), Tailwind + shadcn/ui, Framer Motion
  • Admin console: a completely separate, standalone Next.js app for internal staff — own codebase, own container, own login, own session cookie; it never shares state with the customer app and only ever talks to the API
  • Caching: Redis — cache-aside reads (user profiles, stats), Redis-backed rate limiting, refresh-token hash lookups
  • API docs: Swagger UI at /api-docs (local dev only, gated behind an explicit env flag)
  • Analytics: self-hosted Umami, privacy-friendly, its own database
  • Reverse proxy: nginx in front of everything — one port (80), routes by hostname, and is what makes the API's trust proxy setting trustworthy instead of spoofable
  • Runs on: Docker Compose — Postgres, Redis, the API, the worker, both frontends, Umami, and nginx all start with one command

Quickstart

cp server/.env.example server/.env   # set JWT_SECRET / JWT_REFRESH_SECRET / SESSION_SECRET
docker compose -f infra/docker-compose.yml up -d --build

Then open http://app.localhost for the customer app, http://admin.localhost for the admin console (log in with admin@test.com / Password123! from the seed data) — both resolve to 127.0.0.1 in any modern browser, no /etc/hosts editing needed. This is the intended way to run the whole stack — everything (Postgres, API, worker, both frontends, nginx) runs in containers named aens-*, not from your terminal.

Prefer to run a piece directly on your machine for active development? See docs/SETUP.md for the manual, per-directory instructions (server/, client/user/, and client/admin/ each have their own package.json).

Docs

  • docs/SETUP.md — getting a local environment running, Docker or manual
  • docs/API.md — REST endpoint reference
  • docs/ARCHITECTURE.md — how it's built and why, including real bugs found and fixed along the way
  • docs/SECURITY.md — security audit test list: what's implemented and verified, what's an accepted tradeoff, what's an open gap
  • docs/TODO.md — prioritized, documented path to production-grade: what to add, remove, and fix, and why
  • docs/PLAN.md — the implementation plan this was built from

Features

  • Schedule emails with CC/BCC, priority, and a custom send time (any timezone)
  • Automatic retries with a configurable attempt limit, full per-attempt audit trail
  • JWT auth with email verification, password reset, and account lockout after repeated failed logins
  • A customer dashboard: overview stats + delivery chart, scheduled-email list with filters, per-email detail/attempt history, profile & account settings
  • A standalone admin console for internal staff: user management, system-wide email/log visibility — a separate application with its own login and session, not a route inside the customer app, and not reachable from it
  • Redis-backed caching (cache-aside reads, explicit invalidation on writes) and rate limiting
  • Swagger/OpenAPI docs and self-hosted Umami analytics

Project layout

server/         Express API + cron worker — its own package.json, .env, Jest suite
client/
  user/         Next.js customer app + marketing site — its own package.json
  admin/        Next.js admin console — standalone app, its own package.json, its own login
infra/
  docker-compose.yml   the whole stack, one command
  docker/               a Dockerfile per service
  nginx/                 nginx.conf, proxy_params.conf — the reverse proxy in front of everything
docs/           setup, API reference, architecture notes, security audit, the original plan

Each of server/, client/user/, and client/admin/ is self-contained: its own dependencies, its own .env. There's nothing to install at the repo root, and client/user//client/admin/ don't import from each other — client/ itself is just their parent directory, not a package.

CI/CD

  • CI (.github/workflows/ci.yml): lints, npm audits (fails on high/critical), and tests the server against a real Postgres service container; lints, audits, and builds both frontends; lints the nginx config with nginx -t — on every push/PR to main/develop.
  • CD (.github/workflows/cd.yml): on push to main, builds each image (api, worker, client, admin, nginx), scans it with Trivy (fails on high/critical, blocking the push), then publishes to GitHub Container Registry (ghcr.io). Every action in both workflows is pinned to a commit SHA, not a floating tag. Pulling the images onto an actual host is left to you — no deploy target is assumed.

About

a system that allows users to schedule automated email notifications to be sent at a future date using cron jobs.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages