nexu-app 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1192 -0
- package/package.json +43 -0
- package/templates/default/.changeset/config.json +11 -0
- package/templates/default/.eslintignore +16 -0
- package/templates/default/.eslintrc.js +67 -0
- package/templates/default/.github/actions/build/action.yml +35 -0
- package/templates/default/.github/actions/quality/action.yml +53 -0
- package/templates/default/.github/dependabot.yml +51 -0
- package/templates/default/.github/workflows/deploy-dev.yml +83 -0
- package/templates/default/.github/workflows/deploy-prod.yml +83 -0
- package/templates/default/.github/workflows/deploy-rec.yml +83 -0
- package/templates/default/.husky/commit-msg +1 -0
- package/templates/default/.husky/pre-commit +1 -0
- package/templates/default/.nexu-version +1 -0
- package/templates/default/.prettierignore +7 -0
- package/templates/default/.prettierrc +19 -0
- package/templates/default/.vscode/extensions.json +14 -0
- package/templates/default/.vscode/settings.json +36 -0
- package/templates/default/apps/gitkeep +0 -0
- package/templates/default/commitlint.config.js +26 -0
- package/templates/default/docker/docker-compose.dev.yml +49 -0
- package/templates/default/docker/docker-compose.prod.yml +64 -0
- package/templates/default/docker/docker-compose.yml +6 -0
- package/templates/default/docs/architecture.md +452 -0
- package/templates/default/docs/cli.md +330 -0
- package/templates/default/docs/contributing.md +462 -0
- package/templates/default/docs/scripts.md +460 -0
- package/templates/default/gitignore +44 -0
- package/templates/default/lintstagedrc.cjs +4 -0
- package/templates/default/package.json +51 -0
- package/templates/default/packages/auth/package.json +61 -0
- package/templates/default/packages/auth/src/components/ProtectedRoute.tsx +75 -0
- package/templates/default/packages/auth/src/components/SignInForm.tsx +153 -0
- package/templates/default/packages/auth/src/components/SignUpForm.tsx +179 -0
- package/templates/default/packages/auth/src/components/SocialButtons.tsx +147 -0
- package/templates/default/packages/auth/src/components/index.ts +4 -0
- package/templates/default/packages/auth/src/hooks/index.ts +4 -0
- package/templates/default/packages/auth/src/hooks/useAuth.ts +51 -0
- package/templates/default/packages/auth/src/hooks/useRequireAuth.ts +54 -0
- package/templates/default/packages/auth/src/hooks/useSession.ts +48 -0
- package/templates/default/packages/auth/src/hooks/useUser.ts +48 -0
- package/templates/default/packages/auth/src/index.ts +45 -0
- package/templates/default/packages/auth/src/next/index.ts +18 -0
- package/templates/default/packages/auth/src/next/middleware.ts +183 -0
- package/templates/default/packages/auth/src/next/server.ts +219 -0
- package/templates/default/packages/auth/src/providers/AuthContext.tsx +435 -0
- package/templates/default/packages/auth/src/providers/index.ts +1 -0
- package/templates/default/packages/auth/src/types/index.ts +284 -0
- package/templates/default/packages/auth/src/utils/api.ts +228 -0
- package/templates/default/packages/auth/src/utils/index.ts +3 -0
- package/templates/default/packages/auth/src/utils/oauth.ts +230 -0
- package/templates/default/packages/auth/src/utils/token.ts +204 -0
- package/templates/default/packages/auth/tsconfig.json +14 -0
- package/templates/default/packages/auth/tsup.config.ts +18 -0
- package/templates/default/packages/cache/package.json +26 -0
- package/templates/default/packages/cache/src/index.ts +137 -0
- package/templates/default/packages/cache/tsconfig.json +9 -0
- package/templates/default/packages/cache/tsup.config.ts +9 -0
- package/templates/default/packages/config/eslint/index.js +20 -0
- package/templates/default/packages/config/package.json +9 -0
- package/templates/default/packages/config/typescript/base.json +26 -0
- package/templates/default/packages/constants/package.json +26 -0
- package/templates/default/packages/constants/src/index.ts +121 -0
- package/templates/default/packages/constants/tsconfig.json +9 -0
- package/templates/default/packages/constants/tsup.config.ts +9 -0
- package/templates/default/packages/logger/package.json +27 -0
- package/templates/default/packages/logger/src/index.ts +197 -0
- package/templates/default/packages/logger/tsconfig.json +11 -0
- package/templates/default/packages/logger/tsup.config.ts +9 -0
- package/templates/default/packages/result/package.json +26 -0
- package/templates/default/packages/result/src/index.ts +142 -0
- package/templates/default/packages/result/tsconfig.json +9 -0
- package/templates/default/packages/result/tsup.config.ts +9 -0
- package/templates/default/packages/types/package.json +26 -0
- package/templates/default/packages/types/src/index.ts +78 -0
- package/templates/default/packages/types/tsconfig.json +9 -0
- package/templates/default/packages/types/tsup.config.ts +10 -0
- package/templates/default/packages/ui/package.json +38 -0
- package/templates/default/packages/ui/src/components/Button.tsx +58 -0
- package/templates/default/packages/ui/src/components/Card.tsx +85 -0
- package/templates/default/packages/ui/src/components/Input.tsx +45 -0
- package/templates/default/packages/ui/src/index.ts +15 -0
- package/templates/default/packages/ui/tsconfig.json +11 -0
- package/templates/default/packages/ui/tsup.config.ts +11 -0
- package/templates/default/packages/utils/package.json +30 -0
- package/templates/default/packages/utils/src/index.test.ts +130 -0
- package/templates/default/packages/utils/src/index.ts +154 -0
- package/templates/default/packages/utils/tsconfig.json +10 -0
- package/templates/default/packages/utils/tsup.config.ts +10 -0
- package/templates/default/pnpm-workspace.yaml +3 -0
- package/templates/default/scripts/audit.mjs +700 -0
- package/templates/default/scripts/deploy.mjs +40 -0
- package/templates/default/scripts/generate-app.mjs +808 -0
- package/templates/default/scripts/lib/package-manager.mjs +186 -0
- package/templates/default/scripts/setup.mjs +102 -0
- package/templates/default/services/.env.example +16 -0
- package/templates/default/services/docker-compose.yml +207 -0
- package/templates/default/services/grafana/provisioning/dashboards/dashboards.yml +11 -0
- package/templates/default/services/grafana/provisioning/datasources/datasources.yml +9 -0
- package/templates/default/services/postgres/init/gitkeep +2 -0
- package/templates/default/services/prometheus/prometheus.yml +13 -0
- package/templates/default/tsconfig.json +27 -0
- package/templates/default/turbo.json +40 -0
- package/templates/default/vitest.config.ts +15 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package manager detection and utilities
|
|
3
|
+
* Supports: npm, yarn, pnpm
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { execSync, spawnSync } from 'child_process';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detect which package manager is being used in a project
|
|
12
|
+
* @param {string} projectDir - The project directory to check
|
|
13
|
+
* @returns {'pnpm' | 'yarn' | 'npm'} The detected package manager
|
|
14
|
+
*/
|
|
15
|
+
export function detectPackageManager(projectDir = process.cwd()) {
|
|
16
|
+
// Check for lock files
|
|
17
|
+
if (fs.existsSync(path.join(projectDir, 'pnpm-lock.yaml'))) {
|
|
18
|
+
return 'pnpm';
|
|
19
|
+
}
|
|
20
|
+
if (fs.existsSync(path.join(projectDir, 'yarn.lock'))) {
|
|
21
|
+
return 'yarn';
|
|
22
|
+
}
|
|
23
|
+
if (fs.existsSync(path.join(projectDir, 'package-lock.json'))) {
|
|
24
|
+
return 'npm';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check packageManager field in package.json
|
|
28
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
29
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
30
|
+
try {
|
|
31
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
32
|
+
if (pkg.packageManager) {
|
|
33
|
+
if (pkg.packageManager.startsWith('pnpm')) return 'pnpm';
|
|
34
|
+
if (pkg.packageManager.startsWith('yarn')) return 'yarn';
|
|
35
|
+
if (pkg.packageManager.startsWith('npm')) return 'npm';
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
// Ignore parse errors
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Check npm_config_user_agent environment variable (set by package managers)
|
|
43
|
+
const userAgent = process.env.npm_config_user_agent || '';
|
|
44
|
+
if (userAgent.includes('pnpm')) return 'pnpm';
|
|
45
|
+
if (userAgent.includes('yarn')) return 'yarn';
|
|
46
|
+
|
|
47
|
+
// Default to npm
|
|
48
|
+
return 'npm';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if a package manager is installed
|
|
53
|
+
* @param {string} pm - Package manager name
|
|
54
|
+
* @returns {boolean}
|
|
55
|
+
*/
|
|
56
|
+
export function isPackageManagerInstalled(pm) {
|
|
57
|
+
try {
|
|
58
|
+
const result = spawnSync(process.platform === 'win32' ? 'where' : 'which', [pm], {
|
|
59
|
+
stdio: 'pipe',
|
|
60
|
+
});
|
|
61
|
+
return result.status === 0;
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the run command for a package manager
|
|
69
|
+
* @param {'pnpm' | 'yarn' | 'npm'} pm
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
72
|
+
export function getRunCommand(pm) {
|
|
73
|
+
switch (pm) {
|
|
74
|
+
case 'pnpm':
|
|
75
|
+
return 'pnpm';
|
|
76
|
+
case 'yarn':
|
|
77
|
+
return 'yarn';
|
|
78
|
+
case 'npm':
|
|
79
|
+
default:
|
|
80
|
+
return 'npm run';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get the execute command (for running binaries)
|
|
86
|
+
* @param {'pnpm' | 'yarn' | 'npm'} pm
|
|
87
|
+
* @returns {string}
|
|
88
|
+
*/
|
|
89
|
+
export function getExecCommand(pm) {
|
|
90
|
+
switch (pm) {
|
|
91
|
+
case 'pnpm':
|
|
92
|
+
return 'pnpm exec';
|
|
93
|
+
case 'yarn':
|
|
94
|
+
return 'yarn';
|
|
95
|
+
case 'npm':
|
|
96
|
+
default:
|
|
97
|
+
return 'npx';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the install command
|
|
103
|
+
* @param {'pnpm' | 'yarn' | 'npm'} pm
|
|
104
|
+
* @param {object} options
|
|
105
|
+
* @param {boolean} options.frozen - Use frozen lockfile
|
|
106
|
+
* @returns {string}
|
|
107
|
+
*/
|
|
108
|
+
export function getInstallCommand(pm, options = {}) {
|
|
109
|
+
const { frozen = false } = options;
|
|
110
|
+
|
|
111
|
+
switch (pm) {
|
|
112
|
+
case 'pnpm':
|
|
113
|
+
return frozen ? 'pnpm install --frozen-lockfile' : 'pnpm install';
|
|
114
|
+
case 'yarn':
|
|
115
|
+
return frozen ? 'yarn install --frozen-lockfile' : 'yarn install';
|
|
116
|
+
case 'npm':
|
|
117
|
+
default:
|
|
118
|
+
return frozen ? 'npm ci' : 'npm install';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the add dependency command
|
|
124
|
+
* @param {'pnpm' | 'yarn' | 'npm'} pm
|
|
125
|
+
* @param {string} pkg - Package name
|
|
126
|
+
* @param {object} options
|
|
127
|
+
* @param {boolean} options.dev - Install as dev dependency
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
export function getAddCommand(pm, pkg, options = {}) {
|
|
131
|
+
const { dev = false } = options;
|
|
132
|
+
|
|
133
|
+
switch (pm) {
|
|
134
|
+
case 'pnpm':
|
|
135
|
+
return dev ? `pnpm add -D ${pkg}` : `pnpm add ${pkg}`;
|
|
136
|
+
case 'yarn':
|
|
137
|
+
return dev ? `yarn add -D ${pkg}` : `yarn add ${pkg}`;
|
|
138
|
+
case 'npm':
|
|
139
|
+
default:
|
|
140
|
+
return dev ? `npm install -D ${pkg}` : `npm install ${pkg}`;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get workspace filter command
|
|
146
|
+
* @param {'pnpm' | 'yarn' | 'npm'} pm
|
|
147
|
+
* @param {string} workspace - Workspace name
|
|
148
|
+
* @returns {string}
|
|
149
|
+
*/
|
|
150
|
+
export function getWorkspaceFilter(pm, workspace) {
|
|
151
|
+
switch (pm) {
|
|
152
|
+
case 'pnpm':
|
|
153
|
+
return `--filter=${workspace}`;
|
|
154
|
+
case 'yarn':
|
|
155
|
+
return `workspace ${workspace}`;
|
|
156
|
+
case 'npm':
|
|
157
|
+
default:
|
|
158
|
+
return `-w ${workspace}`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Run a command with the detected package manager
|
|
164
|
+
* @param {string} script - Script to run
|
|
165
|
+
* @param {object} options
|
|
166
|
+
* @param {string} options.cwd - Working directory
|
|
167
|
+
* @param {'pnpm' | 'yarn' | 'npm'} options.pm - Package manager (auto-detected if not provided)
|
|
168
|
+
*/
|
|
169
|
+
export function runScript(script, options = {}) {
|
|
170
|
+
const { cwd = process.cwd(), pm = detectPackageManager(cwd) } = options;
|
|
171
|
+
const runCmd = getRunCommand(pm);
|
|
172
|
+
const cmd = `${runCmd} ${script}`;
|
|
173
|
+
console.log(`> ${cmd}`);
|
|
174
|
+
execSync(cmd, { stdio: 'inherit', cwd });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default {
|
|
178
|
+
detectPackageManager,
|
|
179
|
+
isPackageManagerInstalled,
|
|
180
|
+
getRunCommand,
|
|
181
|
+
getExecCommand,
|
|
182
|
+
getInstallCommand,
|
|
183
|
+
getAddCommand,
|
|
184
|
+
getWorkspaceFilter,
|
|
185
|
+
runScript,
|
|
186
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import {
|
|
8
|
+
detectPackageManager,
|
|
9
|
+
isPackageManagerInstalled,
|
|
10
|
+
getInstallCommand,
|
|
11
|
+
getRunCommand,
|
|
12
|
+
} from './lib/package-manager.mjs';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
const ROOT_DIR = path.resolve(__dirname, '..');
|
|
17
|
+
|
|
18
|
+
// Detect package manager
|
|
19
|
+
const pm = detectPackageManager(ROOT_DIR);
|
|
20
|
+
const runCmd = getRunCommand(pm);
|
|
21
|
+
|
|
22
|
+
console.log('🚀 Setting up monorepo...');
|
|
23
|
+
console.log(`📦 Using package manager: ${pm}`);
|
|
24
|
+
|
|
25
|
+
function run(cmd) {
|
|
26
|
+
console.log(`> ${cmd}`);
|
|
27
|
+
execSync(cmd, { stdio: 'inherit', cwd: ROOT_DIR });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check if package manager is installed
|
|
31
|
+
if (!isPackageManagerInstalled(pm)) {
|
|
32
|
+
console.log(`📦 Installing ${pm}...`);
|
|
33
|
+
if (pm === 'pnpm') {
|
|
34
|
+
run('npm install -g pnpm');
|
|
35
|
+
} else if (pm === 'yarn') {
|
|
36
|
+
run('npm install -g yarn');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Install dependencies
|
|
41
|
+
console.log('📦 Installing dependencies...');
|
|
42
|
+
run(getInstallCommand(pm));
|
|
43
|
+
|
|
44
|
+
// Setup husky
|
|
45
|
+
console.log('🐶 Setting up Husky...');
|
|
46
|
+
run(`${runCmd} prepare`);
|
|
47
|
+
|
|
48
|
+
// Create environment files
|
|
49
|
+
console.log('🔐 Creating environment files...');
|
|
50
|
+
|
|
51
|
+
const envPath = path.join(ROOT_DIR, '.env');
|
|
52
|
+
if (!fs.existsSync(envPath)) {
|
|
53
|
+
const envContent = `# Database
|
|
54
|
+
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/nexu
|
|
55
|
+
DB_USER=postgres
|
|
56
|
+
DB_PASSWORD=postgres
|
|
57
|
+
DB_NAME=nexu
|
|
58
|
+
|
|
59
|
+
# API
|
|
60
|
+
API_URL=http://localhost:4000
|
|
61
|
+
|
|
62
|
+
# App
|
|
63
|
+
NODE_ENV=development
|
|
64
|
+
`;
|
|
65
|
+
fs.writeFileSync(envPath, envContent);
|
|
66
|
+
console.log('✅ Created .env file');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const webEnvPath = path.join(ROOT_DIR, 'apps', 'web', '.env.local');
|
|
70
|
+
const webAppsDir = path.join(ROOT_DIR, 'apps', 'web');
|
|
71
|
+
if (fs.existsSync(webAppsDir) && !fs.existsSync(webEnvPath)) {
|
|
72
|
+
const webEnvContent = `NEXT_PUBLIC_API_URL=http://localhost:4000
|
|
73
|
+
`;
|
|
74
|
+
fs.writeFileSync(webEnvPath, webEnvContent);
|
|
75
|
+
console.log('✅ Created apps/web/.env.local');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const apiEnvPath = path.join(ROOT_DIR, 'apps', 'api', '.env');
|
|
79
|
+
const apiAppsDir = path.join(ROOT_DIR, 'apps', 'api');
|
|
80
|
+
if (fs.existsSync(apiAppsDir) && !fs.existsSync(apiEnvPath)) {
|
|
81
|
+
const apiEnvContent = `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/nexu
|
|
82
|
+
PORT=4000
|
|
83
|
+
NODE_ENV=development
|
|
84
|
+
`;
|
|
85
|
+
fs.writeFileSync(apiEnvPath, apiEnvContent);
|
|
86
|
+
console.log('✅ Created apps/api/.env');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Build packages
|
|
90
|
+
console.log('🔨 Building packages...');
|
|
91
|
+
run(`${runCmd} build`);
|
|
92
|
+
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log('✅ Setup complete!');
|
|
95
|
+
console.log('');
|
|
96
|
+
console.log('Available commands:');
|
|
97
|
+
console.log(` ${runCmd} dev - Start development servers`);
|
|
98
|
+
console.log(` ${runCmd} build - Build all packages`);
|
|
99
|
+
console.log(` ${runCmd} lint - Run linting`);
|
|
100
|
+
console.log(` ${runCmd} test - Run tests`);
|
|
101
|
+
console.log(` ${runCmd} docker:dev - Start with Docker (dev)`);
|
|
102
|
+
console.log('');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Database
|
|
2
|
+
POSTGRES_USER=nexu
|
|
3
|
+
POSTGRES_PASSWORD=nexu
|
|
4
|
+
POSTGRES_DB=nexu
|
|
5
|
+
|
|
6
|
+
# Messaging
|
|
7
|
+
RABBITMQ_USER=nexu
|
|
8
|
+
RABBITMQ_PASSWORD=nexu
|
|
9
|
+
|
|
10
|
+
# Monitoring
|
|
11
|
+
GRAFANA_USER=admin
|
|
12
|
+
GRAFANA_PASSWORD=admin
|
|
13
|
+
|
|
14
|
+
# Storage
|
|
15
|
+
MINIO_USER=nexu
|
|
16
|
+
MINIO_PASSWORD=nexu1234
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
version: '3.8'
|
|
2
|
+
|
|
3
|
+
# Base docker-compose for external services
|
|
4
|
+
# Usage: docker compose -f services/docker-compose.yml --profile <profile> up -d
|
|
5
|
+
#
|
|
6
|
+
# Available profiles:
|
|
7
|
+
# - database: PostgreSQL, Redis
|
|
8
|
+
# - messaging: RabbitMQ, Kafka
|
|
9
|
+
# - monitoring: Prometheus, Grafana
|
|
10
|
+
# - storage: MinIO (S3-compatible)
|
|
11
|
+
# - search: Elasticsearch
|
|
12
|
+
# - all: All services
|
|
13
|
+
|
|
14
|
+
networks:
|
|
15
|
+
nexu-network:
|
|
16
|
+
driver: bridge
|
|
17
|
+
|
|
18
|
+
volumes:
|
|
19
|
+
postgres_data:
|
|
20
|
+
redis_data:
|
|
21
|
+
rabbitmq_data:
|
|
22
|
+
kafka_data:
|
|
23
|
+
zookeeper_data:
|
|
24
|
+
prometheus_data:
|
|
25
|
+
grafana_data:
|
|
26
|
+
minio_data:
|
|
27
|
+
elasticsearch_data:
|
|
28
|
+
|
|
29
|
+
services:
|
|
30
|
+
# ============================================
|
|
31
|
+
# DATABASE SERVICES
|
|
32
|
+
# ============================================
|
|
33
|
+
postgres:
|
|
34
|
+
image: postgres:16-alpine
|
|
35
|
+
container_name: nexu-postgres
|
|
36
|
+
profiles: ['database', 'all']
|
|
37
|
+
environment:
|
|
38
|
+
POSTGRES_USER: ${POSTGRES_USER:-nexu}
|
|
39
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-nexu}
|
|
40
|
+
POSTGRES_DB: ${POSTGRES_DB:-nexu}
|
|
41
|
+
ports:
|
|
42
|
+
- '5432:5432'
|
|
43
|
+
volumes:
|
|
44
|
+
- postgres_data:/var/lib/postgresql/data
|
|
45
|
+
- ./postgres/init:/docker-entrypoint-initdb.d
|
|
46
|
+
networks:
|
|
47
|
+
- nexu-network
|
|
48
|
+
healthcheck:
|
|
49
|
+
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-nexu}']
|
|
50
|
+
interval: 10s
|
|
51
|
+
timeout: 5s
|
|
52
|
+
retries: 5
|
|
53
|
+
|
|
54
|
+
redis:
|
|
55
|
+
image: redis:7-alpine
|
|
56
|
+
container_name: nexu-redis
|
|
57
|
+
profiles: ['database', 'all']
|
|
58
|
+
command: redis-server --appendonly yes
|
|
59
|
+
ports:
|
|
60
|
+
- '6379:6379'
|
|
61
|
+
volumes:
|
|
62
|
+
- redis_data:/data
|
|
63
|
+
networks:
|
|
64
|
+
- nexu-network
|
|
65
|
+
healthcheck:
|
|
66
|
+
test: ['CMD', 'redis-cli', 'ping']
|
|
67
|
+
interval: 10s
|
|
68
|
+
timeout: 5s
|
|
69
|
+
retries: 5
|
|
70
|
+
|
|
71
|
+
# ============================================
|
|
72
|
+
# MESSAGING SERVICES
|
|
73
|
+
# ============================================
|
|
74
|
+
rabbitmq:
|
|
75
|
+
image: rabbitmq:3-management-alpine
|
|
76
|
+
container_name: nexu-rabbitmq
|
|
77
|
+
profiles: ['messaging', 'all']
|
|
78
|
+
environment:
|
|
79
|
+
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-nexu}
|
|
80
|
+
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-nexu}
|
|
81
|
+
ports:
|
|
82
|
+
- '5672:5672'
|
|
83
|
+
- '15672:15672'
|
|
84
|
+
volumes:
|
|
85
|
+
- rabbitmq_data:/var/lib/rabbitmq
|
|
86
|
+
networks:
|
|
87
|
+
- nexu-network
|
|
88
|
+
healthcheck:
|
|
89
|
+
test: ['CMD', 'rabbitmq-diagnostics', '-q', 'ping']
|
|
90
|
+
interval: 30s
|
|
91
|
+
timeout: 10s
|
|
92
|
+
retries: 5
|
|
93
|
+
|
|
94
|
+
zookeeper:
|
|
95
|
+
image: confluentinc/cp-zookeeper:7.5.0
|
|
96
|
+
container_name: nexu-zookeeper
|
|
97
|
+
profiles: ['messaging', 'all']
|
|
98
|
+
environment:
|
|
99
|
+
ZOOKEEPER_CLIENT_PORT: 2181
|
|
100
|
+
ZOOKEEPER_TICK_TIME: 2000
|
|
101
|
+
ports:
|
|
102
|
+
- '2181:2181'
|
|
103
|
+
volumes:
|
|
104
|
+
- zookeeper_data:/var/lib/zookeeper/data
|
|
105
|
+
networks:
|
|
106
|
+
- nexu-network
|
|
107
|
+
|
|
108
|
+
kafka:
|
|
109
|
+
image: confluentinc/cp-kafka:7.5.0
|
|
110
|
+
container_name: nexu-kafka
|
|
111
|
+
profiles: ['messaging', 'all']
|
|
112
|
+
depends_on:
|
|
113
|
+
- zookeeper
|
|
114
|
+
environment:
|
|
115
|
+
KAFKA_BROKER_ID: 1
|
|
116
|
+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
|
117
|
+
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
|
|
118
|
+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
|
119
|
+
ports:
|
|
120
|
+
- '9092:9092'
|
|
121
|
+
volumes:
|
|
122
|
+
- kafka_data:/var/lib/kafka/data
|
|
123
|
+
networks:
|
|
124
|
+
- nexu-network
|
|
125
|
+
|
|
126
|
+
# ============================================
|
|
127
|
+
# MONITORING SERVICES
|
|
128
|
+
# ============================================
|
|
129
|
+
prometheus:
|
|
130
|
+
image: prom/prometheus:latest
|
|
131
|
+
container_name: nexu-prometheus
|
|
132
|
+
profiles: ['monitoring', 'all']
|
|
133
|
+
command:
|
|
134
|
+
- '--config.file=/etc/prometheus/prometheus.yml'
|
|
135
|
+
- '--storage.tsdb.path=/prometheus'
|
|
136
|
+
ports:
|
|
137
|
+
- '9090:9090'
|
|
138
|
+
volumes:
|
|
139
|
+
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
|
140
|
+
- prometheus_data:/prometheus
|
|
141
|
+
networks:
|
|
142
|
+
- nexu-network
|
|
143
|
+
|
|
144
|
+
grafana:
|
|
145
|
+
image: grafana/grafana:latest
|
|
146
|
+
container_name: nexu-grafana
|
|
147
|
+
profiles: ['monitoring', 'all']
|
|
148
|
+
environment:
|
|
149
|
+
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
|
|
150
|
+
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
|
|
151
|
+
ports:
|
|
152
|
+
- '3001:3000'
|
|
153
|
+
volumes:
|
|
154
|
+
- grafana_data:/var/lib/grafana
|
|
155
|
+
- ./grafana/provisioning:/etc/grafana/provisioning
|
|
156
|
+
networks:
|
|
157
|
+
- nexu-network
|
|
158
|
+
depends_on:
|
|
159
|
+
- prometheus
|
|
160
|
+
|
|
161
|
+
# ============================================
|
|
162
|
+
# STORAGE SERVICES
|
|
163
|
+
# ============================================
|
|
164
|
+
minio:
|
|
165
|
+
image: minio/minio:latest
|
|
166
|
+
container_name: nexu-minio
|
|
167
|
+
profiles: ['storage', 'all']
|
|
168
|
+
command: server /data --console-address ":9001"
|
|
169
|
+
environment:
|
|
170
|
+
MINIO_ROOT_USER: ${MINIO_USER:-nexu}
|
|
171
|
+
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD:-nexu1234}
|
|
172
|
+
ports:
|
|
173
|
+
- '9000:9000'
|
|
174
|
+
- '9001:9001'
|
|
175
|
+
volumes:
|
|
176
|
+
- minio_data:/data
|
|
177
|
+
networks:
|
|
178
|
+
- nexu-network
|
|
179
|
+
healthcheck:
|
|
180
|
+
test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
|
|
181
|
+
interval: 30s
|
|
182
|
+
timeout: 20s
|
|
183
|
+
retries: 3
|
|
184
|
+
|
|
185
|
+
# ============================================
|
|
186
|
+
# SEARCH SERVICES
|
|
187
|
+
# ============================================
|
|
188
|
+
elasticsearch:
|
|
189
|
+
image: elasticsearch:8.11.0
|
|
190
|
+
container_name: nexu-elasticsearch
|
|
191
|
+
profiles: ['search', 'all']
|
|
192
|
+
environment:
|
|
193
|
+
- discovery.type=single-node
|
|
194
|
+
- xpack.security.enabled=false
|
|
195
|
+
- 'ES_JAVA_OPTS=-Xms512m -Xmx512m'
|
|
196
|
+
ports:
|
|
197
|
+
- '9200:9200'
|
|
198
|
+
- '9300:9300'
|
|
199
|
+
volumes:
|
|
200
|
+
- elasticsearch_data:/usr/share/elasticsearch/data
|
|
201
|
+
networks:
|
|
202
|
+
- nexu-network
|
|
203
|
+
healthcheck:
|
|
204
|
+
test: ['CMD-SHELL', 'curl -s http://localhost:9200 | grep -q "cluster_name"']
|
|
205
|
+
interval: 30s
|
|
206
|
+
timeout: 10s
|
|
207
|
+
retries: 5
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
global:
|
|
2
|
+
scrape_interval: 15s
|
|
3
|
+
evaluation_interval: 15s
|
|
4
|
+
|
|
5
|
+
scrape_configs:
|
|
6
|
+
- job_name: 'prometheus'
|
|
7
|
+
static_configs:
|
|
8
|
+
- targets: ['localhost:9090']
|
|
9
|
+
|
|
10
|
+
# Add your app targets here
|
|
11
|
+
# - job_name: 'nexu-api'
|
|
12
|
+
# static_configs:
|
|
13
|
+
# - targets: ['host.docker.internal:3000']
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"jsx": "react-jsx",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"resolveJsonModule": true,
|
|
9
|
+
"allowJs": false,
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"declarationMap": true,
|
|
12
|
+
"sourceMap": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noImplicitAny": true,
|
|
16
|
+
"strictNullChecks": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true,
|
|
20
|
+
"esModuleInterop": true,
|
|
21
|
+
"allowSyntheticDefaultImports": true,
|
|
22
|
+
"forceConsistentCasingInFileNames": true,
|
|
23
|
+
"skipLibCheck": true,
|
|
24
|
+
"isolatedModules": true
|
|
25
|
+
},
|
|
26
|
+
"exclude": ["node_modules", "dist", ".next", "coverage", "packages/config", "scripts"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"globalDependencies": ["**/.env.*local"],
|
|
4
|
+
"globalEnv": ["NODE_ENV"],
|
|
5
|
+
"remoteCache": {
|
|
6
|
+
"signature": true
|
|
7
|
+
},
|
|
8
|
+
"tasks": {
|
|
9
|
+
"build": {
|
|
10
|
+
"dependsOn": ["^build"],
|
|
11
|
+
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
|
|
12
|
+
},
|
|
13
|
+
"dev": {
|
|
14
|
+
"cache": false,
|
|
15
|
+
"persistent": true
|
|
16
|
+
},
|
|
17
|
+
"lint": {
|
|
18
|
+
"dependsOn": ["^build"],
|
|
19
|
+
"outputs": []
|
|
20
|
+
},
|
|
21
|
+
"lint:fix": {
|
|
22
|
+
"outputs": []
|
|
23
|
+
},
|
|
24
|
+
"test": {
|
|
25
|
+
"dependsOn": ["build"],
|
|
26
|
+
"outputs": ["coverage/**"]
|
|
27
|
+
},
|
|
28
|
+
"test:coverage": {
|
|
29
|
+
"dependsOn": ["build"],
|
|
30
|
+
"outputs": ["coverage/**"]
|
|
31
|
+
},
|
|
32
|
+
"typecheck": {
|
|
33
|
+
"dependsOn": ["^build"],
|
|
34
|
+
"outputs": []
|
|
35
|
+
},
|
|
36
|
+
"clean": {
|
|
37
|
+
"cache": false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: ['**/*.{test,spec}.{ts,tsx}'],
|
|
8
|
+
exclude: ['**/node_modules/**', '**/dist/**'],
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: 'v8',
|
|
11
|
+
reporter: ['text', 'json', 'html'],
|
|
12
|
+
exclude: ['node_modules/', 'dist/', '**/*.config.*', '**/*.d.ts', '**/types/'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|