This commit is contained in:
2026-04-10 16:55:38 -05:00
parent 3e9ca1a146
commit 2d3b97864e
12 changed files with 10 additions and 238 deletions

View File

@@ -1 +0,0 @@
module.exports = { root: true, env: { node: true }, extends: ['eslint:recommended'] };

3
api/.gitignore vendored
View File

@@ -1,3 +0,0 @@
node_modules
.next
styles/tailwind.build.css

View File

@@ -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"]

View File

@@ -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"
}
}

View File

@@ -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())
}

View File

@@ -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());

View File

@@ -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'
};

View File

@@ -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}`);
});

View File

@@ -1,2 +0,0 @@
import { PrismaClient } from '@prisma/client';
export const prisma = new PrismaClient();

View File

@@ -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;

View File

@@ -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"
]
}

View File

@@ -1,53 +1,16 @@
version: "3.9"
services:
db:
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:
cielectrical-web:
build: ./web
container_name: cielectrical-web
restart: unless-stopped
environment:
NODE_ENV: production
NEXT_TELEMETRY_DISABLED: "1"
API_BASE_URL: http://api:4000
NEXT_PUBLIC_SITE_URL: http://localhost:3000
depends_on:
api:
condition: service_healthy
ports:
- "3000:3000"
restart: unless-stopped
NEXT_PUBLIC_SITE_URL: https://ci-electrical.com
# API_BASE_URL wurde entfernt, da das Backend wegfällt
networks:
- bizmatch
volumes:
db_data:
networks:
bizmatch:
external: true