This repository is a robust base template for building modern web applications using Next.js, React, TailwindCSS, GraphQL, MongoDB, Sequelize, and Shadcn components. It is designed with a modular structure to facilitate scalability and maintainability.
First, install the create-nrtgmp-app package globally:
npm install -g create-nrtgmp-appThen, create a new project using the package:
npx create-nrtgmp-app my-nrtgmp-appNavigate to the project directory and run the development server:
cd my-nrtgmp-app
npm run devOpen http://localhost:3000 with your browser to see the result.
- Next.js: A React framework for production.
- React: A JavaScript library for building user interfaces.
- TailwindCSS: A utility-first CSS framework.
- GraphQL: A query language for your API.
- MongoDB: A NoSQL database.
- Sequelize: A promise-based Node.js ORM for Postgres, MySQL, MariaDB, SQLite, and Microsoft SQL Server.
- Shadcn Components: A set of UI components.
GraphQL is set up using Apollo Server and Apollo Client. The Apollo Client setup will change frequently, and documentation for it will be added later.
In development mode, there is an Apollo GraphQL playground available at http://localhost:3000/graphql.
The project follows a modular structure for GraphQL. To add a new query or extend an existing query:
- Create a folder in
/src/graphql. - Add two files:
*.graphqland*.resolver.js.
# src/graphql/user/user.graphql
type User {
id: Int!
name: String!
}
type Query {
users: [User!]
}*.graphql files define the schema for the query. This example defines a User type with id and name fields, and a users query that returns a list of users.
// src/graphql/user/user.resolver.js
const { users } = require("./user.js");
module.exports = {
Query: {
users: async (parent, args) => {
return users;
}
}
}*.resolver.js files export an object with the query resolvers.
This resolver provides the implementation for the users query, returning a list of users.
To add APIs, use the Next.js App Router:
- Create a folder in
/src/app/api. - Inside this folder, create a file named
route.js. - Export async functions for supported methods that handle the request and response.
// src/app/api/hello/route.js
export async function GET(request) {
return new Response(JSON.stringify({ message: 'Hello, world!' }), {
headers: { 'Content-Type': 'application/json' },
});
}This example creates an API route at /api/hello exposing a GET method that returns a JSON response with a message.
This repository supports both MongoDB and PostgreSQL (via Sequelize) with a modular setup. Databases will be connected automatically at initialization if the necessary environment variables are provided.
- Directory:
/src/mongodb - Datasources:
/src/mongodb/datasources.js
- Directory:
/src/sequelize - Datasources:
/src/sequelize/datasources.js
Ensure the following environment variables are set in your .env file:
- MongoDB:
MONGODB_URI - PostgreSQL:
DB_HOST,DB_PORT,DB_NAME,DB_USER,DB_PASS
Datasources can be accessed in GraphQL resolvers by using the ds object from context.
// src/graphql/user/user.resolver.js
module.exports = {
Query: {
users: async (parent, args, { ds }) => {
return ds.UserDataSource.getUsers();
}
}
}Datasources can be accessed by importing @/mongodb/datasources.js or @/sequelize/datasources.js.
// src/app/api/user/route.js
import mongoDatasources as ds from '@/mongodb/datasources.js';
// or
// import sequelizeDatasources as ds from '@/sequelize/datasources.js';
export async function GET(request) {
return new Response(JSON.stringify(await ds.UserDataSource.getUsers()), {
headers: { 'Content-Type': 'application/json' },
});
}- Create a folder in
/src/mongodb/models. - Add two files:
*.model.jsand*.datasource.js.
// src/mongodb/models/user/user.model.js
const { Schema, model } = require('mongoose');
const userSchema = new Schema({
id: {
type: Number,
required: true
},
name: {
type: String,
required: true
}
});
const UserModel = model('user', userSchema);
module.exports = {
UserModel
};*.model.js files define the schema for the model and export the model. This example defines a User model with id and name fields.
// src/mongodb/models/user/user.datasource.js
const { MongoDataSource } = require('apollo-datasource-mongodb')
const { UserModel } = require('./user.model.js');
class UserDataSource extends MongoDataSource {
async getUserById(id) {
return this.model.findOne({ id });
}
}
module.exports = {
name: "UserDataSource",
model: UserModel,
datasource: UserDataSource
};*.datasource.js files define the datasource for the model and export an object containing the model name, model, and datasource. This example defines a UserDataSource with a method to get a user by ID.
- Create a folder in
/src/sequelize/models. - Add a single file:
*.model.js.
// src/sequelize/models/user/user.model.js
const { DataTypes, Model } = require('sequelize');
class UserModel extends Model {
static getUserById(id) {
return this.findByPk(id);
}
}
const UserModelDefination = {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false
},
password: {
type: DataTypes.STRING,
allowNull: false
}
}
module.exports = {
modelName: 'User',
model: UserModel,
defination: UserModelDefination
};*.model.js files define the model for the datasource and export an object containing the model name, model, and model defination. This example defines a User model with id, name, email, and password fields.
To prevent naming clashes between similar names, there is a prefix for Sequelize datasources which can be changed through the environment variable SEQUELIZE_PREFIX. The default prefix is "pg".
As Sequelize supports multiple databases, the setup for MySQL, MariaDB, SQLite, and Microsoft SQL Server is similar to PostgreSQL. The difference will be changing the environment variables and the database dialect in the Sequelize configuration.
NRTGMP uses Iron Session for managing session data. The session data is stored in cookies and encrypted using Iron. The session data can be accessed in API routes, GraphQL resolvers and Sever components & actions.
To start using session data, add session fields in the defaultSession object in /src/lib/session/options.js. You can also customize Iron session options in the serverOptions object.
// src/lib/session/options.js
export const serverOptions = {
cookieName: process.env.SESSION_COOKIE_NAME || "NSESSION",
password: process.env.SESSION_SECRET,
cookieOptions: {
secure: process.env.NODE_ENV === "production",
},
};
export const defaultSession = {
user: "Guest",
};If the session is not set, the default session data will be returned. You can modify the session data directly like a JavaScript object and call session.save() to save the changes.
Session data is accessed in API routes, server components, and actions using the getSession function from @/lib/session/fromCookies.
import { getSession } from '@/lib/session/fromCookies';
export async function Something(request) {
const session = await getSession();
session.user = "New User";
await session.save();
}In this example, Something can be an API route, server component, or action.
Session data is accessed in GraphQL resolvers using the session object from context.
// src/graphql/user/user.resolver.js
module.exports = {
Query: {
users: async (parent, args, { session }) => {
session.user = "New User";
await session.save();
}
}
}Shadcn components are set up in this repository. More information on how to use them will be added later.
npm run dev: Start the development server.npm run build: Build the project.npm run start: Start the production server.npm run lint: Run the linter.