sdfsd
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
module.exports = { root: true, env: { node: true }, extends: ['eslint:recommended'] };
|
|
||||||
3
api/.gitignore
vendored
3
api/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
.next
|
|
||||||
styles/tailwind.build.css
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
FROM node:20-alpine AS deps
|
|
||||||
WORKDIR /app
|
|
||||||
COPY package.json .
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
FROM node:20-alpine AS builder
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
|
||||||
COPY . .
|
|
||||||
RUN npx prisma generate && npm run build
|
|
||||||
|
|
||||||
FROM node:20-alpine AS runner
|
|
||||||
RUN apk add --no-cache openssl
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=builder /app/node_modules ./node_modules
|
|
||||||
COPY --from=builder /app/dist ./dist
|
|
||||||
COPY --from=builder /app/package.json ./package.json
|
|
||||||
COPY --from=builder /app/prisma ./prisma
|
|
||||||
EXPOSE 4000
|
|
||||||
CMD ["node", "dist/src/index.js"]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ci-electrical-api",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
|
|
||||||
"build": "tsc -p tsconfig.json",
|
|
||||||
"start": "node dist/index.js",
|
|
||||||
"lint": "eslint .",
|
|
||||||
"typecheck": "tsc --noEmit",
|
|
||||||
"seed": "node --loader ts-node/esm prisma/seed.ts",
|
|
||||||
"prisma:generate": "prisma generate",
|
|
||||||
"prisma:migrate": "prisma migrate dev"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"cors": "^2.8.5",
|
|
||||||
"dotenv": "^16.4.5",
|
|
||||||
"express": "^4.19.2",
|
|
||||||
"zod": "3.23.8",
|
|
||||||
"@prisma/client": "5.17.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/cors": "^2.8.17",
|
|
||||||
"@types/express": "^4.17.21",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"typescript": "^5.5.4",
|
|
||||||
"ts-node": "^10.9.2",
|
|
||||||
"ts-node-dev": "^2.0.0",
|
|
||||||
"prisma": "5.17.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
|
|
||||||
}
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgresql"
|
|
||||||
url = env("DATABASE_URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Listing {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
title String
|
|
||||||
slug String @unique
|
|
||||||
image String?
|
|
||||||
summary String
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
}
|
|
||||||
|
|
||||||
model Testimonial {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
name String
|
|
||||||
area String
|
|
||||||
text String
|
|
||||||
rating Int @default(5)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
await prisma.listing.upsert({
|
|
||||||
where: { slug: 'retail-lighting-retrofit-south-side' },
|
|
||||||
update: {},
|
|
||||||
create: {
|
|
||||||
title: 'Retail Lighting Retrofit — South Side',
|
|
||||||
slug: 'retail-lighting-retrofit-south-side',
|
|
||||||
image: '/images/project-1.jpg',
|
|
||||||
summary: 'LED conversion for 5,000 sq ft retail space; 35% energy savings.'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await prisma.listing.upsert({
|
|
||||||
where: { slug: 'panel-upgrade-ocean-drive' },
|
|
||||||
update: {},
|
|
||||||
create: {
|
|
||||||
title: 'Residential Panel Upgrade — Ocean Drive',
|
|
||||||
slug: 'panel-upgrade-ocean-drive',
|
|
||||||
image: '/images/project-2.jpg',
|
|
||||||
summary: '100A → 200A service upgrade with AFCI breakers and EV-ready outlet.'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await prisma.listing.upsert({
|
|
||||||
where: { slug: 'office-buildout-downtown' },
|
|
||||||
update: {},
|
|
||||||
create: {
|
|
||||||
title: 'Office Build-Out — Downtown',
|
|
||||||
slug: 'office-buildout-downtown',
|
|
||||||
image: '/images/project-3.jpg',
|
|
||||||
summary: 'Complete tenant build-out: power distribution, LED lighting, data wiring.'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await prisma.testimonial.createMany({
|
|
||||||
data: [
|
|
||||||
{ name: 'Maria S.', area: 'Ocean Drive', text: 'Panel upgrade done fast. No more tripping breakers!', rating: 5 },
|
|
||||||
{ name: 'David R.', area: 'Downtown', text: 'Office build-out finished on time. Great team.', rating: 5 },
|
|
||||||
{ name: 'Jennifer L.', area: 'Flour Bluff', text: 'Emergency repair on Sunday. Reliable service.', rating: 5 }
|
|
||||||
],
|
|
||||||
skipDuplicates: true
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Seed complete');
|
|
||||||
}
|
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import 'dotenv/config';
|
|
||||||
export const env = {
|
|
||||||
PORT: Number(process.env.PORT || 4000),
|
|
||||||
DATABASE_URL: process.env.DATABASE_URL || 'postgresql://postgres:postgres@localhost:5432/cielectrical?schema=public'
|
|
||||||
};
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import express from 'express';
|
|
||||||
import cors from 'cors';
|
|
||||||
import { env } from './env.js';
|
|
||||||
import listings from './routes/listings.js';
|
|
||||||
import { prisma } from './prisma.js';
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
app.use(cors());
|
|
||||||
app.use(express.json());
|
|
||||||
|
|
||||||
app.get('/health', async (_req, res) => {
|
|
||||||
try {
|
|
||||||
await prisma.$queryRaw`SELECT 1`;
|
|
||||||
res.json({ ok: true });
|
|
||||||
} catch (e) {
|
|
||||||
res.status(500).json({ ok: false });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/listings', listings);
|
|
||||||
|
|
||||||
app.listen(env.PORT, () => {
|
|
||||||
console.log(`API on :${env.PORT}`);
|
|
||||||
});
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
export const prisma = new PrismaClient();
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { Router } from 'express';
|
|
||||||
import { prisma } from '../prisma.js';
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get('/', async (_req, res) => {
|
|
||||||
const listings = await prisma.listing.findMany({ orderBy: { createdAt: 'desc' }, take: 10 });
|
|
||||||
res.json(listings);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2022",
|
|
||||||
"lib": [
|
|
||||||
"ES2022"
|
|
||||||
],
|
|
||||||
"module": "NodeNext",
|
|
||||||
"moduleResolution": "NodeNext",
|
|
||||||
"outDir": "dist",
|
|
||||||
"strict": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"forceConsistentCasingInFileNames": true
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src",
|
|
||||||
"prisma/**/*.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,53 +1,16 @@
|
|||||||
version: "3.9"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
db:
|
cielectrical-web:
|
||||||
image: postgres:16-alpine
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-cielectrical}
|
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
volumes:
|
|
||||||
- db_data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-cielectrical}"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
api:
|
|
||||||
build: ./api
|
|
||||||
environment:
|
|
||||||
NODE_ENV: production
|
|
||||||
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-cielectrical}?schema=public
|
|
||||||
PORT: 4000
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
ports:
|
|
||||||
- "4000:4000"
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "node", "-e", "fetch('http://localhost:4000/health').then(()=>process.exit(0)).catch(()=>process.exit(1))"]
|
|
||||||
interval: 15s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
web:
|
|
||||||
build: ./web
|
build: ./web
|
||||||
|
container_name: cielectrical-web
|
||||||
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
NEXT_TELEMETRY_DISABLED: "1"
|
NEXT_TELEMETRY_DISABLED: "1"
|
||||||
API_BASE_URL: http://api:4000
|
NEXT_PUBLIC_SITE_URL: https://ci-electrical.com
|
||||||
NEXT_PUBLIC_SITE_URL: http://localhost:3000
|
# API_BASE_URL wurde entfernt, da das Backend wegfällt
|
||||||
depends_on:
|
networks:
|
||||||
api:
|
- bizmatch
|
||||||
condition: service_healthy
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
volumes:
|
networks:
|
||||||
db_data:
|
bizmatch:
|
||||||
|
external: true
|
||||||
Reference in New Issue
Block a user