Migrate frontend to Angular 20 with full Docker support

Implemented a complete Angular 20 migration with modern standalone components architecture and production-ready Docker deployment:

**Frontend Migration:**
- Created Angular 20 application with standalone components (no NgModules)
- Implemented three main components: artifacts-list, upload-form, query-form
- Added TypeScript models and services for type-safe API communication
- Migrated dark theme UI with all existing features
- Configured routing and navigation between views
- Set up development proxy for seamless API integration
- Reactive forms with validation for upload and query functionality
- Auto-refresh artifacts every 5 seconds with RxJS observables
- Client-side sorting, filtering, and search capabilities
- Tags displayed as inline badges, SIM source grouping support

**Docker Integration:**
- Multi-stage Dockerfile for Angular (Node 24 build, nginx Alpine serve)
- nginx configuration for SPA routing and API proxy
- Updated docker-compose.yml with frontend service on port 80
- Health checks for all services
- Production-optimized build with gzip compression and asset caching

**Technical Stack:**
- Angular 20 with standalone components
- TypeScript for type safety
- RxJS for reactive programming
- nginx as reverse proxy
- Multi-stage Docker builds for optimal image size

All features fully functional and tested in Docker environment.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-15 11:35:28 -05:00
parent 2861022ac6
commit ed5773893e
37 changed files with 12195 additions and 0 deletions

53
frontend/src/app/app.ts Normal file
View File

@@ -0,0 +1,53 @@
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { ArtifactService } from './services/artifact';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive],
template: `
<div class="container">
<header>
<h1>◆ Obsidian</h1>
<div class="header-info">
<span class="badge">{{ deploymentMode }}</span>
<span class="badge">{{ storageBackend }}</span>
</div>
</header>
<nav class="tabs">
<a routerLink="/artifacts" routerLinkActive="active" class="tab-button">
📦 Artifacts
</a>
<a routerLink="/upload" routerLinkActive="active" class="tab-button">
📤 Upload
</a>
<a routerLink="/query" routerLinkActive="active" class="tab-button">
🔍 Query
</a>
</nav>
<router-outlet></router-outlet>
</div>
`,
styleUrls: ['./app.css']
})
export class AppComponent implements OnInit {
deploymentMode: string = '';
storageBackend: string = '';
constructor(private artifactService: ArtifactService) {}
ngOnInit() {
this.artifactService.getApiInfo().subscribe({
next: (info) => {
this.deploymentMode = `Mode: ${info.deployment_mode}`;
this.storageBackend = `Storage: ${info.storage_backend}`;
},
error: (err) => console.error('Failed to load API info:', err)
});
}
}