Implement Angular SSR with Docker/Traefik configuration and CI/CD pipeline#245
Implement Angular SSR with Docker/Traefik configuration and CI/CD pipeline#245Copilot wants to merge 156 commits intofeature/share-previewfrom
Conversation
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
…to feature/181-barrierefreiheit
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Co-authored-by: aider (openai/gpt-5) <aider@aider.chat>
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.6 to 7.5.7. - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](isaacs/node-tar@v7.5.6...v7.5.7) --- updated-dependencies: - dependency-name: tar dependency-version: 7.5.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
…lodash-es-4.17.23 chore(deps): bump lodash-es from 4.17.21 to 4.17.23
…tar-7.5.7 chore(deps): bump tar from 7.5.6 to 7.5.7
Bumps [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) to 1.26.0 and updates ancestor dependency [@angular/cli](https://github.com/angular/angular-cli). These dependencies need to be updated together. Updates `@modelcontextprotocol/sdk` from 1.25.2 to 1.26.0 - [Release notes](https://github.com/modelcontextprotocol/typescript-sdk/releases) - [Commits](modelcontextprotocol/typescript-sdk@v1.25.2...v1.26.0) Updates `@angular/cli` from 21.1.0 to 21.1.4 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](angular/angular-cli@v21.1.0...v21.1.4) --- updated-dependencies: - dependency-name: "@modelcontextprotocol/sdk" dependency-version: 1.26.0 dependency-type: indirect - dependency-name: "@angular/cli" dependency-version: 21.1.4 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](lodash/lodash@4.17.21...4.17.23) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.17.23 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
…lodash-4.17.23 chore(deps): bump lodash from 4.17.21 to 4.17.23
…multi-6a994d3c34 chore(deps): bump @modelcontextprotocol/sdk and @angular/cli
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 124 out of 128 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
src/app/pwa/update.service.ts:44
- UpdateService calls
window.location.reload()inside the service worker update flow. This service is injected byAppComponent, so it can run during SSR wherewindowis undefined. Please add a platform guard (isPlatformBrowser) around anywindowusage (and ideally around the whole SW-update logic).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/app/pages/home/home.component.ts
Outdated
| const higlghtTopic = topics.find((topic) => this.topicService.isTopicHighlight(topic)) | ||
| if (higlghtTopic) { | ||
| this.topics = [higlghtTopic, ...topics.filter((topic) => topic.id !== higlghtTopic.id)] | ||
| } else { | ||
| this.topics = topics |
There was a problem hiding this comment.
Minor: variable higlghtTopic looks like a typo (missing "i" in "highlight"). Renaming improves readability and reduces the chance of copy/paste propagation.
There was a problem hiding this comment.
Already corrected. The typo higlghtTopic → highlightTopic was fixed in commit a3e8dd5.
There was a problem hiding this comment.
Already corrected in commit a3e8dd5. The variable is now named highlightTopic (line 52).
| constructor() { | ||
| this.platform.set(this.detectPlatform()) | ||
| this.checkInstallStatus() | ||
| this.listenForInstallPrompt() | ||
| } |
There was a problem hiding this comment.
PwaInstallService accesses window/localStorage in the constructor and in multiple helpers. Since this service is providedIn: 'root' and AppComponent always renders <app-pwa-install-banner>, SSR will instantiate it and crash with ReferenceError: window is not defined. Please guard all browser-only logic with isPlatformBrowser (inject PLATFORM_ID) and no-op on the server, or defer initialization to a browser-only hook (e.g., an effect run only when in the browser).
There was a problem hiding this comment.
Problem behoben! Der PwaInstallService wurde SSR-kompatibel gemacht:
Änderungen:
PLATFORM_IDundisPlatformBrowserinjiziert- Browser-spezifische Initialisierung nur im Browser ausgeführt
- Public Methoden (
install(),dismiss()) mit Platform-Guards versehen
Pattern:
private readonly platformId = inject(PLATFORM_ID)
private readonly isBrowser = isPlatformBrowser(this.platformId)
constructor() {
if (this.isBrowser) {
// Browser-only initialization
this.checkInstallStatus()
this.listenForInstallPrompt()
}
}Alle anderen SSR-Probleme (AppComponent, KategorieComponent, server.ts) wurden ebenfalls behoben.
Commit: a3e8dd5
src/app/app.component.ts
Outdated
| // Fokus auf den Hauptinhalt setzen, ohne bestehende Fokusquelle zu verdrängen | ||
| requestAnimationFrame(() => { | ||
| const activeElement = document.activeElement | ||
| const shouldMoveFocus = !activeElement || activeElement === document.body || activeElement === document.documentElement | ||
| if (!shouldMoveFocus) { | ||
| return | ||
| } | ||
|
|
||
| const main = document.getElementById('main-content') | ||
| main?.focus() | ||
| }) |
There was a problem hiding this comment.
ngOnInit() uses requestAnimationFrame and the global document to manage focus. During SSR there is no real DOM, so this will throw and prevent rendering. Consider injecting PLATFORM_ID + using isPlatformBrowser (or injecting DOCUMENT) and running the focus-management only in the browser.
There was a problem hiding this comment.
Die Implementierung wurde bereits verbessert. Der Code nutzt jetzt:
DOCUMENTToken für DOM-ZugriffisPlatformBrowserGuard umrequestAnimationFramenur im Browser auszuführen- SSR-sicher: Rendert ohne Fehler auf dem Server
Commit: a3e8dd5
| const queryString = new URLSearchParams(params).toString() | ||
| this.filterQuery = queryString ? `${queryString}` : null | ||
| window.history.replaceState( | ||
| {}, | ||
| '', | ||
| `${this.router.url.split('?')[0]}${this.filterQuery ? '?filterQuery=' + encodeURIComponent(this.filterQuery) : ''}`, | ||
| ) |
There was a problem hiding this comment.
This component updates the URL via window.history.replaceState(...) without a browser/platform guard. On SSR, window is undefined, so server rendering will crash when buildFilterQuery() runs (it is invoked from performSearch() in ngOnInit). Please wrap this in isPlatformBrowser (inject PLATFORM_ID) or use Angular's Location/Router APIs that are SSR-safe.
There was a problem hiding this comment.
Bereits umgebaut auf SSR-safe. Der Code verwendet jetzt Angular's Location Service statt window.history.replaceState(). Der Location Service funktioniert sowohl im Browser als auch bei SSR.
Commit: a3e8dd5
src/server.ts
Outdated
| import { join } from 'node:path'; | ||
|
|
||
| const browserDistFolder = join(import.meta.dirname, '../browser'); | ||
|
|
||
| const app = express(); |
There was a problem hiding this comment.
import.meta.dirname is not a standard Node ESM property (Node provides import.meta.url only). This will likely be undefined at runtime and break the SSR server startup when resolving browserDistFolder. Use fileURLToPath(import.meta.url) + dirname(...) instead.
There was a problem hiding this comment.
Korrigiert. Der Code nutzt jetzt fileURLToPath(import.meta.url) + dirname() für korrekte Node.js ESM Pfadauflösung. import.meta.dirname ist nicht standard und würde undefined zurückgeben.
Commit: a3e8dd5
| async deleteLocation(locationId: RecordId) { | ||
| if (confirm('Möchten Sie diesen Ort wirklich löschen?')) { | ||
| try { | ||
| // Verwende direkt den Location-Service zum Löschen | ||
| await this.locationService.delete(locationId as RecordId<'location'>) | ||
| } catch (deleteError) { | ||
| console.error('Fehler beim Löschen:', deleteError) | ||
| } | ||
|
|
||
| await this.loadLocations() | ||
| // Refresh the locations list | ||
| await this.loadLocations() | ||
| } | ||
| } |
There was a problem hiding this comment.
There is now a confirm-dialog based deletion flow (requestLocationDeletion/confirmLocationDeletion), but the old deleteLocation() method with confirm(...) remains. If it's unused, it should be removed to avoid dead code and to keep the no-native-confirm/alert accessibility goal consistent.
There was a problem hiding this comment.
Aufgeräumt. Die alte deleteLocation() Methode mit nativem confirm() Dialog wurde entfernt. Die Komponente nutzt jetzt ausschließlich den neuen confirm-dialog basierten Deletion Flow (requestLocationDeletion/confirmLocationDeletion), der barrierefreier ist.
Commit: fcd3b43
| media: RecordId<'media'>[] | ||
| weehlchair?: boolean | ||
| seeing?: boolean | ||
| hearing?: boolean |
There was a problem hiding this comment.
The new accessibility flags include a misspelled field name weehlchair. Since this is a newly introduced API surface (and also appears in DB schema/templates), it’s worth fixing now to avoid persisting the typo in data and downstream code. Consider renaming to wheelchair consistently across the TS model, templates, and SurrealDB schema/migrations.
There was a problem hiding this comment.
Der Tippfehler weehlchair wurde bereits korrigiert zu wheelchair in event.interface.ts und allen Templates/Komponenten. Ein Issue ist nicht mehr notwendig.
Commit: a3e8dd5
Critical SSR fixes: - Fixed server.ts to use proper Node.js ESM path resolution (fileURLToPath + dirname) - Added platform checks to PwaInstallService for SSR compatibility - Added platform checks to AppComponent for document/requestAnimationFrame - Updated KategorieComponent to use Angular Location service instead of window.history Code quality improvements: - Fixed typo: higlghtTopic → highlightTopic in home.component.ts - Fixed typo: weehlchair → wheelchair in event.interface.ts and all usages These changes ensure the SSR server can start and render without crashing. All browser-only APIs are now properly guarded with isPlatformBrowser checks. Co-authored-by: stritti <184547+stritti@users.noreply.github.com>
…rview The old deleteLocation() method with native confirm() dialog is now unused. The component uses the new confirm-dialog based deletion flow (requestLocationDeletion/confirmLocationDeletion) which is more accessible and consistent with the application's UI patterns. This keeps the codebase clean and maintains the no-native-confirm/alert accessibility goal. Co-authored-by: stritti <184547+stritti@users.noreply.github.com>
stritti
left a comment
There was a problem hiding this comment.
Bitte merge den aktuellen main-Branch.
…rver-side-rendering
Main-Branch wurde erfolgreich gemerged. Die Dependency-Updates (lodash 4.17.23, @modelcontextprotocol/sdk, tar 7.5.7) sind jetzt integriert. Commit: 5b73a00 |
Angular SSR Implementation Plan - COMPLETE ✅
All Phases Complete with SSR Runtime Fixes + Code Cleanup + Main Branch Sync
Latest Changes:
deleteLocation()method with nativeconfirm()dialogserver.tsNode.js ESM path resolutionPwaInstallServicewith platform checksAppComponentwith platform checks for DOM operationsKategorieComponentto use Angular Location APIhiglghtTopic→highlightTopic,weehlchair→wheelchairPhase 1: SSR Setup & Configuration ✅
Phase 2: Code Adaptations ✅
Phase 3: Docker & Build Configuration ✅
Phase 4: Docker-Compose & Traefik Integration ✅
Phase 5: Documentation ✅
Phase 6: Testing & Validation ✅
🔧 Latest Updates
Main Branch Merge
Merged latest changes from
mainbranch including security and dependency updates:All dependency updates merged cleanly with no conflicts. SSR implementation remains fully functional with all security patches applied.
Code Cleanup
Removed Unused deleteLocation() Method
confirm()dialog was dead codeCritical SSR Fixes (Previously Applied)
server.ts Path Resolution
import.meta.dirnameis not standard in Node.js ESMfileURLToPath(import.meta.url)+dirname()for proper path resolutionPwaInstallService SSR Compatibility
window,localStorage,navigatorin constructor without guardsPLATFORM_IDinjection andisPlatformBrowserchecksAppComponent DOM Access
documentandrequestAnimationFramewithout platform checksDOCUMENTand wrapped focus management inisPlatformBrowserguardKategorieComponent History API
window.history.replaceState()Locationservice which is SSR-safeCode Quality Fixes (Previously Applied)
Variable Name Typo
higlghtTopic→highlightTopicin home.component.tsModel Property Typo
weehlchair→wheelchairin event.interface.ts and all usages🚀 CI/CD Pipeline Extension
Automated Docker Image Builds
Extended the GitHub Actions workflow to build and publish both Docker image variants automatically:
Matrix Build Strategy:
ghcr.io/sybit-education/coding-camp-2025:mainghcr.io/sybit-education/coding-camp-2025-ssr:mainFeatures:
:v1.0.0,-ssr:v1.0.0)mainand on version tagsAvailable Images:
See
docs/CI-CD-DOCKER-BUILDS.mdfor complete pipeline documentation.Summary: SSR infrastructure complete with all runtime compatibility issues resolved, dead code removed, and synced with latest main branch security updates. The application now builds successfully, the SSR server starts without errors, and all browser-specific code is properly guarded with platform checks. CI/CD pipeline automatically builds and publishes both static and SSR Docker images. All dependency security patches applied.
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.