Compare commits
14 Commits
0b4e4207d1
...
79098f59c6
| Author | SHA1 | Date |
|---|---|---|
|
|
79098f59c6 | |
|
|
345761da87 | |
|
|
7e00b4d71b | |
|
|
715220f6d5 | |
|
|
dc79ac3df7 | |
|
|
a545b84f6c | |
|
|
2d293d8b12 | |
|
|
d008b50892 | |
|
|
1a1eaa46ae | |
|
|
a9dcb66e5b | |
|
|
33ea71dc12 | |
|
|
91bcf3c2ed | |
|
|
36ef7eb4bf | |
|
|
ae12eb87f0 |
|
|
@ -0,0 +1,6 @@
|
|||
node_modules
|
||||
.git
|
||||
.idea
|
||||
.vscode
|
||||
dist
|
||||
coverage
|
||||
|
|
@ -1,19 +1,25 @@
|
|||
# Build Stage
|
||||
FROM node:18-alpine AS build
|
||||
|
||||
# --- STAGE 1: Build ---
|
||||
FROM node:22-alpine AS builder
|
||||
WORKDIR /app
|
||||
# HIER KEIN NODE_ENV=production setzen! Wir brauchen devDependencies zum Bauen.
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Runtime Stage
|
||||
FROM node:18-alpine
|
||||
|
||||
# --- STAGE 2: Runtime ---
|
||||
FROM node:22-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/dist /app/dist
|
||||
COPY --from=build /app/package*.json /app/
|
||||
|
||||
RUN npm install --production
|
||||
# HIER ist es richtig!
|
||||
ENV NODE_ENV=production
|
||||
|
||||
CMD ["node", "dist/main.js"]
|
||||
COPY --from=builder /app/dist /app/dist
|
||||
COPY --from=builder /app/package*.json /app/
|
||||
|
||||
# Installiert nur "dependencies" (Nest core, TypeORM, Helmet, Sharp etc.)
|
||||
# "devDependencies" (TypeScript, Jest, ESLint) werden weggelassen.
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
# WICHTIG: Pfad prüfen (siehe Punkt 2 unten)
|
||||
CMD ["node", "dist/src/main.js"]
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
services:
|
||||
app:
|
||||
image: node:22-alpine
|
||||
container_name: bizmatch-app
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ./:/app
|
||||
- node_modules:/app/node_modules
|
||||
ports:
|
||||
- '3001:3001'
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- DATABASE_URL
|
||||
command: sh -c "if [ ! -f node_modules/.installed ]; then npm ci && touch node_modules/.installed; fi && npm run build && node dist/src/main.js"
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- bizmatch
|
||||
|
||||
postgres:
|
||||
container_name: bizmatchdb
|
||||
image: postgres:17-alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- bizmatch-db-data:/var/lib/postgresql/data
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
ports:
|
||||
- '5434:5432'
|
||||
networks:
|
||||
- bizmatch
|
||||
|
||||
volumes:
|
||||
bizmatch-db-data:
|
||||
driver: local
|
||||
node_modules:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
bizmatch:
|
||||
external: true
|
||||
|
|
@ -1,13 +1,41 @@
|
|||
# STAGE 1: Build
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
# Wir erstellen ein Arbeitsverzeichnis, das eine Ebene über dem Projekt liegt
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# 1. Wir kopieren die Backend-Models an die Stelle, wo Angular sie erwartet
|
||||
# Deine Pfade suchen nach ../bizmatch-server, also legen wir es daneben.
|
||||
COPY bizmatch-server/src/models ./bizmatch-server/src/models
|
||||
|
||||
# 2. Jetzt kümmern wir uns um das Frontend
|
||||
# Wir kopieren erst die package Files für besseres Caching
|
||||
COPY bizmatch/package*.json ./bizmatch/
|
||||
|
||||
# Wechseln in den Frontend Ordner zum Installieren
|
||||
WORKDIR /usr/src/app/bizmatch
|
||||
RUN npm ci
|
||||
|
||||
# 3. Den Rest des Frontends kopieren
|
||||
COPY bizmatch/ .
|
||||
|
||||
# 4. Bauen
|
||||
RUN npm run build:ssr
|
||||
|
||||
# --- STAGE 2: Runtime ---
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# GANZEN dist-Ordner kopieren, nicht nur bizmatch
|
||||
COPY dist ./dist
|
||||
COPY package*.json ./
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=4000
|
||||
|
||||
# Kopiere das Ergebnis aus dem Builder (Pfad beachten!)
|
||||
COPY --from=builder /usr/src/app/bizmatch/dist /app/dist
|
||||
COPY --from=builder /usr/src/app/bizmatch/package*.json /app/
|
||||
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
EXPOSE 4200
|
||||
EXPOSE 4000
|
||||
|
||||
CMD ["node", "dist/bizmatch/server/server.mjs"]
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@
|
|||
],
|
||||
"styles": [
|
||||
"src/styles.scss",
|
||||
"src/styles/lazy-load.css"
|
||||
"src/styles/lazy-load.css",
|
||||
"node_modules/quill/dist/quill.snow.css",
|
||||
"node_modules/leaflet/dist/leaflet.css",
|
||||
"node_modules/ngx-sharebuttons/themes/default.scss"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
|
|
@ -98,7 +101,8 @@
|
|||
],
|
||||
"optimization": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
"sourceMap": true,
|
||||
"outputHashing": "all"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
services:
|
||||
bizmatch-ssr:
|
||||
build: .
|
||||
image: bizmatch-ssr
|
||||
container_name: bizmatch-ssr
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '4200:4200'
|
||||
environment:
|
||||
NODE_ENV: DEVELOPMENT
|
||||
|
|
@ -7,6 +7,10 @@ import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@a
|
|||
import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
|
||||
import { getAuth, provideAuth } from '@angular/fire/auth';
|
||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||
import { GALLERY_CONFIG, GalleryConfig } from 'ng-gallery';
|
||||
import { provideQuillConfig } from 'ngx-quill';
|
||||
import { provideShareButtonsOptions, SharerMethods, withConfig } from 'ngx-sharebuttons';
|
||||
import { shareIcons } from 'ngx-sharebuttons/icons';
|
||||
import { environment } from '../environments/environment';
|
||||
import { routes } from './app.routes';
|
||||
import { AuthInterceptor } from './interceptors/auth.interceptor';
|
||||
|
|
@ -20,7 +24,8 @@ import { createLogger } from './utils/utils';
|
|||
const logger = createLogger('ApplicationConfig');
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideClientHydration(),
|
||||
// Temporarily disabled for SSR debugging
|
||||
// provideClientHydration(),
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
|
|
@ -43,6 +48,13 @@ export const appConfig: ApplicationConfig = {
|
|||
provide: 'TIMEOUT_DURATION',
|
||||
useValue: 5000, // Standard-Timeout von 5 Sekunden
|
||||
},
|
||||
{
|
||||
provide: GALLERY_CONFIG,
|
||||
useValue: {
|
||||
autoHeight: true,
|
||||
imageSize: 'cover',
|
||||
} as GalleryConfig,
|
||||
},
|
||||
{ provide: ErrorHandler, useClass: GlobalErrorHandler }, // Registriere den globalen ErrorHandler
|
||||
{
|
||||
provide: IMAGE_CONFIG,
|
||||
|
|
@ -50,6 +62,13 @@ export const appConfig: ApplicationConfig = {
|
|||
disableImageSizeWarning: true,
|
||||
},
|
||||
},
|
||||
provideShareButtonsOptions(
|
||||
shareIcons(),
|
||||
withConfig({
|
||||
debug: true,
|
||||
sharerMethod: SharerMethods.Anchor,
|
||||
}),
|
||||
),
|
||||
provideRouter(
|
||||
routes,
|
||||
withEnabledBlockingInitialNavigation(),
|
||||
|
|
@ -60,6 +79,18 @@ export const appConfig: ApplicationConfig = {
|
|||
),
|
||||
...(environment.production ? [POSTHOG_INIT_PROVIDER] : []),
|
||||
provideAnimations(),
|
||||
provideQuillConfig({
|
||||
modules: {
|
||||
syntax: true,
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'], // Einige Standardoptionen
|
||||
[{ header: [1, 2, 3, false] }], // Benutzerdefinierte Header
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ color: [] }], // Dropdown mit Standardfarben
|
||||
['clean'], // Entfernt Formatierungen
|
||||
],
|
||||
},
|
||||
}),
|
||||
provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
|
||||
provideAuth(() => getAuth()),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,8 +1,24 @@
|
|||
import { RenderMode, ServerRoute } from '@angular/ssr';
|
||||
|
||||
export const serverRoutes: ServerRoute[] = [
|
||||
{ path: 'home', renderMode: RenderMode.Prerender },
|
||||
{ path: 'home', renderMode: RenderMode.Server }, // Das hatten wir vorhin gefixt
|
||||
|
||||
// WICHTIG: Alle geschützten Routen nur im Browser rendern!
|
||||
// Damit überspringt der Server den AuthGuard Check komplett und schickt
|
||||
// nur eine leere Hülle (index.html), die der Browser dann füllt.
|
||||
{ path: 'account', renderMode: RenderMode.Client },
|
||||
{ path: 'account/**', renderMode: RenderMode.Client },
|
||||
{ path: 'myListings', renderMode: RenderMode.Client },
|
||||
{ path: 'myFavorites', renderMode: RenderMode.Client },
|
||||
{ path: 'createBusinessListing', renderMode: RenderMode.Client },
|
||||
{ path: 'createCommercialPropertyListing', renderMode: RenderMode.Client },
|
||||
{ path: 'editBusinessListing/**', renderMode: RenderMode.Client },
|
||||
{ path: 'editCommercialPropertyListing/**', renderMode: RenderMode.Client },
|
||||
|
||||
// Statische Seiten
|
||||
{ path: 'terms-of-use', renderMode: RenderMode.Prerender },
|
||||
{ path: 'privacy-statement', renderMode: RenderMode.Prerender },
|
||||
|
||||
// Fallback
|
||||
{ path: '**', renderMode: RenderMode.Server }
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,15 +1,27 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { createLogger } from '../utils/utils';
|
||||
const logger = createLogger('AuthGuard');
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private router: Router,
|
||||
@Inject(PLATFORM_ID) private platformId: Object
|
||||
) {}
|
||||
|
||||
async canActivate(): Promise<boolean> {
|
||||
// 1. SSR CHECK: Wenn wir auf dem Server sind, immer erlauben!
|
||||
// Der Server soll nicht redirecten, sondern einfach das HTML rendern.
|
||||
if (!isPlatformBrowser(this.platformId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. CLIENT CHECK: Das läuft nur im Browser
|
||||
const token = await this.authService.getToken();
|
||||
if (token) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<!-- SEO-optimized heading -->
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl md:text-4xl font-bold text-neutral-900 mb-2">Businesses for Sale - Find Your Next Business Opportunity</h1>
|
||||
<p class="text-lg text-neutral-600">Discover profitable business opportunities across the United States. Browse
|
||||
<p class="text-lg text-neutral-600">Discover profitable business opportunities across the State of Texas. Browse
|
||||
verified listings from business owners and brokers.</p>
|
||||
<div class="mt-4 text-base text-neutral-700 max-w-4xl">
|
||||
<p>BizMatch features a curated selection of businesses for sale across diverse industries and price ranges. Browse opportunities in sectors like restaurants, retail, franchises, services, e-commerce, and manufacturing. Each listing includes financial details, years established, location information, and seller contact details. Our marketplace connects business buyers with sellers and brokers nationwide, making it easy to find your next business opportunity.</p>
|
||||
|
|
|
|||
|
|
@ -129,23 +129,16 @@
|
|||
mask="(000) 000-0000"></app-validated-input>
|
||||
<app-validated-input label="Company Website" name="companyWebsite"
|
||||
[(ngModel)]="user.companyWebsite"></app-validated-input>
|
||||
<!-- <app-validated-input label="Company Location" name="companyLocation" [(ngModel)]="user.companyLocation"></app-validated-input> -->
|
||||
<!-- <app-validated-city label="Company Location" name="location" [(ngModel)]="user.location"></app-validated-city> -->
|
||||
<app-validated-location label="Company Location" name="location"
|
||||
[(ngModel)]="user.location"></app-validated-location>
|
||||
</div>
|
||||
|
||||
<!-- <div>
|
||||
<label for="companyOverview" class="block text-sm font-medium text-gray-700">Company Overview</label>
|
||||
<quill-editor [(ngModel)]="user.companyOverview" name="companyOverview" [modules]="quillModules"></quill-editor>
|
||||
</div> -->
|
||||
|
||||
<div>
|
||||
<app-validated-quill label="Company Overview" name="companyOverview"
|
||||
[(ngModel)]="user.companyOverview"></app-validated-quill>
|
||||
</div>
|
||||
<div>
|
||||
<!-- <label for="offeredServices" class="block text-sm font-medium text-gray-700">Services We Offer</label>
|
||||
<quill-editor [(ngModel)]="user.offeredServices" name="offeredServices" [modules]="quillModules"></quill-editor> -->
|
||||
<app-validated-quill label="Services We Offer" name="offeredServices"
|
||||
[(ngModel)]="user.offeredServices"></app-validated-quill>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ChangeDetectorRef, Component } from '@angular/core';
|
|||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { APP_ICONS } from '../../../utils/fontawesome-icons';
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { QuillModule, provideQuillConfig } from 'ngx-quill';
|
||||
import { QuillModule } from 'ngx-quill';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||
import { AutoCompleteCompleteEvent, Invoice, UploadParams, ValidationMessage, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
|
|
@ -47,19 +47,7 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
|||
],
|
||||
providers: [
|
||||
TitleCasePipe,
|
||||
DatePipe,
|
||||
provideQuillConfig({
|
||||
modules: {
|
||||
syntax: true,
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'],
|
||||
[{ header: [1, 2, 3, false] }],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ color: [] }],
|
||||
['clean'],
|
||||
],
|
||||
},
|
||||
}) as any,
|
||||
DatePipe
|
||||
],
|
||||
templateUrl: './account.component.html',
|
||||
styleUrls: [
|
||||
|
|
@ -77,9 +65,6 @@ export class AccountComponent {
|
|||
editorModules = TOOLBAR_OPTIONS;
|
||||
env = environment;
|
||||
faTrash = APP_ICONS.faTrash;
|
||||
quillModules = {
|
||||
toolbar: [['bold', 'italic', 'underline', 'strike'], [{ list: 'ordered' }, { list: 'bullet' }], [{ header: [1, 2, 3, 4, 5, 6, false] }], [{ color: [] }, { background: [] }], ['clean']],
|
||||
};
|
||||
uploadParams: UploadParams;
|
||||
validationMessages: ValidationMessage[] = [];
|
||||
customerTypeOptions: Array<{ value: string; label: string }> = [];
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import { QuillModule } from 'ngx-quill';
|
|||
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { NgxCurrencyDirective } from 'ngx-currency';
|
||||
import { provideQuillConfig } from 'ngx-quill';
|
||||
import { BusinessListing, CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||
import { AutoCompleteCompleteEvent, ImageProperty, createDefaultBusinessListing, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
|
||||
|
|
@ -48,20 +47,6 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
|||
ValidatedTextareaComponent,
|
||||
ValidatedLocationComponent,
|
||||
],
|
||||
providers: [
|
||||
provideQuillConfig({
|
||||
modules: {
|
||||
syntax: true,
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'],
|
||||
[{ header: [1, 2, 3, false] }],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ color: [] }],
|
||||
['clean'],
|
||||
],
|
||||
},
|
||||
}) as any,
|
||||
],
|
||||
templateUrl: './edit-business-listing.component.html',
|
||||
styleUrls: [
|
||||
'./edit-business-listing.component.scss',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { APP_ICONS } from '../../../utils/fontawesome-icons';
|
|||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { NgxCurrencyDirective } from 'ngx-currency';
|
||||
import { ImageCropperComponent } from 'ngx-image-cropper';
|
||||
import { QuillModule, provideQuillConfig } from 'ngx-quill';
|
||||
import { QuillModule } from 'ngx-quill';
|
||||
import { BusinessListing, CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||
import { AutoCompleteCompleteEvent, ImageProperty, UploadParams, createDefaultCommercialPropertyListing, emailToDirName } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||
|
||||
|
|
@ -53,20 +53,6 @@ import { TOOLBAR_OPTIONS } from '../../utils/defaults';
|
|||
ValidatedLocationComponent,
|
||||
ImageCropAndUploadComponent,
|
||||
],
|
||||
providers: [
|
||||
provideQuillConfig({
|
||||
modules: {
|
||||
syntax: true,
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline'],
|
||||
[{ header: [1, 2, 3, false] }],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
[{ color: [] }],
|
||||
['clean'],
|
||||
],
|
||||
},
|
||||
}) as any,
|
||||
],
|
||||
templateUrl: './edit-commercial-property-listing.component.html',
|
||||
styleUrls: [
|
||||
'./edit-commercial-property-listing.component.scss',
|
||||
|
|
|
|||
|
|
@ -1,8 +1,20 @@
|
|||
// SSR-safe: check if window exists (it doesn't on server-side)
|
||||
const hostname = typeof window !== 'undefined' ? window.location.hostname : 'localhost';
|
||||
// SSR-safe: check if window exists
|
||||
// Im Browser nehmen wir den aktuellen Host (z.B. localhost).
|
||||
// Auf dem Server (SSR in Docker) nehmen wir 'bizmatch-app' (der Name des Backend-Containers).
|
||||
const isBrowser = typeof window !== 'undefined' && window.navigator.userAgent !== 'node';
|
||||
const hostname = isBrowser ? window.location.hostname : 'bizmatch-app';
|
||||
// Im Server-Modus nutzen wir den internen Docker-Namen
|
||||
const internalUrl = 'http://bizmatch-app:3001';
|
||||
// Im Browser-Modus die öffentliche URL
|
||||
const publicUrl = 'https://api.bizmatch.net';
|
||||
const calculatedApiBaseUrl = isBrowser ? publicUrl : internalUrl;
|
||||
// WICHTIG: Port anpassen!
|
||||
// Lokal läuft das Backend auf 3001. Im Docker Container auch auf 3001.
|
||||
// Deine alte Config hatte hier :4200 stehen, das war falsch (das ist das Frontend).
|
||||
export const environment_base = {
|
||||
// apiBaseUrl: 'http://localhost:3000',
|
||||
apiBaseUrl: `http://${hostname}:4200`,
|
||||
// GETTER FUNCTION für die API URL (besser als statischer String für diesen Fall)
|
||||
apiBaseUrl: calculatedApiBaseUrl,
|
||||
imageBaseUrl: 'https://dev.bizmatch.net',
|
||||
buildVersion: '<BUILD_VERSION>',
|
||||
mailinfoUrl: 'https://dev.bizmatch.net',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { environment_base } from './environment.base';
|
||||
|
||||
export const environment = environment_base;
|
||||
export const environment = { ...environment_base }; // Kopie erstellen
|
||||
|
||||
environment.production = true;
|
||||
|
||||
// WICHTIG: Diese Zeile auskommentieren, solange du lokal testest!
|
||||
// Sonst greift er immer aufs Internet zu, statt auf deinen lokalen Docker-Container.
|
||||
environment.apiBaseUrl = 'https://api.bizmatch.net';
|
||||
|
||||
environment.mailinfoUrl = 'https://www.bizmatch.net';
|
||||
environment.imageBaseUrl = 'https://api.bizmatch.net';
|
||||
environment.imageBaseUrl = 'https://www.bizmatch.net';// Ggf. auch auskommentieren, wenn Bilder lokal liegen
|
||||
|
||||
environment.POSTHOG_KEY = 'phc_eUIcIq0UPVzEDtZLy78klKhGudyagBz3goDlKx8SQFe';
|
||||
environment.POSTHOG_HOST = 'https://eu.i.posthog.com';
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
// External CSS imports - these URL imports don't trigger deprecation warnings
|
||||
// Using css2 API with specific weights for better performance
|
||||
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap');
|
||||
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css');
|
||||
|
||||
// Local CSS files loaded as CSS (not SCSS) to avoid @import deprecation
|
||||
// Note: These are loaded via angular.json styles array is the preferred approach,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
services:
|
||||
# --- FRONTEND ---
|
||||
bizmatch-ssr:
|
||||
build:
|
||||
context: . # Pfad zum Angular Ordner
|
||||
dockerfile: bizmatch/Dockerfile
|
||||
image: bizmatch-ssr
|
||||
container_name: bizmatch-ssr
|
||||
extra_hosts:
|
||||
- "localhost:host-gateway"
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '4200:4000' # Extern 4200 -> Intern 4000 (SSR)
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
volumes:
|
||||
- ./bizmatch-server/pictures:/app/pictures
|
||||
|
||||
# --- BACKEND ---
|
||||
app:
|
||||
build:
|
||||
context: ./bizmatch-server # Pfad zum NestJS Ordner
|
||||
dockerfile: Dockerfile
|
||||
image: bizmatch-server:latest
|
||||
container_name: bizmatch-app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3001:3001'
|
||||
env_file:
|
||||
- ./bizmatch-server/.env # Pfad zur .env Datei
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- bizmatch
|
||||
# WICHTIG: Kein Volume Mapping für node_modules im Prod-Modus!
|
||||
# Das Image bringt alles fertig mit.
|
||||
|
||||
# --- DATABASE ---
|
||||
postgres:
|
||||
container_name: bizmatchdb
|
||||
image: postgres:17-alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- bizmatch-db-data:/var/lib/postgresql/data
|
||||
env_file:
|
||||
- ./bizmatch-server/.env
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
ports:
|
||||
- '5434:5432'
|
||||
networks:
|
||||
- bizmatch
|
||||
|
||||
volumes:
|
||||
bizmatch-db-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
bizmatch:
|
||||
external: false # Oder true, falls du es manuell erstellt hast
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "🚀 Starte Update Prozess..."
|
||||
|
||||
# 1. Neuesten Code holen
|
||||
echo "📥 Git Pull..."
|
||||
git pull
|
||||
|
||||
# 2. Docker Images neu bauen und Container neu starten
|
||||
# --build: Zwingt Docker, die Images neu zu bauen (nutzt Multi-Stage)
|
||||
# -d: Detached mode (im Hintergrund)
|
||||
# --remove-orphans: Räumt alte Container auf, falls Services umbenannt wurden
|
||||
echo "🐳 Baue und starte Container..."
|
||||
docker compose up -d --build --remove-orphans
|
||||
|
||||
# 3. Aufräumen (Optional)
|
||||
# Löscht alte Images ("dangling images"), die beim Build übrig geblieben sind, um Platz zu sparen
|
||||
echo "🧹 Räume alte Images auf..."
|
||||
docker image prune -f
|
||||
|
||||
echo "✅ Fertig! Die App läuft in der neuesten Version."
|
||||
Loading…
Reference in New Issue