fix: Gitea Traefik routing and connection pool optimization
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled

- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
This commit is contained in:
2025-11-09 14:46:15 +01:00
parent 85c369e846
commit 36ef2a1e2c
1366 changed files with 104925 additions and 28719 deletions

View File

@@ -0,0 +1,302 @@
/**
* Unified Animation System
*
* Consolidates all scroll animation modules into a single, unified system.
* Replaces: scrollfx, parallax, scroll-timeline, scroll-loop, scroll-dependent, sticky-fade, sticky-steps
*/
import { Logger } from '../../core/logger.js';
import { ScrollAnimation } from './ScrollAnimation.js';
import { TimelineAnimation } from './TimelineAnimation.js';
/**
* AnimationSystem - Unified animation system
*/
export class AnimationSystem {
constructor(config = {}) {
this.config = {
enabled: config.enabled ?? true,
useIntersectionObserver: config.useIntersectionObserver ?? true,
throttleDelay: config.throttleDelay || 16, // ~60fps
...config
};
this.animations = new Map(); // Map<element, Animation>
this.observers = new Map(); // Map<element, IntersectionObserver>
this.scrollHandler = null;
this.isScrolling = false;
// Initialize
if (this.config.enabled) {
this.init();
}
Logger.info('[AnimationSystem] Initialized', {
enabled: this.config.enabled,
useIntersectionObserver: this.config.useIntersectionObserver
});
}
/**
* Create a new AnimationSystem instance
*/
static create(config = {}) {
return new AnimationSystem(config);
}
/**
* Initialize animation system
*/
init() {
// Set up scroll handler
if (!this.config.useIntersectionObserver) {
this.setupScrollHandler();
}
// Auto-initialize elements with data attributes
this.autoInitialize();
}
/**
* Set up scroll handler
*/
setupScrollHandler() {
let ticking = false;
this.scrollHandler = () => {
if (!ticking) {
window.requestAnimationFrame(() => {
this.updateAnimations();
ticking = false;
});
ticking = true;
}
};
window.addEventListener('scroll', this.scrollHandler, { passive: true });
}
/**
* Auto-initialize elements with data attributes
*/
autoInitialize() {
// Fade in on scroll (scrollfx)
this.initializeFadeIn();
// Parallax
this.initializeParallax();
// Scroll timeline
this.initializeTimeline();
// Sticky fade
this.initializeStickyFade();
// Sticky steps
this.initializeStickySteps();
}
/**
* Initialize fade-in animations (scrollfx)
*/
initializeFadeIn() {
const elements = document.querySelectorAll('.fade-in-on-scroll, .zoom-in, [data-animate="fade-in"]');
elements.forEach(element => {
this.registerAnimation(element, {
type: 'fade-in',
offset: parseFloat(element.dataset.offset) || 0.85,
delay: parseFloat(element.dataset.delay) || 0,
once: element.dataset.once !== 'false'
});
});
}
/**
* Initialize parallax animations
*/
initializeParallax() {
const elements = document.querySelectorAll('[data-parallax], .parallax');
elements.forEach(element => {
const speed = parseFloat(element.dataset.parallax || element.dataset.speed) || 0.5;
this.registerAnimation(element, {
type: 'parallax',
speed
});
});
}
/**
* Initialize timeline animations (scroll-timeline)
*/
initializeTimeline() {
const elements = document.querySelectorAll('[data-scroll-timeline], [data-scroll-step]');
elements.forEach(element => {
this.registerAnimation(element, {
type: 'timeline',
steps: element.dataset.scrollSteps ? parseInt(element.dataset.scrollSteps) : null,
triggerPoint: parseFloat(element.dataset.triggerPoint) || 0.4
});
});
}
/**
* Initialize sticky fade animations
*/
initializeStickyFade() {
const elements = document.querySelectorAll('[data-sticky-fade], .sticky-fade');
elements.forEach(element => {
this.registerAnimation(element, {
type: 'sticky-fade',
fadeStart: parseFloat(element.dataset.fadeStart) || 0,
fadeEnd: parseFloat(element.dataset.fadeEnd) || 1
});
});
}
/**
* Initialize sticky steps animations
*/
initializeStickySteps() {
const elements = document.querySelectorAll('[data-sticky-steps], .sticky-steps');
elements.forEach(element => {
const steps = element.dataset.stickySteps ? parseInt(element.dataset.stickySteps) : 3;
this.registerAnimation(element, {
type: 'sticky-steps',
steps
});
});
}
/**
* Register an animation
*/
registerAnimation(element, config) {
if (this.animations.has(element)) {
Logger.warn('[AnimationSystem] Animation already registered for element', element);
return;
}
let animation;
switch (config.type) {
case 'fade-in':
case 'zoom-in':
animation = new ScrollAnimation(element, {
type: config.type,
offset: config.offset || 0.85,
delay: config.delay || 0,
once: config.once !== false
});
break;
case 'parallax':
animation = new ScrollAnimation(element, {
type: 'parallax',
speed: config.speed || 0.5
});
break;
case 'timeline':
animation = new TimelineAnimation(element, {
steps: config.steps,
triggerPoint: config.triggerPoint || 0.4
});
break;
case 'sticky-fade':
animation = new ScrollAnimation(element, {
type: 'sticky-fade',
fadeStart: config.fadeStart || 0,
fadeEnd: config.fadeEnd || 1
});
break;
case 'sticky-steps':
animation = new ScrollAnimation(element, {
type: 'sticky-steps',
steps: config.steps || 3
});
break;
default:
Logger.warn('[AnimationSystem] Unknown animation type', config.type);
return;
}
this.animations.set(element, animation);
// Set up observer if using IntersectionObserver
if (this.config.useIntersectionObserver) {
this.setupObserver(element, animation);
}
Logger.debug('[AnimationSystem] Animation registered', { element, type: config.type });
}
/**
* Set up IntersectionObserver for element
*/
setupObserver(element, animation) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
animation.enter();
} else if (!animation.config.once) {
animation.exit();
}
});
}, {
threshold: animation.config.offset || 0.85,
rootMargin: '0px'
});
observer.observe(element);
this.observers.set(element, observer);
}
/**
* Update all animations (for scroll-based updates)
*/
updateAnimations() {
this.animations.forEach((animation, element) => {
if (animation.needsUpdate) {
animation.update();
}
});
}
/**
* Remove animation
*/
removeAnimation(element) {
const animation = this.animations.get(element);
if (animation) {
animation.destroy();
this.animations.delete(element);
}
const observer = this.observers.get(element);
if (observer) {
observer.disconnect();
this.observers.delete(element);
}
}
/**
* Destroy animation system
*/
destroy() {
// Remove all animations
this.animations.forEach((animation, element) => {
this.removeAnimation(element);
});
// Remove scroll handler
if (this.scrollHandler) {
window.removeEventListener('scroll', this.scrollHandler);
}
Logger.info('[AnimationSystem] Destroyed');
}
}