feat: scaffold monorepo with Turborepo + NestJS + Next.js

- Turborepo monorepo with pnpm workspaces
- apps/api: NestJS 11.x with CQRS module
- apps/web: Next.js 14 App Router + TailwindCSS
- src/modules/shared: base entities, Result pattern, value objects
- TypeScript 5.7+ strict mode, shared tsconfig base
- Build pipeline: dev, build, lint, test, typecheck

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-07 23:52:33 +07:00
commit e1e5fa6252
52 changed files with 6110 additions and 0 deletions

8
apps/api/nest-cli.json Normal file
View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}

31
apps/api/package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "@goodgo/api",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "nest start --watch",
"build": "nest build",
"start": "node dist/main",
"start:prod": "node dist/main",
"lint": "eslint \"{src,test}/**/*.ts\"",
"test": "vitest run",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@nestjs/common": "^11.0.0",
"@nestjs/core": "^11.0.0",
"@nestjs/cqrs": "^11.0.0",
"@nestjs/platform-express": "^11.0.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.0"
},
"devDependencies": {
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.0",
"@types/express": "^5.0.0",
"@types/node": "^22.0.0",
"typescript": "^5.7.0",
"vitest": "^3.0.0"
}
}

View File

@@ -0,0 +1,9 @@
import { Controller, Get } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
healthCheck() {
return { status: 'ok', service: 'goodgo-api' };
}
}

View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { CqrsModule } from '@nestjs/cqrs';
import { AppController } from './app.controller';
@Module({
imports: [CqrsModule.forRoot()],
controllers: [AppController],
})
export class AppModule {}

11
apps/api/src/main.ts Normal file
View File

@@ -0,0 +1,11 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const port = process.env['PORT'] ?? 3001;
await app.listen(port);
console.log(`API running on http://localhost:${port}`);
}
bootstrap();

15
apps/api/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "./dist",
"rootDir": "./src",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"declaration": false,
"declarationMap": false
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

3
apps/web/app/globals.css Normal file
View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

19
apps/web/app/layout.tsx Normal file
View File

@@ -0,0 +1,19 @@
import type { Metadata } from 'next';
import './globals.css';
export const metadata: Metadata = {
title: 'GoodGo Platform',
description: 'Vietnam Real Estate Platform',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="vi">
<body>{children}</body>
</html>
);
}

8
apps/web/app/page.tsx Normal file
View File

@@ -0,0 +1,8 @@
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-center p-24">
<h1 className="text-4xl font-bold">GoodGo Platform</h1>
<p className="mt-4 text-lg text-gray-600">Vietnam Real Estate Platform</p>
</main>
);
}

5
apps/web/next-env.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

6
apps/web/next.config.js Normal file
View File

@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};
module.exports = nextConfig;

26
apps/web/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "@goodgo/web",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev --port 3000",
"build": "next build",
"start": "next start",
"lint": "next lint",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"next": "^14.2.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"tailwindcss": "^3.4.0",
"typescript": "^5.7.0"
}
}

View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -0,0 +1,14 @@
import type { Config } from 'tailwindcss';
const config: Config = {
content: [
'./app/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
],
theme: {
extend: {},
},
plugins: [],
};
export default config;

41
apps/web/tsconfig.json Normal file
View File

@@ -0,0 +1,41 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"target": "ES2017",
"lib": [
"DOM",
"DOM.Iterable",
"ES2022"
],
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
},
"declaration": false,
"declarationMap": false,
"sourceMap": false,
"noEmit": true,
"allowJs": true,
"isolatedModules": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules",
".next"
]
}

File diff suppressed because one or more lines are too long