style: auto-format codebase with Prettier

Applied formatting to 1487+ files using pnpm format:write
  - TypeScript/JavaScript files
  - Svelte components
  - Astro pages
  - JSON configs
  - Markdown docs

  13 files still need manual review (Astro JSX comments)
This commit is contained in:
Wuesteon 2025-11-27 18:33:16 +01:00
parent 0241f5554c
commit d36b321d9d
3952 changed files with 661498 additions and 739751 deletions

View file

@ -61,7 +61,7 @@ describe('Tags Integration', () => {
testUser = await pb.collection('users').create({
email: `test-${Date.now()}@example.com`,
password: 'testpassword123',
passwordConfirm: 'testpassword123'
passwordConfirm: 'testpassword123',
});
await pb.collection('users').authWithPassword(testUser.email, 'testpassword123');
@ -73,7 +73,7 @@ describe('Tags Integration', () => {
slug: 'test-tag',
user_id: testUser.id,
color: '#3B82F6',
is_public: false
is_public: false,
});
expect(tag.name).toBe('Test Tag');
@ -84,14 +84,14 @@ describe('Tags Integration', () => {
const tag = await pb.collection('tags').create({
name: 'My Tag',
slug: 'my-tag',
user_id: testUser.id
user_id: testUser.id,
});
// Try to update with different user
const otherUser = await pb.collection('users').create({
email: `other-${Date.now()}@example.com`,
password: 'testpassword123',
passwordConfirm: 'testpassword123'
passwordConfirm: 'testpassword123',
});
await pb.collection('users').authWithPassword(otherUser.email, 'testpassword123');
@ -309,7 +309,7 @@ Sentry.init({
integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
tracesSampleRate: 1.0,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0
replaysOnErrorSampleRate: 1.0,
});
export const handleError = Sentry.handleErrorWithSentry();
@ -326,7 +326,7 @@ export async function GET() {
const checks = {
app: 'ok',
database: 'unknown',
timestamp: new Date().toISOString()
timestamp: new Date().toISOString(),
};
try {
@ -423,7 +423,7 @@ const migrations = [
await pb.collections.update('tags', tagsCollection);
console.log('✓ Fixed tags collection rules');
}
},
},
{
version: 2,
@ -431,8 +431,8 @@ const migrations = [
up: async (pb) => {
// Add indexes for performance
// Implementation here
}
}
},
},
];
async function runMigrations() {

View file

@ -108,7 +108,7 @@ import { writable, derived } from 'svelte/store';
export const cardStore = createCardStore({
cards: new Map(),
activeCard: null,
editMode: false
editMode: false,
});
```
@ -174,8 +174,8 @@ const CardSchema = z.object({
constraints: z.object({
maxModules: z.number().max(20),
maxHTMLSize: z.number().max(100000),
maxCSSSize: z.number().max(50000)
})
maxCSSSize: z.number().max(50000),
}),
});
```
@ -194,7 +194,7 @@ const CardSchema = z.object({
const cardEventBus = {
emit: (event: string, data: any) => {},
on: (event: string, handler: Function) => {},
off: (event: string, handler: Function) => {}
off: (event: string, handler: Function) => {},
};
```
@ -222,7 +222,7 @@ export const cardsStore = {
createCard: async (config: CardConfig) => {},
updateCard: async (id: string, updates: Partial<Card>) => {},
deleteCard: async (id: string) => {},
convertCard: async (id: string, targetMode: RenderMode) => {}
convertCard: async (id: string, targetMode: RenderMode) => {},
};
```
@ -272,7 +272,7 @@ if (import.meta.env.DEV) {
inspect: (cardId: string) => {},
export: (cardId: string) => {},
import: (config: any) => {},
benchmark: () => {}
benchmark: () => {},
};
}
```

View file

@ -10,12 +10,14 @@ Successfully implemented cards display on user profile pages by creating a simpl
## Changes Made
### 1. Server-Side Data Loading (`/src/routes/p/[username]/+page.server.ts`)
- Removed complex Card type import that was causing 500 errors
- Implemented direct PocketBase query without type dependencies
- Added safe JSON parsing for card config/metadata fields
- Filter cards by `page="profile"` and `visibility="public"`
### 2. Client-Side Rendering (`/src/routes/p/[username]/+page.svelte`)
- Removed dependency on complex CardRenderer component
- Created inline simplified card rendering for three modes:
- **Beginner Mode**: Renders modules (header, content, media, links)
@ -24,6 +26,7 @@ Successfully implemented cards display on user profile pages by creating a simpl
- Added "Featured Cards" section above links
### 3. Card Management (`/src/routes/(app)/my/cards/+page.svelte`)
- Updated to load ALL user cards, not just profile ones
- Existing profile toggle functionality allows users to control visibility
- Added stats showing total cards vs cards on profile
@ -32,12 +35,14 @@ Successfully implemented cards display on user profile pages by creating a simpl
## Key Features
### Profile Page
- Cards appear in a responsive grid (1-3 columns)
- Simple module-based rendering for beginner cards
- Fallback display for advanced/expert cards
- Only shows public cards marked for profile display
### Management Page
- Checkbox to toggle "Show on Profile"
- Warning if card is not public but set for profile
- Drag-and-drop reordering still functional
@ -46,12 +51,14 @@ Successfully implemented cards display on user profile pages by creating a simpl
## Technical Approach
### Why This Works
1. **No Type Imports**: Server-side code doesn't import complex Card types
2. **Direct Database Access**: Uses PocketBase directly with JSON parsing
3. **Simplified Rendering**: Inline rendering without complex components
4. **Progressive Enhancement**: Basic display with room for improvements
### Trade-offs
- Less feature-rich display than full CardRenderer
- Advanced/Expert cards show metadata only (not full rendering)
- No template variable replacement
@ -60,11 +67,13 @@ Successfully implemented cards display on user profile pages by creating a simpl
## Future Improvements
### Short Term
1. Add client-side CardRenderer for better display
2. Implement template variable replacement
3. Add preview mode in card management
### Long Term
1. Refactor Card type system for SSR compatibility
2. Create server-safe card components
3. Implement full rendering for all card modes
@ -80,4 +89,4 @@ Successfully implemented cards display on user profile pages by creating a simpl
## Conclusion
The simplified approach successfully displays cards on profile pages while avoiding the complex type system issues. This provides a working foundation that can be enhanced incrementally without breaking production.
The simplified approach successfully displays cards on profile pages while avoiding the complex type system issues. This provides a working foundation that can be enhanced incrementally without breaking production.

View file

@ -11,6 +11,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
## Aktuelle Situation
### Technologie-Stack
- **Frontend:** SvelteKit v2.22 mit Svelte 5.0
- **Styling:** Tailwind CSS v4.0
- **Backend:** PocketBase (aktuell)
@ -18,6 +19,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
- **Hosting:** Separate Instanzen für Dev (localhost:8090) und Prod (pb.ulo.ad)
### Implementierte Features
- URL-Shortening mit custom Short-Codes
- User Authentication & Profile Management
- Link-Management mit Tags
@ -89,6 +91,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
## Migrations-Strategie (falls notwendig)
### Wann der Wechsel sinnvoll wäre:
- ✅ Mehr als 10.000 aktive User
- ✅ Mehr als 1 Million Clicks/Tag
- ✅ Komplexe Business Intelligence Anforderungen
@ -96,6 +99,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
- ✅ Geografisch verteilte Deployments
### Empfohlener Migrations-Pfad:
1. **Phase 1:** Weiter mit PocketBase (JETZT)
2. **Phase 2:** Redis-Cache für Hot-Links hinzufügen
3. **Phase 3:** Analytics in separaten Service auslagern
@ -104,6 +108,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
## Konkrete Empfehlungen
### Kurzfristig (0-3 Monate)
1. **Bei PocketBase bleiben**
- Fokus auf Feature-Entwicklung
- User-Feedback sammeln
@ -115,6 +120,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
- Lazy-Loading für Analytics
### Mittelfristig (3-6 Monate)
1. **Hybrid-Ansatz evaluieren**
- PocketBase für Auth & Core-Data
- Redis für Link-Resolution Cache
@ -126,6 +132,7 @@ Nach eingehender Analyse des aktuellen Projekts und dem erhaltenen Feedback bewe
- Datenbasierte Entscheidungen treffen
### Langfristig (6+ Monate)
1. **Bei nachgewiesenem Bedarf**
- Migration zu PostgreSQL planen
- Schrittweise Migration
@ -143,17 +150,17 @@ Die Kritik an PocketBase ist **teilweise berechtigt**, aber für die aktuelle Pr
## Anhang: Feature-Vergleich
| Feature | PocketBase | PostgreSQL + Stack | Bewertung |
|---------|------------|-------------------|-----------|
| Setup-Zeit | 5 Minuten | 2-3 Stunden | PocketBase ✅ |
| Auth System | Eingebaut | Lucia/Auth.js nötig | PocketBase ✅ |
| REST API | Automatisch | Prisma + tRPC/REST | PocketBase ✅ |
| Realtime | WebSockets eingebaut | Separate Lösung | PocketBase ✅ |
| File Storage | Eingebaut | S3/Cloudinary | PocketBase ✅ |
| Admin UI | Eingebaut | Eigenbau/Forest Admin | PocketBase ✅ |
| Complex Queries | Limitiert | Vollständig | PostgreSQL ✅ |
| Skalierung | Vertikal | Horizontal | PostgreSQL ✅ |
| Performance | Gut bis 100k Users | Exzellent | PostgreSQL ✅ |
| Kosten | Niedrig | Mittel-Hoch | PocketBase ✅ |
| Feature | PocketBase | PostgreSQL + Stack | Bewertung |
| --------------- | -------------------- | --------------------- | ------------- |
| Setup-Zeit | 5 Minuten | 2-3 Stunden | PocketBase ✅ |
| Auth System | Eingebaut | Lucia/Auth.js nötig | PocketBase ✅ |
| REST API | Automatisch | Prisma + tRPC/REST | PocketBase ✅ |
| Realtime | WebSockets eingebaut | Separate Lösung | PocketBase ✅ |
| File Storage | Eingebaut | S3/Cloudinary | PocketBase ✅ |
| Admin UI | Eingebaut | Eigenbau/Forest Admin | PocketBase ✅ |
| Complex Queries | Limitiert | Vollständig | PostgreSQL ✅ |
| Skalierung | Vertikal | Horizontal | PostgreSQL ✅ |
| Performance | Gut bis 100k Users | Exzellent | PostgreSQL ✅ |
| Kosten | Niedrig | Mittel-Hoch | PocketBase ✅ |
**Gesamtbewertung für aktuelles Projekt:** PocketBase 7:3 PostgreSQL
**Gesamtbewertung für aktuelles Projekt:** PocketBase 7:3 PostgreSQL

View file

@ -209,7 +209,7 @@ export function getVariant(testId: string, cookies: Cookies) {
variant = Math.random() > 0.5 ? 'A' : 'B';
cookies.set(cookieName, variant, {
path: '/',
maxAge: 60 * 60 * 24 * 30 // 30 Tage
maxAge: 60 * 60 * 24 * 30, // 30 Tage
});
}
@ -219,7 +219,7 @@ export function getVariant(testId: string, cookies: Cookies) {
// Usage in +layout.server.ts
export async function load({ cookies }) {
return {
heroVariant: getVariant('homepage-hero', cookies)
heroVariant: getVariant('homepage-hero', cookies),
};
}
```

View file

@ -68,8 +68,8 @@ export class ABTestingService {
variants: [
{ id: 'control', name: 'Original', weight: 34 },
{ id: 'value-focused', name: 'Value Proposition', weight: 33 },
{ id: 'social-proof', name: 'Social Proof First', weight: 33 }
]
{ id: 'social-proof', name: 'Social Proof First', weight: 33 },
],
});
this.tests.set('homepage-cta', {
@ -80,8 +80,8 @@ export class ABTestingService {
{ id: 'start-free', name: 'Start Free', weight: 25 },
{ id: 'try-now', name: 'Try Now', weight: 25 },
{ id: 'get-started', name: 'Get Started', weight: 25 },
{ id: 'create-link', name: 'Create Your First Link', weight: 25 }
]
{ id: 'create-link', name: 'Create Your First Link', weight: 25 },
],
});
}
@ -107,7 +107,7 @@ export class ABTestingService {
maxAge: 60 * 60 * 24 * 30,
httpOnly: true,
secure: true,
sameSite: 'lax'
sameSite: 'lax',
});
return variant;
@ -151,8 +151,8 @@ export const load: PageServerLoad = async ({ locals, cookies }) => {
// Existing data...
abTests: {
hero: heroVariant,
cta: ctaVariant
}
cta: ctaVariant,
},
};
};
```
@ -173,7 +173,7 @@ export const load: PageServerLoad = async ({ locals, cookies }) => {
const heroComponents = {
control: HeroOriginal,
'value-focused': HeroValue,
'social-proof': HeroSocial
'social-proof': HeroSocial,
};
const HeroComponent = heroComponents[data.abTests?.hero?.id || 'control'];
@ -183,7 +183,7 @@ export const load: PageServerLoad = async ({ locals, cookies }) => {
'start-free': 'Start Free - No Credit Card',
'try-now': 'Try Now',
'get-started': 'Get Started Free',
'create-link': 'Create Your First Link'
'create-link': 'Create Your First Link',
};
const ctaText = ctaTexts[data.abTests?.cta?.id || 'start-free'];
@ -204,7 +204,7 @@ export const load: PageServerLoad = async ({ locals, cookies }) => {
export const featureFlags = {
newHero: import.meta.env.PUBLIC_FEATURE_NEW_HERO === 'true',
interactiveDemo: import.meta.env.PUBLIC_FEATURE_DEMO === 'true',
pricingCalculator: import.meta.env.PUBLIC_FEATURE_CALCULATOR === 'true'
pricingCalculator: import.meta.env.PUBLIC_FEATURE_CALCULATOR === 'true',
};
// .env.local
@ -225,7 +225,7 @@ export const load: PageServerLoad = async ({ url, cookies }) => {
// Override cookie for testing
cookies.set('ab_homepage-hero', variant, {
path: '/',
maxAge: 60 * 60 * 24
maxAge: 60 * 60 * 24,
});
}
@ -259,16 +259,16 @@ export function getTimeBasedVariant(): string {
export const heroHeadlines = {
control: {
headline: 'Short Links That Work Harder',
subheadline: 'Professional URL management with real-time analytics'
subheadline: 'Professional URL management with real-time analytics',
},
benefit: {
headline: 'Save 3 Hours Per Week on Link Management',
subheadline: 'Automate your URL workflow with smart analytics'
subheadline: 'Automate your URL workflow with smart analytics',
},
social: {
headline: 'Join 10,000+ Marketers Using uLoad',
subheadline: 'The trusted URL shortener for growing brands'
}
subheadline: 'The trusted URL shortener for growing brands',
},
};
```
@ -288,23 +288,23 @@ export const heroHeadlines = {
'start-free': {
text: 'Start Free - No Credit Card',
color: 'bg-purple-600 hover:bg-purple-700',
size: 'px-8 py-4 text-lg'
size: 'px-8 py-4 text-lg',
},
'try-now': {
text: 'Try Now →',
color: 'bg-blue-600 hover:bg-blue-700',
size: 'px-6 py-3 text-base'
size: 'px-6 py-3 text-base',
},
'get-started': {
text: 'Get Started Free',
color: 'bg-gradient-to-r from-purple-600 to-blue-600',
size: 'px-8 py-4 text-lg'
size: 'px-8 py-4 text-lg',
},
'create-link': {
text: '🔗 Create Your First Link',
color: 'bg-black hover:bg-gray-800',
size: 'px-6 py-4 text-lg'
}
size: 'px-6 py-4 text-lg',
},
};
const config = configs[variant];
@ -363,7 +363,7 @@ export function trackABEvent(
window.gtag('event', 'ab_test', {
test_id: testId,
variant_id: variantId,
action: action
action: action,
});
}
@ -375,8 +375,8 @@ export function trackABEvent(
testId,
variantId,
action,
timestamp: new Date().toISOString()
})
timestamp: new Date().toISOString(),
}),
});
}
```
@ -520,7 +520,7 @@ export const load: PageServerLoad = async ({ cookies, locals }) => {
heroVariant = Math.random() > 0.5 ? 'a' : 'b';
cookies.set('ab_hero', heroVariant, {
path: '/',
maxAge: 60 * 60 * 24 * 30
maxAge: 60 * 60 * 24 * 30,
});
}
@ -528,7 +528,7 @@ export const load: PageServerLoad = async ({ cookies, locals }) => {
return {
// Existing data...
heroVariant
heroVariant,
};
};
```

View file

@ -37,7 +37,7 @@ async function getLocationFromIP(ipAddress) {
const data = await response.json();
return {
country: data.country_name || 'Unknown',
city: data.city || 'Unknown'
city: data.city || 'Unknown',
};
} catch (error) {
return { country: 'Unknown', city: 'Unknown' };

View file

@ -139,7 +139,7 @@ migrate(
{ name: 'folders', oldField: 'user', newField: 'user_id' },
{ name: 'folders', oldField: 'public', newField: 'is_public' },
{ name: 'tags', oldField: 'user', newField: 'user_id' },
{ name: 'tags', oldField: 'public', newField: 'is_public' }
{ name: 'tags', oldField: 'public', newField: 'is_public' },
];
collections.forEach(({ name, oldField, newField }) => {
@ -169,7 +169,7 @@ migrate(
{ name: 'links', fields: ['user_id', 'is_active', 'folder_id'] },
{ name: 'analytics', fields: ['link_id', 'ip_address'] },
{ name: 'folders', fields: ['user_id', 'is_public'] },
{ name: 'tags', fields: ['user_id', 'is_public'] }
{ name: 'tags', fields: ['user_id', 'is_public'] },
];
collections.forEach(({ name, fields }) => {
@ -206,7 +206,7 @@ export class DBCompatibility {
folder: 'folder_id',
active: 'is_active',
public: 'is_public',
ip: 'ip_address'
ip: 'ip_address',
};
return mapping[oldName] || oldName;
@ -236,7 +236,7 @@ export class DBCompatibility {
folder_id: 'folder',
is_active: 'active',
is_public: 'public',
ip_address: 'ip'
ip_address: 'ip',
};
const transformed = { ...data };
@ -346,7 +346,7 @@ migrate((db) => {
const updates = [
'UPDATE links SET user = user_id WHERE user_id IS NOT NULL',
'UPDATE links SET active = is_active WHERE is_active IS NOT NULL',
'UPDATE analytics SET link = link_id WHERE link_id IS NOT NULL'
'UPDATE analytics SET link = link_id WHERE link_id IS NOT NULL',
// ... weitere Updates
];
@ -390,7 +390,7 @@ export async function validateMigration() {
linksIntegrity: await checkLinksIntegrity(),
analyticsConsistency: await checkAnalyticsConsistency(),
relationsValid: await checkRelationsValid(),
performanceMetrics: await checkPerformance()
performanceMetrics: await checkPerformance(),
};
return checks;