Skip to content

ironexdev/ent-stack

Repository files navigation

ENT Stack

ent-title

NPM version Setup Guide ffn

Table of Contents

What is the ENT Stack?

The ENT Stack is a full-stack TypeScript project starter that integrates Express 5, Next.js 15, and TRPC.

It allows you to build and share code between frontend and backend in a single project while maintaining the flexibility to host them separately.

Features

πŸŒ€ PNPM Workspace - Monorepo

  • The stack uses PNPM Workspace because it's simple and painless to use. With its efficient dependency management and shared package architecture, PNPM ensures faster installs and a clean, modular workflow.
  • Within the monorepo, each top-level folder plays a distinct role:
    • apps folder contains both the backend (apps/backend) and frontend (apps/frontend) codebases.
    • packages folder contains a shared directory (packages/shared) that centralizes common configurations, utilities, services type definitions, and translations.
  • To maintain uniform code quality, each of these directories includes an eslint.config.js file featuring consistent rules. A root-level tsconfig.json provides a base set of TypeScript configurations, while each subproject extends these defaults to meet its own requirements.

🀝 Type-Safe API Layer

  • The stack leverages TRPC to create a type-safe bridge between the frontend and backend. This ensures that your IDE automatically provides type hints and autocompletion for API endpoints, eliminating the need for manual type definitions.

βš™οΈ Environment and Configuration

  • Leverages T3 Env type-safe environment variables validation in both backend and frontend
  • Contains Shared configuration file shared-config.ts that is extended by both Backend backend-config.ts and Frontend frontend-config.ts files for feature-focused settings

πŸ›’οΈ Database

  • The backend uses Drizzle ORM for interacting with a MySQL database, providing a type-safe and developer-friendly API.
  • It also contains Docker Image and a script bin/docker/run-local-db.sh to run the database locally.

πŸ”’ Authentication and Authorization

  • The stack provides passwordless registration and login through short verification PINs, secure JWT access tokens, and UUID-based refresh tokens. Additionally, frontend routes can be marked as protected in routes.ts, restricting them to authenticated users - this is evaluated in middleware.ts.

πŸͺ² Validation and Error Handling

  • The stack uses Zod for consistent input validation across the frontend and backend, integrated with TRPC for type-safe error management.
  • Input is sanitized to prevent injection attacks.
  • Errors are categorized into client, server, and userland types for precise handling.
  • Tanstack Query handles errors through a custom handler with callbacks for server, client, and userland errors.

πŸ”„ State Management

  • Uses Zustand for lightweight, synchronous global state management, delivering a minimal overhead approach for storing and controlling shared data across the application.
  • Uses Tanstack Query for asynchronous data fetching and caching, providing an SSR-friendly solution that keeps the UI and server in sync.

🌐 Internationalization (i18n) and Localization

  • A custom, lightweight solution handles localization using standalone functions that use ICU message syntax.
  • Translation functions can be used anywhere in the stack (both backend and frontend).
  • The stack includes two scripts for message import (pnpm import-messages) and export (pnpm export-messages)
  • Frontend routes are fully translatable, defined in standalone .ts file, and dynamically evaluated at runtime through Next.js middleware.

πŸͺ΅ Logging

  • The stack employs Pino for lightweight and efficient logging across both backend and frontend. Its simple API and minimal overhead ensure clear, structured logs without impacting performance.

βœ‰οΈ Mailing

  • integrates Resend for developer friendly e-mail sending.
  • Backend also contains email test router for email previews and testing.
  • Email templates are written in Handlebars.

πŸ€– Testing

  • The stack uses Playwright for unified frontend and backend testing, ensuring consistency and reliability.
  • Mailslurp is used for receiving e-mails in tests.

🐳 DevOPS - Infrastructure and CI/CD

Getting Started

Get up and running with the ENT Stack in just two steps:

Prerequisites

πŸ’‘ How to install prerequisites on Ubuntu 24

1/ πŸš€ Create your project

pnpm create ent-stack@latest
  • Creates a new project (folder) based on specific version of this repository.
  • The version used is specified in the description of the npm package.

2/ πŸ”₯ Setup

pnpm fire
  • Installs dependencies
  • Starts the local database in a Docker container
  • Creates the database and tables
  • Runs dev environments for both the backend and frontend

At this point, your application should be up and running locally. But to enable email sending and testing, you need to follow the final step below.

3/ πŸ§ͺ Configure Mailing and Run Tests

To enable mailing, you need to do the following:

Resend domain Resend API Key
MailSlurp inbox and inbox id MailSlurp API Key

After that, make sure to restart dev environment, and then you can run the tests by executing the following commands:

  • Test Backend
pnpm backend:test
  • Test Frontend
pnpm frontend:test

Here is the list of values that MUST BE THE SAME in both backend and frontend .env files:

Backend Frontend
SITE_NAME NEXT_PUBLIC_SITE_NAME
COOKIE_DOMAIN NEXT_PUBLIC_COOKIE_DOMAIN
BACKEND_URL NEXT_PUBLIC_BACKEND_URL
FRONTEND_URL NEXT_PUBLIC_FRONTEND_URL
JWT_SECRET JWT_SECRET

Documentation

For information about ENT Stack features go to the πŸ“„ Documentation

Troubleshooting

1/ IDE issues

- Node interpreter is not set
- Eslint/Prettier is not working on save
- TypeScript highlights non-existent errors
  • These issues can occur if your IDE is not properly configured. For reference, I'm attaching my PHPStorm (WebStorm) configuration on WSL2 with Ubuntu, showing the settings for ESLint, Prettier, and Node.js.:
Eslint Settings Prettier Settings Node.js Settings

2/ MySQL container name conflict

docker: Error response from daemon: Conflict. The container name "/mysql" is already in use by container
  • Remove the existing container by running docker rm mysql
  • Or for more nuclear solution, run bin/docker/cleanup.sh
    • this script forcefully cleans up Docker by removing all build caches, containers, images, and unused networks to free disk space and reset the environment.