DEV Community

Er Hardik Chauhan
Er Hardik Chauhan

Posted on

Master Full-Stack Monorepos: A Step-by-Step Guide

Ever wondered how to streamline your full-stack development process? This guide walks you through setting up a full-stack monorepo with the latest tools and technologies. Follow these step-by-step instructions to create a modern, robust, and scalable application using:

> TypeScript
> Vite
> pnpm
> Docker
> And more!
Enter fullscreen mode Exit fullscreen mode

Full-Stack Monorepo Setup Documentation

This documentation covers the setup and usage of a full-stack monorepo project with the following technologies and tools:

Here are the tools grouped into relevant categories:

Programming Language and Frameworks

- TypeScript
- Express
- React
Enter fullscreen mode Exit fullscreen mode

Build and Development Tools

- Vite
- pnpm
- Docker
- ESLint
- Prettier
- Husky
Enter fullscreen mode Exit fullscreen mode

Database and ORM

- Sequelize
- PostgreSQL
Enter fullscreen mode Exit fullscreen mode

Authentication and Security

- jsonwebtoken
- bcryptjs
- cookie-parser
- AWS WAF
Enter fullscreen mode Exit fullscreen mode

AWS and Cloud Services

- AWS SDK v3
- Terraform
Enter fullscreen mode Exit fullscreen mode

Logging and Validation

- Winston
- Zod
Enter fullscreen mode Exit fullscreen mode

Networking and API

- Axios
Enter fullscreen mode Exit fullscreen mode

UI Frameworks and Libraries

- Bootstrap
Enter fullscreen mode Exit fullscreen mode

CI/CD and DevOps

- GitHub Actions
- SonarQube
- Trivy
Enter fullscreen mode Exit fullscreen mode

These groupings can help organize your tools by their purpose, making it easier for your readers to understand the different aspects of your full-stack monorepo setup.

Project Structure

my-monorepo/
│
├── packages/
│   ├── server/
│   │   ├── Dockerfile
│   │   ├── src/
│   │   │   ├── config/
│   │   │   │   └── sequelize.ts
│   │   │   ├── controllers/
│   │   │   │   └── userController.ts
│   │   │   ├── middleware/
│   │   │   │   └── auth.ts
│   │   │   ├── models/
│   │   │   │   └── user.ts
│   │   │   ├── repositories/
│   │   │   │   └── userRepository.ts
│   │   │   ├── routes/
│   │   │   │   ├── auth.ts
│   │   │   │   └── user.ts
│   │   │   ├── services/
│   │   │   │   └── userService.ts
│   │   │   ├── utils/
│   │   │   │   ├── logger.ts
│   │   │   │   └── syncEnv.ts
│   │   │   └── index.ts
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   ├── .env.development
│   │   ├── .env.beta
│   │   ├── .env.test
│   │   ├── .env.production
│   │   ├── sequelize-cli/
│   │   │   ├── config/
│   │   │   │   └── config.js
│   │   │   ├── models/
│   │   │   ├── migrations/
│   │   │   └── seeders/
│   ├── client/
│   │   ├── src/
│   │   │   ├── axios.ts
│   │   │   ├── context/
│   │   │   │   └── AuthContext.tsx
│   │   │   ├── components/
│   │   │   │   └── AuthExample.tsx
│   │   │   ├── App.tsx
│   │   │   ├── main.tsx
│   │   │   └── index.html
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── shared/
│   │   ├── src/
│   │   │   └── utils.ts
│   │   ├── package.json
│   │   └── tsconfig.json
├── terraform/
│   ├── development/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── terraform.tfvars
│   ├── production/
│   │   └── main.tf
├── .github/
│   └── workflows/
│       └── deploy.yml
├── .eslintrc.json
├── .prettierrc
├── docker-compose.yml
├── package.json
├── pnpm-workspace.yaml
├── tsconfig.json
Enter fullscreen mode Exit fullscreen mode

Step-by-Step Setup

1. Initialize the Monorepo

  1. Create Project Structure:
mkdir my-monorepo
cd my-monorepo
mkdir packages
mkdir packages/server packages/client packages/shared
touch pnpm-workspace.yaml
touch .env.development .env.beta .env.test .env.production
touch docker-compose.yml
touch .eslintrc.json .prettierrc
Enter fullscreen mode Exit fullscreen mode
  1. Initialize the Monorepo with pnpm:
pnpm init -y
Enter fullscreen mode Exit fullscreen mode
  1. Set Up Workspaces in pnpm-workspace.yaml:
packages:
  - 'packages/*'
Enter fullscreen mode Exit fullscreen mode

2. Environment Variables

  1. Create Environment Files:

.env.development:

VITE_NODE_ENV=development
VITE_DATABASE_URL=postgres://user:password@db:5432/mydb_dev
VITE_PORT=4000
VITE_JWT_SECRET=your_jwt_secret
Enter fullscreen mode Exit fullscreen mode

.env.beta, .env.test, .env.production: similarly create these files with appropriate values.

3. Docker Configuration

  1. Create docker-compose.yml:
version: '3.8'
services:
  server:
    build: ./packages/server
    ports:
      - "${VITE_PORT}:${VITE_PORT}"
    env_file:
      - ./.env.development
    depends_on:
      - db
  db:
    image: postgres:latest
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb_development
Enter fullscreen mode Exit fullscreen mode
  1. Create Dockerfile for Server in packages/server/Dockerfile:
FROM node:22

WORKDIR /app

COPY package*.json ./
COPY pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN pnpm install

COPY . .

RUN pnpm -r build

CMD ["pnpm", "dev"]
Enter fullscreen mode Exit fullscreen mode

4. TypeScript Configuration

  1. Create the Root tsconfig.json:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@shared/*": ["packages/shared/src/*"],
      "@client/*": ["packages/client/src/*"],
      "@server/*": ["packages/server/src/*"]
    }
  },
  "include": ["packages/*/src"]
}
Enter fullscreen mode Exit fullscreen mode
  1. Install TypeScript:
pnpm add -D typescript
Enter fullscreen mode Exit fullscreen mode

5. Linting and Formatting

  1. Create .eslintrc.json:
{
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
  "plugins": ["@typescript-eslint"],
  "parser": "@typescript-eslint/parser",
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "rules": {}
}
Enter fullscreen mode Exit fullscreen mode
  1. Create .prettierrc:
{
  "semi": true,
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2,
  "trailingComma": "all"
}
Enter fullscreen mode Exit fullscreen mode
  1. Install ESLint and Prettier:
pnpm add -D eslint prettier eslint-plugin-prettier eslint-config-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser
Enter fullscreen mode Exit fullscreen mode

6. Husky

  1. Install Husky:
pnpm add -D husky
pnpm dlx husky-init && pnpm install
Enter fullscreen mode Exit fullscreen mode
  1. Add a Pre-commit Hook:
npx husky add .husky/pre-commit "pnpm lint"
Enter fullscreen mode Exit fullscreen mode

7. Configure Server with Controller-Service-Repository Pattern, Logging, and Authentication

  1. Install Dependencies:
pnpm add express sequelize pg pg-hstore jsonwebtoken bcryptjs cookie-parser zod winston @aws-sdk/client-secrets-manager
pnpm add -D @types/express @types/node @types/jsonwebtoken @types/bcryptjs @types/cookie-parser @types/sequelize
Enter fullscreen mode Exit fullscreen mode
  1. Configure vite.config.ts:

packages/server/vite.config.ts:

import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    port: Number(import.meta.env.VITE_PORT) || 4000,
  }
});
Enter fullscreen mode Exit fullscreen mode
  1. Create Sequelize Configuration:

packages/server/src/config/sequelize.ts:

import { Sequelize } from 'sequelize';

const sequelize = new Sequelize(import.meta.env.VITE_DATABASE_URL as string, {
  dialect: 'postgres',
});

export default sequelize;
Enter fullscreen mode Exit fullscreen mode
  1. Create User Model:

packages/server/src/models/user.ts:

import { DataTypes, Model } from 'sequelize';
import sequelize from '../config/sequelize';

class User extends Model {
  public id!: number;
  public email!: string;
  public password!: string;
}

User.init(
  {
    id: {
      type: DataTypes.INTEGER,
      autoIncrement: true,
      primaryKey: true,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  {
    sequelize,
    tableName: 'users',
  }
);

export default User;
Enter fullscreen mode Exit fullscreen mode
  1. Create Repository:

packages/server/src/repositories/userRepository.ts:

import User from '../models/user';

class UserRepository {
  async create(email: string, password: string) {
    return User.create({ email, password });
  }

  async findByEmail(email: string) {
    return User.findOne({ where: { email } });
  }

  async findById(id: number) {
    return User.findByPk(id);
  }
}

export default new UserRepository();
Enter fullscreen mode Exit fullscreen mode
  1. Create Service:

packages/server/src/services/userService.ts:

import bcrypt from 'bcryptjs';
import userRepository from '../repositories/userRepository';
import { generateToken } from '../utils/auth';
import User from '../models/user';

class UserService {
  async register(email: string, password: string) {
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = await userRepository.create(email, hashedPassword);
    const token = generateToken(user);
    return { user, token };
  }

  async login(email: string, password: string) {
    const user = await userRepository.findByEmail(email);
    if (!user) throw new Error('Invalid email or password');
    const isValidPassword = await bcrypt.compare(password, user.password);
    if (!isValidPassword) throw new Error('Invalid email or password');
    const token = generateToken(user);
    return { user, token };
  }

  async getUserById(id: number) {
    return userRepository.findById(id);
  }
}

export default new UserService();
Enter fullscreen mode Exit fullscreen mode
  1. Create Controller:

packages/server/src/controllers/userController.ts:

import { Request, Response } from 'express';
import userService from '../services/userService';
import logger from '../utils/logger';

class UserController {
  async register(req: Request, res: Response) {
    try {
      const { email, password } = req.body;
      const { user, token } = await userService.register(email, password);
      res.cookie('token', token, { httpOnly: true });
      res.status(201).json({ message: 'User registered', user });
    } catch (error) {
      logger.error('Error in register: %o', error);
      res.status(400).json({ message: error.message });
    }
  }

  async login(req: Request, res: Response) {
    try {
      const { email, password } = req.body;
      const { user, token } = await userService.login(email, password);
      res.cookie('token', token, { httpOnly: true });
      res.status(200).json({ message: 'User logged in', user });
    } catch (error) {
      logger.error('Error in login: %o', error);
      res.status(400).json({ message: error.message });
    }
  }

  async logout(req: Request, res: Response) {
    res.clearCookie('token');
    res.status(200).json({ message: 'User logged out' });
  }

  async profile(req: Request, res: Response) {
    try {
      const user = await userService.getUserById(req.user.id);
      res.json({ user });
    } catch (error) {
      logger.error('Error in profile: %o', error);
      res.status(400).json({ message: error.message });
    }
  }
}

export default new UserController();
Enter fullscreen mode Exit fullscreen mode
  1. Authentication Middleware:

packages/server/src/middleware/auth.ts:

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import User from '../models/user';

export const authenticateJWT = (req: Request, res: Response, next: NextFunction) => {
  const token = req.cookies.token;

  if (token) {
    jwt.verify(token, import.meta.env.VITE_JWT_SECRET as string, (err, user) => {
      if (err) {
        return res.sendStatus(403);
      }
      req.user = user;
      next();
    });
  } else {
    res.sendStatus(401);
  }
};

export const generateToken = (user: User) => {
  return jwt.sign({ id: user.id, email: user.email }, import.meta.env.VITE_JWT_SECRET as string, { expiresIn: '1h' });
};
Enter fullscreen mode Exit fullscreen mode
  1. Logging with Winston:

packages/server/src/utils/logger.ts:

import { createLogger, format, transports } from 'winston';

const logger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
    format.errors({ stack: true }),
    format.splat(),
    format.json()
  ),
  defaultMeta: { service: 'user-service' },
  transports: [
    new transports.File({ filename: 'error.log', level: 'error' }),
    new transports.File({ filename: 'combined.log' }),
  ],
});

if (process.env.NODE_ENV !== 'production') {
  logger.add(new transports.Console({
    format: format.combine(
      format.colorize(),
      format.simple()
    )
  }));
}

export default logger;
Enter fullscreen mode Exit fullscreen mode
  1. Create Routes:

packages/server/src/routes/auth.ts:

import express from 'express';
import userController from '../controllers/userController';

const router = express.Router();

router.post('/register', userController.register);
router.post('/login', userController.login);
router.post('/logout', userController.logout);

export default router;
Enter fullscreen mode Exit fullscreen mode

packages/server/src/routes/user.ts:

import express from 'express';
import { authenticateJWT } from '../middleware/auth';
import userController from '../controllers/userController';

const router = express.Router();

router.get('/profile', authenticateJWT, userController.profile);

export default router;
Enter fullscreen mode Exit fullscreen mode
  1. Sync Environment Variables from AWS Secrets Manager:

packages/server/src/utils/syncEnv.ts:

import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
import dotenv from "dotenv";
dotenv.config();

const client = new SecretsManagerClient({ region: "your-region" });

async function syncEnv() {
  const secretName = "your-secret-name";
  const command = new GetSecretValueCommand({ SecretId: secretName });

  try {
    const data = await client.send(command);
    if (data.SecretString) {
      const secrets = JSON.parse(data.SecretString);
      for (const key in secrets) {
        import.meta.env[key] = secrets[key];
      }
    }
  } catch (err) {
    console.error(err);
  }
}

syncEnv();
Enter fullscreen mode Exit fullscreen mode
  1. Main Server File:

packages/server/src/index.ts:

import express from 'express';
import cookieParser from 'cookie-parser';
import dotenv from 'dotenv';
import authRoutes from './routes/auth';
import userRoutes from './routes/user';
import sequelize from './config/sequelize';
import './utils/syncEnv';
import logger from './utils/logger';

dotenv.config();

const app = express();
const port = import.meta.env.VITE_PORT || 4000;

app.use(express.json());
app.use(cookieParser());

app.use('/auth', authRoutes);
app.use('/user', userRoutes);

app.get('/', (req, res) => {
  res.send('Hello from Express and TypeScript!');
});

sequelize.sync().then(() => {
  app.listen(port, () => {
    logger.info(`Server is running at http://localhost:${port}`);
  });
});
Enter fullscreen mode Exit fullscreen mode

8. Frontend Configuration

  1. Create package.json for Client:
{
  "name": "client",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "vitest",
    "e2e": "playwright test"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "bootstrap": "^5.0.2",
    "axios": "^0.21.1"
  },
  "devDependencies": {
    "vite": "^2.3.8",
    "vitest": "^0.0.134",
    "typescript": "^4.2.4",
    "@vitejs/plugin-react": "^1.1.0",
    "@playwright/test": "^1.12.3"
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Create tsconfig.json in Client:
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src",
    "module": "esnext",
    "target": "es6",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}
Enter fullscreen mode Exit fullscreen mode
  1. Create vite.config.ts for Client:

packages/client/vite.config.ts:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000
  }
});
Enter fullscreen mode Exit fullscreen mode
  1. Set Up Axios:

packages/client/src/axios.ts:

import axios from 'axios';

const api = axios.create({


 baseURL: import.meta.env.VITE_API_URL || 'http://localhost:4000',
  withCredentials: true,
});

export default api;
Enter fullscreen mode Exit fullscreen mode
  1. Auth Context:

packages/client/src/context/AuthContext.tsx:

import React, { createContext, useState, useEffect, ReactNode } from 'react';
import api from '../axios';

interface AuthContextProps {
  user: any;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
}

const AuthContext = createContext<AuthContextProps | undefined>(undefined);

export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [user, setUser] = useState<any>(null);

  useEffect(() => {
    // Check if the user is authenticated on mount
    const fetchUser = async () => {
      try {
        const response = await api.get('/user/profile');
        setUser(response.data.user);
      } catch (err) {
        setUser(null);
      }
    };

    fetchUser();
  }, []);

  const login = async (email: string, password: string) => {
    const response = await api.post('/auth/login', { email, password });
    setUser(response.data.user);
  };

  const logout = async () => {
    await api.post('/auth/logout');
    setUser(null);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => {
  const context = React.useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};
Enter fullscreen mode Exit fullscreen mode
  1. Auth Component Example:

packages/client/src/components/AuthExample.tsx:

import React, { useState } from 'react';
import { useAuth } from '../context/AuthContext';

const AuthExample: React.FC = () => {
  const { user, login, logout } = useAuth();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = async () => {
    await login(email, password);
  };

  return (
    <div>
      {user ? (
        <div>
          <h1>Welcome, {user.email}</h1>
          <button onClick={logout}>Logout</button>
        </div>
      ) : (
        <div>
          <h1>Login</h1>
          <input
            type="email"
            placeholder="Email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <input
            type="password"
            placeholder="Password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
          <button onClick={handleLogin}>Login</button>
        </div>
      )}
    </div>
  );
};

export default AuthExample;
Enter fullscreen mode Exit fullscreen mode
  1. Main Component:

packages/client/src/App.tsx:

import React from 'react';
import { AuthProvider } from './context/AuthContext';
import AuthExample from './components/AuthExample';

const App: React.FC = () => {
  return (
    <AuthProvider>
      <AuthExample />
    </AuthProvider>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode
  1. Index File:

packages/client/src/main.tsx:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css';

ReactDOM.render(<App />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode
  1. HTML File:

packages/client/src/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React Vite App</title>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/src/main.tsx"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Step 9: CI/CD Configuration with GitHub Actions

  1. Create .github/workflows/deploy.yml:
name: CI/CD Pipeline

on:
  push:
    branches:
      - main
      - development
      - beta
      - test
      - production
  pull_request:
    branches:
      - main

jobs:
  build:
    name: Build and Test
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '22'
        cache: 'pnpm'

    - name: Install dependencies
      run: pnpm install

    - name: Run tests
      run: pnpm test

    - name: Run linting
      run: pnpm lint

    - name: Run formatting
      run: pnpm format

  sonar:
    name: SonarQube Scan
    runs-on: ubuntu-latest
    needs: build

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '22'
        cache: 'pnpm'

    - name: Install dependencies
      run: pnpm install

    - name: Run SonarQube scan
      env:
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
      run: |
        pnpm install -g sonar-scanner
        sonar-scanner \
          -Dsonar.projectKey=my-project \
          -Dsonar.sources=. \
          -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
          -Dsonar.login=${{ secrets.SONAR_TOKEN }}

  trivy:
    name: Trivy Scan
    runs-on: ubuntu-latest
    needs: build

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1

    - name: Build Docker image
      run: docker build -t my-app .

    - name: Run Trivy scan
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: my-app

  deploy:
    name: Deploy
    needs: [build, sonar, trivy]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/development' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/test' || github.ref == 'refs/heads/production'

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '22'
        cache: 'pnpm'

    - name: Install dependencies
      run: pnpm install

    - name: Build project
      run: pnpm run build

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-west-2

    - name: Deploy frontend to S3 and CloudFront
      run: |
        aws s3 sync packages/client/dist s3://${{ secrets.S3_BUCKET_NAME }}
        aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"

    - name: Deploy backend with Terraform
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      run: |
        cd terraform/${{ github.ref_name }}
        terraform init
        terraform apply -auto-approve

  release:
    name: Create Release
    runs-on: ubuntu-latest
    needs: deploy
    if: github.ref == 'refs/heads/main'

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Create release
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: v1.0.${{ github.run_number }}
        release_name: Release v1.0.${{ github.run_number }}
        draft: false
        prerelease: false
Enter fullscreen mode Exit fullscreen mode

Step 10: Configure Secrets in GitHub

In your GitHub repository, navigate to Settings -> Secrets and add the following secrets:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • S3_BUCKET_NAME
  • CLOUDFRONT_DISTRIBUTION_ID
  • SONAR_HOST_URL
  • SONAR_TOKEN
  • GITHUB_TOKEN (usually auto-generated by GitHub Actions)

Step 11: Install Dependencies and Run

  1. Install all dependencies:
pnpm install
Enter fullscreen mode Exit fullscreen mode
  1. Run local development:
pnpm run dev
Enter fullscreen mode Exit fullscreen mode
  1. Push to GitHub:
git add .
git commit -m "Initial setup with CI/CD, Docker, and Terraform"
git push origin main
Enter fullscreen mode Exit fullscreen mode

Step 12: Sequelize Commands

Generate a new migration:

npx sequelize-cli migration:generate --name migration_name
Enter fullscreen mode Exit fullscreen mode

Run migrations:

npx sequelize-cli db:migrate
Enter fullscreen mode Exit fullscreen mode

Create a new model:

npx sequelize-cli model:generate --name ModelName --attributes name:string,age:integer
Enter fullscreen mode Exit fullscreen mode

Generate seed data:

npx sequelize-cli seed:generate --name seed_name
Enter fullscreen mode Exit fullscreen mode

Run seeders:

npx sequelize-cli db:seed:all
Enter fullscreen mode Exit fullscreen mode

Top comments (0)