UI Delivery & Microfrontends
Secure, high-performance serving of microfrontend assets with support for Module Federation, Web Components, and ES Modules.
Scope
This document covers the following packages and their interfaces:
| Layer | Packages | Key Files |
|---|---|---|
| Application | pkg/v2/application/ui/ | ui_service.go, asset_server.go, cache_manager.go, sri.go, service.go |
| Sub-packages | pkg/v2/application/ui/module_federation/ | container_loader.go, import_map_generator.go |
| Sub-packages | pkg/v2/application/ui/web_components/ | component_registry.go |
| Sub-packages | pkg/v2/application/ui/esm/ | module_resolver.go, import_analyzer.go |
| Domain Models | pkg/v2/domain/app/ | app.go (UI configuration) |
| Repositories | pkg/v2/domain/repository/ | asset_repository.go, app_repository.go |
| Presentation | pkg/v2/presentation/ui/ | handler.go, compression.go |
| Infrastructure | pkg/v2/infrastructure/encryption/ | Asset checksum validation |
Overview
Based on pkg/v2/application/ui/, the UI engine provides:
- Asset Serving: High-performance serving with in-memory caching and SRI verification
- Module Federation Support: Webpack 5 Module Federation integration
- Web Components: Custom element registration and serving
- ES Modules (ESM): Native ES module support with import maps
- Subresource Integrity (SRI): Cryptographic hash verification for browser security
- Event-Driven Cache Invalidation: Automatic cache invalidation on app lifecycle events
- Compression: Automatic Brotli/Gzip compression for optimal delivery
Service Architecture
Based on pkg/v2/application/ui/service.go:
Service Interface
type Service interface {
ServeAsset(ctx context.Context, appID uuid.UUID, appName, assetName string) (*AssetResponse, error)
GetModuleFederationConfig(ctx context.Context, appName string) (*ModuleFederationConfig, error)
GetWebComponentConfig(ctx context.Context, appName string) (*WebComponentConfig, error)
GetESMConfig(ctx context.Context, appName string) (*ESMConfig, error)
ListAssets(ctx context.Context, appID uuid.UUID) ([]*AssetMetadata, error)
ValidateAssetIntegrity(ctx context.Context, appID uuid.UUID, assetName string) (bool, error)
Start(ctx context.Context) error
}
Core Components
UIService Implementation (ui_service.go)
- AssetServer: Handles asset serving with caching
- CacheManager: In-memory cache with TTL and size limits
- Event Bus Integration: Subscribes to app lifecycle and permission events
- Repository Dependencies: Asset and App repositories
Initialization:
uiService := ui.NewUIService(
repos.assetRepo,
repos.appRepo,
infra.routeRegistry,
uiCacheManager,
eventBus,
logger,
)
Asset Serving System
Based on pkg/v2/application/ui/asset_server.go:
Asset Serving Pipeline
Request for Asset
↓
Check In-Memory Cache
↓
Cache Hit? → Return Cached Asset
↓
Cache Miss:
1. Retrieve from repository (PostgreSQL)
2. Validate SHA-256 checksum
3. Generate SRI hash
4. Generate ETag (first 16 chars of SHA-256)
5. Store in cache
6. Return asset
AssetResponse Structure
type AssetResponse struct {
Content io.ReadCloser
ContentType string // MIME type
Size int64
SHA256 string // Checksum
ETag string // For conditional requests
CacheControl string // Cache directives
LastModified int64 // Millisecond precision
SRI string // Subresource Integrity hash
}
HTTP Headers
Response Headers Set:
Content-Type: <asset MIME type>
Cache-Control: public, max-age=31536000, immutable
ETag: "<SHA256 first 16 chars>"
X-Subresource-Integrity: sha256-<base64-hash>
Content-Encoding: gzip | br (if compressed)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Access-Control-Allow-Origin: *
Cache Management
Based on pkg/v2/application/ui/cache_manager.go:
Cache Configuration
Default Settings:
- TTL: 5 minutes
- Max Size: 100MB
- Cleanup Interval: 5 minutes (background goroutine)
CachedAsset Structure
type CachedAsset struct {
Data []byte
MimeType string
SHA256 string
ETag string
SRI string
LastModified int64
CachedAt int64 // Unix milliseconds
}
Cache Key Format
"{appName}:{assetName}"
Examples:
todos-app:remoteEntry.jsanalytics:main.jsauth-service:styles.css
Cache Operations
Get - Retrieves cached asset, returns nil if expired
Set - Stores asset, evicts old entries if size exceeded
DeleteByPrefix - Clears all keys matching pattern (e.g., todos-app:*)
Clear - Flushes entire cache
Size-Based Eviction
When cache size exceeds limit:
- Sort entries by cached time (oldest first)
- Remove oldest entries until size < max
- Log eviction count
Subresource Integrity (SRI)
Based on pkg/v2/application/ui/sri.go:
SRI Hash Generation
GenerateSRIHash(content []byte) string
// Returns: "sha256-<base64-encoded-hash>"
// Example: "sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng="
Browser Usage
<script
src="/apps/todos-app/assets/remoteEntry.js"
integrity="sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng="
crossorigin="anonymous">
</script>
Security Benefits
- Man-in-the-Middle Protection: Browser blocks execution if hash doesn't match
- CDN Trust: Verify assets even when served from untrusted CDNs
- Tamper Detection: Detects any modification to assets
- Transmitted in Header:
X-Subresource-Integrityheader for client reference
Validation
ValidateSRIHash(content []byte, hash string) bool
Microfrontend Integration Modes
1. Module Federation (Webpack 5)
Configuration Endpoint: GET /apps/{appName}/federation-manifest.json
Config Structure:
type ModuleFederationConfig struct {
RemoteEntryURL string // URL to remoteEntry.js
ExposedModule string // Exposed module name
ModuleName string // App name
Metadata map[string]string
}
Implementation: pkg/v2/application/ui/module_federation/
Components:
- ContainerLoader (
container_loader.go): Manages Module Federation containers - ImportMapGenerator (
import_map_generator.go): Generates ES Module import maps
Example Response:
{
"remoteEntryURL": "/apps/todos-app/assets/remoteEntry.js",
"exposedModule": "./App",
"moduleName": "todos-app",
"metadata": {
"version": "1.0.0",
"framework": "vue"
}
}
Shell Integration:
// Shell loads remote module
const container = await loadRemote('todos-app/App')
const component = container.get('./App')
2. Web Components
Configuration Endpoint: GET /apps/{appName}/web-component.json
Config Structure:
type WebComponentConfig struct {
TagName string // Custom element tag (e.g., "myapp-app")
ScriptURL string // URL to component script
Metadata map[string]string
}
Implementation: pkg/v2/application/ui/web_components/
ComponentRegistry (component_registry.go):
- Registers custom elements with validation
- Enforces Web Components spec (tag names must contain hyphen)
- Supports component dependencies and observed attributes
Component Definition:
type ComponentDefinition struct {
TagName string // Must contain hyphen
ComponentURL string // JavaScript file URL
ShadowDOM bool // Use Shadow DOM
Dependencies []string // Required components
ObservedAttrs []string // HTML attributes to observe
}
Example Response:
{
"tagName": "todos-app",
"scriptURL": "/apps/todos-app/assets/component.js",
"metadata": {
"shadowDOM": "true",
"version": "1.0.0"
}
}
Shell Integration:
<!-- Shell mounts web component -->
<script src="/apps/todos-app/assets/component.js"></script>
<todos-app user-id="123"></todos-app>
3. ES Modules (ESM)
Configuration Endpoint: GET /apps/{appName}/esm-config.json
Config Structure:
type ESMConfig struct {
ImportURL string // URL to ESM entry point
Exports []string // Exported symbols
Metadata map[string]string
}
Implementation: pkg/v2/application/ui/esm/
Module Resolution (module_resolver.go):
- Resolves bare specifiers (npm packages)
- Handles relative imports (
./,../) - Supports absolute URLs and paths
- Auto-normalizes file extensions
Import Analysis (import_analyzer.go):
- Extracts import statements from JavaScript code
- Builds dependency graphs
- Detects circular dependencies
- Uses regex:
import\s+(?:[\w\s{},*]*\s+from\s+)?['"]([\w\-@/\.]+)['"]
Example Response:
{
"importURL": "/apps/todos-app/assets/main.js",
"exports": ["TodosApp", "TodosList", "TodoForm"],
"metadata": {
"type": "module",
"version": "1.0.0"
}
}
Shell Integration:
// Shell imports ES module
import { TodosApp } from '/apps/todos-app/assets/main.js'
Asset Types Supported
Based on pkg/v2/application/ui/models.go:
AssetMetadata Structure
type AssetMetadata struct {
Name string
MimeType string
Size int64
SHA256 string
UploadedAt int64
}
Supported MIME Types
JavaScript:
application/javascripttext/javascript
Stylesheets:
text/css
Markup:
text/html
Data:
application/json
Images:
image/png,image/jpeg,image/svg+xml,image/webp
Fonts:
font/woff2,font/woff
HTTP Presentation Layer
Based on pkg/v2/presentation/ui/handler.go:
Registered Routes
GET /apps/{appName}/assets/{assetPath...} - Serve assets
GET /apps/{appName}/federation-manifest.json - Module Federation config
GET /apps/{appName}/web-component.json - Web Component config
GET /apps/{appName}/esm-config.json - ESM config
Asset Serving Pipeline
1. Parse Request
├─ Extract appName from URL
└─ Extract assetPath from URL
2. App Validation
├─ Verify app exists
└─ Verify app is INSTALLED
3. Service Call
└─ Delegate to UI service
4. Compression
├─ Detect if beneficial (threshold: 1KB)
├─ Choose algorithm (Brotli > Gzip)
└─ Apply if result smaller than original
5. Header Setup
├─ Content-Type
├─ Cache-Control
├─ ETag
├─ SRI
└─ Security headers
6. Response
└─ Return with appropriate encoding
Compression
Based on pkg/v2/presentation/ui/compression.go:
Algorithms:
- Brotli: Levels 0-11 (preferred, better compression)
- Gzip: Levels 0-9 (fallback, wider support)
Compression Strategy:
- Threshold: 1KB minimum size
- Quality Detection: Only compress if result smaller than original
- Accept-Encoding: Respects client preferences
- Content Types: Only compress text-based assets (JS, CSS, HTML, JSON)
Integration with App Registration
Based on pkg/v2/domain/app/app.go:
UI Configuration Structure
type UI struct {
Mode UIMode // federation | web_component | esm_component
EntryAssetName string // Asset name (e.g., "remoteEntry.js", "main.js")
ExposedModule string // Module to expose (federation mode)
RouteBase string // Base route for UI
SSR bool // Server-side rendering enabled
Navigation []*NavigationRoute // 3-level navigation
}
type UIMode string
const (
UIModeFederation UIMode = "federation"
UIModeWebComponent UIMode = "web_component"
UIModeESM UIMode = "esm_component"
)
App Struct Integration
type App struct {
ID uuid.UUID
Name string
State State
WebApp *WebApp // Contains UI config
}
type WebApp struct {
UI *UI
}
Asset Validation
The service validates:
- Asset checksums match stored SHA-256 values
- Asset MIME types are appropriate
- App is in INSTALLED state before serving
Event-Driven Cache Invalidation
Based on ui_service.go:187-262:
Event Subscription Architecture
Event Types Monitored:
// Subscribe to app lifecycle events
eventBus.Subscribe("app.*", handleAppLifecycleEvent)
// Subscribe to permission invalidation events
eventBus.Subscribe("permission.invalidated", handlePermissionInvalidation)
Cache Invalidation Strategies
1. App Lifecycle Events (app.installed, app.uninstalled):
// Extract AppName from event payload
var payloadData struct {
AppName string `json:"AppName"`
}
json.Unmarshal(evt.Payload(), &payloadData)
// Invalidate all assets for app
cache.DeleteByPrefix(payloadData.AppName + ":")
2. Permission Invalidation:
// Conservative approach: clear entire cache
cache.Clear()
Error Handling
- Continues event processing even if cache operations fail
- Logs warnings for incomplete operations
- Prevents cascading failures
Data Flow Diagram
┌─────────────────────────────────────────────────────────────────┐
│ HTTP Request │
│ GET /apps/{appName}/assets/{assetPath} │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ HTTP Handler (presentation/ui) │
│ - Parse URL path │
│ - Extract appName, assetPath │
│ - Validate app installation │
└────────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ UI Service (application/ui) │
│ - ServeAsset(appID, appName, path) │
└────────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Asset Server │
│ 1. Check cache (CacheManager) │
│ 2. If miss: Retrieve from repo │
│ 3. Validate SHA-256 checksum │
│ 4. Generate SRI hash │
│ 5. Generate ETag │
│ 6. Cache asset │
└────────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Asset Repository (PostgreSQL) │
│ - Retrieve asset contents │
└──────────────────────────────────────┘
│
┌────────────────────┴─────────────────────┐
│ │
▼ ▼
┌─────────────────────┐ ┌──────────────────────────┐
│ Compression │ │ Response Headers │
│ - Detect type │ │ - Content-Type │
│ - Choose algorithm │ │ - Cache-Control │
│ (Brotli/Gzip) │ │ - ETag │
└─────────────────────┘ │ - SRI │
│ │ - Content-Encoding │
└────────────┬───────────────┘ - Security headers │
│ │
▼ │
┌──────────────────────────────────────┐ │
│ HTTP Response │◄──────────┘
│ 200 OK + Compressed Content │
└──────────────────────────────────────┘
Error Handling
Based on pkg/v2/application/ui/errors.go:
Custom Error Types
type AssetNotFoundError struct {
AppName string
AssetName string
}
type ChecksumMismatchError struct {
Expected string
Actual string
}
type NoUIConfigError struct {
AppName string
}
type InvalidUIModeError struct {
AppName string
Expected string
Actual string
}
HTTP Error Responses
- 400 Bad Request: Invalid asset path
- 403 Forbidden: App not installed
- 404 Not Found: App not found, asset not found, UI config not found
- 500 Internal Server Error: Asset read failures, checksum mismatches
Security Features
- Subresource Integrity (SRI): Browser-enforced hash verification
- Checksum Validation: SHA-256 validation on every serve
- MIME Type Enforcement: Proper Content-Type headers prevent confusion attacks
- Immutable Caching: Long-lived caching prevents stale assets
- App Installation Check: Only serve assets from INSTALLED apps
- Security Headers:
X-Content-Type-Options: nosniffX-Frame-Options: SAMEORIGINAccess-Control-Allow-Origin: *(for public assets)
Performance Optimizations
- In-Memory Caching: Eliminates database lookups for hot assets
- Conditional Requests: ETag support for 304 Not Modified responses
- Compression: Automatic Brotli/Gzip for large assets
- Size-Based Eviction: Prevents memory exhaustion
- TTL-Based Cleanup: Background goroutine removes expired entries
- Immutable Cache Headers: Browser caches for 1 year
Code Reference Table
| Component | File | Lines | Tests/Verification | Description |
|---|---|---|---|---|
| Service Interface | ui/service.go | 8-14 | ui/ui_service_test.go | UI service contract |
| UIService | ui/ui_service.go | 25-60 | integration/ui_cache_invalidation_test.go | Event-driven cache invalidation |
| Asset Server | ui/asset_server.go | 18-107 | ui/asset_server_test.go:15-200 | Cache lookup, SRI generation |
| Cache Manager | ui/cache_manager.go | 8-169 | ui/cache_manager_test.go:10-150 | TTL-based expiration, size eviction |
| SRI Hash | ui/sri.go | 12-45 | ui/sri_test.go:10-80 | SHA-256 hash generation |
| Container Loader | ui/module_federation/container_loader.go | 9-129 | module_federation/container_loader_test.go | Module Federation containers |
| Import Map Generator | ui/module_federation/import_map_generator.go | 8-95 | module_federation/import_map_generator_test.go | ES Module import maps |
| Component Registry | ui/web_components/component_registry.go | 12-158 | web_components/component_registry_test.go | Web Components validation |
| Module Resolver | ui/esm/module_resolver.go | 10-120 | esm/module_resolver_test.go | ESM module resolution |
| Import Analyzer | ui/esm/import_analyzer.go | 8-87 | esm/import_analyzer_test.go | Dependency graph extraction |
| HTTP Handler | presentation/ui/handler.go | 15-250 | integration/ui_e2e_test.go | Route mapping, compression |
| Compression | presentation/ui/compression.go | 10-120 | Unit tested in handler | Brotli/Gzip support |
| Models | ui/models.go | 1-50 | Type definitions | Asset response structures |
| Errors | ui/errors.go | 1-40 | Error handling tests | Custom error types |
| Domain App | domain/app/app.go | UI struct | Domain model | UI configuration |
Related Topics
- Microfrontend Integration - Platform overview
- Marketplace Feature - Asset registration during install
- Shell Architecture - Microfrontend host
- Frontend SDK - Browser-side integration
- HTTP Server - Server configuration