chore: add pnpm workspace configuration for apps and packages
This commit is contained in:
57
apps/backend/Dockerfile
Normal file
57
apps/backend/Dockerfile
Normal file
@@ -0,0 +1,57 @@
|
||||
# apps/backend/Dockerfile
|
||||
FROM node:24-alpine AS base
|
||||
RUN npm install -g pnpm@8
|
||||
|
||||
FROM base AS dependencies
|
||||
WORKDIR /app
|
||||
|
||||
# Copy workspace configuration
|
||||
COPY pnpm-workspace.yaml package.json ./
|
||||
COPY apps/backend/package.json ./apps/backend/
|
||||
COPY packages/shared/package.json ./packages/shared/
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS build
|
||||
WORKDIR /app
|
||||
COPY --from=dependencies /app/node_modules ./node_modules
|
||||
COPY --from=dependencies /app/apps/backend/node_modules ./apps/backend/node_modules
|
||||
COPY --from=dependencies /app/packages/shared/node_modules ./packages/shared/node_modules
|
||||
|
||||
# Copy source code
|
||||
COPY packages/shared ./packages/shared
|
||||
COPY apps/backend ./apps/backend
|
||||
COPY prisma ./prisma
|
||||
|
||||
# Build shared packages first
|
||||
RUN pnpm --filter @dreamchat/shared build
|
||||
|
||||
# Generate Prisma client
|
||||
RUN pnpm db:generate
|
||||
|
||||
# Build backend
|
||||
RUN pnpm --filter @dreamchat/backend build
|
||||
|
||||
FROM base AS production
|
||||
WORKDIR /app
|
||||
|
||||
# Copy only production dependencies
|
||||
COPY --from=dependencies /app/node_modules ./node_modules
|
||||
COPY --from=dependencies /app/apps/backend/node_modules ./apps/backend/node_modules
|
||||
COPY --from=build /app/apps/backend/dist ./dist
|
||||
COPY --from=build /app/packages/shared/dist ./node_modules/@dreamchat/shared/dist
|
||||
COPY --from=build /app/node_modules/.pnpm/@prisma+client* ./node_modules/.pnpm/
|
||||
COPY --from=build /app/node_modules/@prisma ./node_modules/@prisma
|
||||
|
||||
# Create logs directory
|
||||
RUN mkdir -p /app/logs
|
||||
|
||||
# Non-root user
|
||||
RUN addgroup -g 1001 -S nodejs
|
||||
RUN adduser -S nodejs -u 1001
|
||||
USER nodejs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "dist/main.js"]
|
||||
50
apps/backend/package.json
Normal file
50
apps/backend/package.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@dreamchat/backend",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"dev": "nest start --watch",
|
||||
"start": "node dist/main",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
|
||||
"db:migrate": "prisma migrate deploy",
|
||||
"db:generate": "prisma generate",
|
||||
"db:seed": "prisma db seed",
|
||||
"clean": "rm -r dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dreamchat/shared": "workspace:*",
|
||||
"@nestjs/common": "^11.1.14",
|
||||
"@nestjs/core": "^11.1.14",
|
||||
"@nestjs/platform-express": "^11.1.14",
|
||||
"@nestjs/platform-socket.io": "^11.1.14",
|
||||
"@nestjs/websockets": "^11.1.14",
|
||||
"@prisma/client": "^7.4.1",
|
||||
"@xenova/transformers": "^2.15.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"dotenv": "^17.3.1",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"puppeteer": "^24.37.5",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.0",
|
||||
"socket.io": "^4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^11.0.16",
|
||||
"@nestjs/testing": "^11.1.14",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/jsonwebtoken": "^9.0.0",
|
||||
"@types/node": "^24.10.13",
|
||||
"@types/passport-jwt": "^4.0.0",
|
||||
"@types/passport-local": "^1.0.0",
|
||||
"jest": "^30.2.0",
|
||||
"prisma": "^7.4.1",
|
||||
"typescript": "^5.3.0"
|
||||
}
|
||||
}
|
||||
13
apps/backend/prisma.config.ts
Normal file
13
apps/backend/prisma.config.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineConfig, env } from 'prisma/config';
|
||||
import 'dotenv/config';
|
||||
|
||||
export default defineConfig({
|
||||
schema: 'prisma/',
|
||||
migrations: {
|
||||
path: 'prisma/migrations',
|
||||
seed: 'tsx prisma/seed.ts',
|
||||
},
|
||||
datasource: {
|
||||
url: env('DATABASE_URL'),
|
||||
},
|
||||
});
|
||||
14
apps/backend/prisma/schema.prisma
Normal file
14
apps/backend/prisma/schema.prisma
Normal file
@@ -0,0 +1,14 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["strictUndefinedChecks"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
55
apps/backend/prisma/seed.ts
Normal file
55
apps/backend/prisma/seed.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Seeding database...');
|
||||
|
||||
// Create default admin user
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: 'admin@dreamchat.local' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'admin@dreamchat.local',
|
||||
username: 'admin',
|
||||
role: 'ADMIN',
|
||||
passwordHash: '$2b$10$YourHashedPasswordHere', // Replace with actual hash
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`✅ Created admin user: ${admin.email}`);
|
||||
|
||||
// Create a sample character
|
||||
const character = await prisma.character.upsert({
|
||||
where: {
|
||||
id: '00000000-0000-0000-0000-000000000001'
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
id: '00000000-0000-0000-0000-000000000001',
|
||||
name: 'Alice',
|
||||
personalityPrompt: 'You are Alice, a curious and adventurous explorer who loves discovering new things. You are friendly, witty, and always eager to help.',
|
||||
backstory: 'Alice grew up in a small village at the edge of a vast forest. From a young age, she was fascinated by the unknown and would often venture into the woods to explore.',
|
||||
attributes: {
|
||||
traits: ['curious', 'brave', 'witty', 'friendly'],
|
||||
age: 25,
|
||||
species: 'human',
|
||||
skills: ['navigation', 'survival', 'cartography'],
|
||||
},
|
||||
userId: admin.id,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`✅ Created sample character: ${character.name}`);
|
||||
|
||||
console.log('✅ Seeding complete!');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('❌ Seeding failed:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
21
apps/backend/tsconfig.json
Normal file
21
apps/backend/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
55
apps/frontend/Dockerfile
Normal file
55
apps/frontend/Dockerfile
Normal file
@@ -0,0 +1,55 @@
|
||||
# apps/frontend/Dockerfile
|
||||
FROM node:24-alpine AS base
|
||||
RUN npm install -g pnpm@8
|
||||
|
||||
FROM base AS dependencies
|
||||
WORKDIR /app
|
||||
|
||||
# Copy workspace configuration
|
||||
COPY pnpm-workspace.yaml package.json ./
|
||||
COPY apps/frontend/package.json ./apps/frontend/
|
||||
COPY packages/shared/package.json ./packages/shared/
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS build
|
||||
WORKDIR /app
|
||||
COPY --from=dependencies /app/node_modules ./node_modules
|
||||
COPY --from=dependencies /app/apps/frontend/node_modules ./apps/frontend/node_modules
|
||||
COPY --from=dependencies /app/packages/shared/node_modules ./packages/shared/node_modules
|
||||
|
||||
# Copy source code
|
||||
COPY packages/shared ./packages/shared
|
||||
COPY apps/frontend ./apps/frontend
|
||||
|
||||
# Build shared packages first
|
||||
RUN pnpm --filter @dreamchat/shared build
|
||||
|
||||
# Build frontend
|
||||
RUN pnpm --filter @dreamchat/frontend build
|
||||
|
||||
# Production stage - using serve for static files
|
||||
# External reverse proxy (nginx/traefik/etc.) expected
|
||||
FROM node:24-alpine AS production
|
||||
WORKDIR /app
|
||||
|
||||
# Install serve
|
||||
RUN npm install -g serve
|
||||
|
||||
# Copy built assets
|
||||
COPY --from=build /app/apps/frontend/dist ./dist
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S nodejs
|
||||
RUN adduser -S nodejs -u 1001
|
||||
USER nodejs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
# Serve static files
|
||||
# Note: External reverse proxy should handle:
|
||||
# - SSL/TLS termination
|
||||
# - Path routing (/api -> backend, / -> frontend)
|
||||
# - WebSocket proxying
|
||||
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||||
33
apps/frontend/package.json
Normal file
33
apps/frontend/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@dreamchat/frontend",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest",
|
||||
"lint": "eslint . --ext ts,tsx",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dreamchat/shared": "workspace:*",
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.20.0",
|
||||
"socket.io-client": "^4.7.0",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"postcss": "^8.4.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5.3.0",
|
||||
"vite": "^5.0.0",
|
||||
"vitest": "^1.0.0"
|
||||
}
|
||||
}
|
||||
25
apps/frontend/tsconfig.json
Normal file
25
apps/frontend/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
10
apps/frontend/tsconfig.node.json
Normal file
10
apps/frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
30
apps/frontend/vite.config.ts
Normal file
30
apps/frontend/vite.config.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
// Development proxy - external reverse proxy used in production
|
||||
'/api': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/ws': {
|
||||
target: 'ws://localhost:3000',
|
||||
ws: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
sourcemap: true,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user