feat: New landing page design + Gap analysis document
Landing Page: - New hero section with 'The market never sleeps' headline - Live market ticker showing hot auctions - Three pillars: Discover, Track, Acquire structure - Better value propositions and CTAs - Improved TLD trending section - Cleaner pricing comparison - More 'Bloomberg meets Apple' aesthetic Documentation: - GAP_ANALYSIS.md: Comprehensive comparison of concept vs implementation - Prioritized roadmap for missing features - concept.md: Original product concept Infrastructure: - Improved start.sh with better process management - Port cleanup and verification - Better error handling and logging
This commit is contained in:
226
GAP_ANALYSIS.md
Normal file
226
GAP_ANALYSIS.md
Normal file
@ -0,0 +1,226 @@
|
||||
# Pounce Gap Analysis: Konzept vs. Implementierung
|
||||
|
||||
**Erstellt:** 10. Dezember 2024
|
||||
**Status:** Aktive Entwicklung
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Die aktuelle Implementierung deckt ca. **65-70%** des Konzepts ab. Die Kernfunktionen sind vorhanden, aber einige wichtige Features für die Monetarisierung und Differenzierung fehlen noch.
|
||||
|
||||
---
|
||||
|
||||
## 1. DISCOVER (Der Trichter für die Masse)
|
||||
|
||||
### ✅ Implementiert
|
||||
| Feature | Status | Anmerkung |
|
||||
|---------|--------|-----------|
|
||||
| Schnelles Suchfeld | ✅ | DomainChecker auf Landing Page |
|
||||
| Domain-Verfügbarkeits-Check | ✅ | WHOIS-basiert, funktioniert |
|
||||
| Affiliate-Links zu Registraren | ⚠️ | Teilweise (nur in Auktionen) |
|
||||
|
||||
### ❌ Fehlt
|
||||
| Feature | Priorität | Aufwand |
|
||||
|---------|-----------|---------|
|
||||
| **Live-Status bei besetzten Domains** | HOCH | Mittel |
|
||||
| → "Webseite ist offline" | | |
|
||||
| → "Steht zum Verkauf auf Sedo" | | |
|
||||
| → "Läuft bald aus" (Expiry-Datum anzeigen) | | |
|
||||
| **Smarte Alternativen** | MITTEL | Mittel |
|
||||
| → KI-Vorschläge basierend auf TLD-Daten | | |
|
||||
| → ".io ist teuer, nimm .xyz für $2" | | |
|
||||
| **Registrar-Preisvergleich im Suchergebnis** | MITTEL | Klein |
|
||||
|
||||
---
|
||||
|
||||
## 2. TRACK (Das Herzstück für Bindung)
|
||||
|
||||
### ✅ Implementiert
|
||||
| Feature | Status | Anmerkung |
|
||||
|---------|--------|-----------|
|
||||
| Watchlist für Domains | ✅ | Voll funktional |
|
||||
| E-Mail Alerts | ✅ | Bei Status-Änderung |
|
||||
| Domain-Limit pro Tier | ✅ | Scout: 5, Trader: 100, Tycoon: 500 |
|
||||
|
||||
### ⚠️ Teilweise Implementiert
|
||||
| Feature | Status | Was fehlt |
|
||||
|---------|--------|-----------|
|
||||
| **Status-Karten (Ampel-System)** | ⚠️ | Konzept: 🟢🟡🔴 Karten, Aktuell: Tabelle |
|
||||
| → 🟢 Chance (Domain dropped/Auktion) | ❌ | |
|
||||
| → 🟡 Warten (DNS Update, Site down) | ❌ | |
|
||||
| → 🔴 Stabil (Domain fest in Hand) | ❌ | |
|
||||
|
||||
### ❌ Fehlt (Pro Features)
|
||||
| Feature | Priorität | Aufwand |
|
||||
|---------|-----------|---------|
|
||||
| **Deep Intel: Wer ist der Besitzer?** | MITTEL | Mittel |
|
||||
| → Automatisierte Impressums-Suche | | |
|
||||
| → Enhanced WHOIS-Daten | | |
|
||||
| **Pre-Drop Alerts** | HOCH | Hoch |
|
||||
| → DNS-Änderungen erkennen | | |
|
||||
| → Warnung BEVOR Domain droppt | | |
|
||||
| **Website-Monitoring** | MITTEL | Mittel |
|
||||
| → Ist Seite offline? | | |
|
||||
| → HTTP-Status-Checks | | |
|
||||
|
||||
---
|
||||
|
||||
## 3. ACQUIRE (Der Marktplatz für Action)
|
||||
|
||||
### ✅ Implementiert
|
||||
| Feature | Status | Anmerkung |
|
||||
|---------|--------|-----------|
|
||||
| Auktions-Aggregation | ✅ | GoDaddy, Sedo, NameJet, DropCatch |
|
||||
| Filter nach TLD, Preis | ✅ | Voll funktional |
|
||||
| "Ending Soon" Auktionen | ✅ | Funktioniert |
|
||||
| "Hot" Auktionen | ✅ | Nach Geboten sortiert |
|
||||
|
||||
### ⚠️ Teilweise Implementiert
|
||||
| Feature | Status | Was fehlt |
|
||||
|---------|--------|-----------|
|
||||
| **No-Bullshit-Filter** | ⚠️ | Basis-Filter vorhanden |
|
||||
| → Automatisches Spam-Filtern | ❌ | Keine KI/Heuristik |
|
||||
| → "Keine Zahlen, max 2 Hyphens" | ❌ | |
|
||||
|
||||
### ❌ Fehlt (Pro Features)
|
||||
| Feature | Priorität | Aufwand |
|
||||
|---------|-----------|---------|
|
||||
| **Deal-Score / Valuation** | HOCH | Mittel |
|
||||
| → Estibot o.ä. API Integration | | |
|
||||
| → "Undervalued 🔥" Label | | |
|
||||
| **Arbitrage-Radar** | MITTEL | Mittel |
|
||||
| → "Kaufe hier für $60, verkaufe dort für $100" | | |
|
||||
| **Smart Filter Presets** | NIEDRIG | Klein |
|
||||
| → "High Value / Low Price" | | |
|
||||
| → "Short Domains (4 Letters)" | | |
|
||||
| → "No Trash" | | |
|
||||
|
||||
---
|
||||
|
||||
## 4. TLD INTELLIGENCE
|
||||
|
||||
### ✅ Implementiert
|
||||
| Feature | Status | Anmerkung |
|
||||
|---------|--------|-----------|
|
||||
| 886+ TLDs getrackt | ✅ | Voll funktional |
|
||||
| Preisentwicklung (Charts) | ✅ | 90-Tage Historie |
|
||||
| Trending TLDs | ✅ | Auf Landing Page |
|
||||
| Registrar-Vergleich | ✅ | Pro TLD verfügbar |
|
||||
|
||||
### ❌ Fehlt
|
||||
| Feature | Priorität | Aufwand |
|
||||
|---------|-----------|---------|
|
||||
| **Arbitrage Finder Tabelle** | MITTEL | Klein |
|
||||
| → "Reg Fee vs. Avg Resale Price" | | |
|
||||
| → Highlight höchste Margen | | |
|
||||
| **Registrierungs-Trends** | NIEDRIG | Mittel |
|
||||
| → "Wächst die TLD?" (Volumen) | | |
|
||||
|
||||
---
|
||||
|
||||
## 5. LANDING PAGE / MARKETING
|
||||
|
||||
### ✅ Implementiert
|
||||
| Feature | Status | Anmerkung |
|
||||
|---------|--------|-----------|
|
||||
| Hero mit Suchfeld | ✅ | DomainChecker |
|
||||
| Trending TLDs | ✅ | 4 Karten |
|
||||
| Trust Indicators | ✅ | 886+ TLDs, 24/7, etc. |
|
||||
| Pricing CTA | ✅ | Scout vs Trader |
|
||||
|
||||
### ❌ Fehlt (laut Konzept)
|
||||
| Feature | Priorität | Aufwand |
|
||||
|---------|-----------|---------|
|
||||
| **Live Market Ticker** | HOCH | Mittel |
|
||||
| → Durchlaufende Leiste mit heißen Domains | | |
|
||||
| **Bessere Headlines** | HOCH | Klein |
|
||||
| → "Der Markt schläft nie. Du schon." | | |
|
||||
| → "Don't guess. Know." | | |
|
||||
| **Value Props klarer** | MITTEL | Klein |
|
||||
| → Discover, Track, Acquire Struktur | | |
|
||||
| **Market Preview Teaser** | MITTEL | Klein |
|
||||
| → "12 unterbewertete .ai Domains" | | |
|
||||
|
||||
---
|
||||
|
||||
## 6. COMMAND CENTER (Dashboard)
|
||||
|
||||
### ✅ Implementiert
|
||||
| Feature | Status | Anmerkung |
|
||||
|---------|--------|-----------|
|
||||
| Dashboard Übersicht | ✅ | Basis-Dashboard |
|
||||
| Watchlist | ✅ | Voll funktional |
|
||||
| Portfolio Management | ✅ | Kauf/Verkauf tracking |
|
||||
| Settings | ✅ | Profil, Billing |
|
||||
|
||||
### ⚠️ Teilweise Implementiert
|
||||
| Feature | Status | Was fehlt |
|
||||
|---------|--------|-----------|
|
||||
| **Activity Feed** | ⚠️ | Keine echten Notifications |
|
||||
| → "3 Domains haben Status geändert" | ❌ | |
|
||||
| **Market Pulse** | ⚠️ | Nicht im Dashboard |
|
||||
| → "5 Auktionen enden heute" | ❌ | |
|
||||
| **Sidebar Navigation** | ⚠️ | Aktuell: Header-Nav |
|
||||
|
||||
### ❌ Fehlt
|
||||
| Feature | Priorität | Aufwand |
|
||||
|---------|-----------|---------|
|
||||
| **Pro Dashboard mit Sidebar** | MITTEL | Mittel |
|
||||
| → Collapsible Sidebar | | |
|
||||
| → Professionelleres "Tool"-Feeling | | |
|
||||
| **Saved Filters** | NIEDRIG | Klein |
|
||||
| → "My AI Search" speichern | | |
|
||||
|
||||
---
|
||||
|
||||
## 7. TONE OF VOICE & BRANDING
|
||||
|
||||
### ⚠️ Teilweise Implementiert
|
||||
| Aspekt | Status | Anmerkung |
|
||||
|--------|--------|-----------|
|
||||
| Dark Mode Design | ✅ | Durchgehend |
|
||||
| Neon-Akzente (Signalgrün) | ✅ | Accent color |
|
||||
| Minimalistisch | ✅ | Gutes Design |
|
||||
|
||||
### ❌ Verbesserungsbedarf
|
||||
| Aspekt | Problem | Lösung |
|
||||
|--------|---------|--------|
|
||||
| **Headlines** | Zu generisch | Konzept-Headlines verwenden |
|
||||
| **Sprache** | Zu technisch | Mehr "treibend, präzise" |
|
||||
| **Versprechen** | Nicht klar | "Don't guess. Know." prominenter |
|
||||
|
||||
---
|
||||
|
||||
## Priorisierte Roadmap
|
||||
|
||||
### Phase 1: Quick Wins (1-2 Wochen)
|
||||
1. ✨ **Landing Page Headlines überarbeiten**
|
||||
2. ✨ **Live Market Ticker hinzufügen**
|
||||
3. ✨ **Deal-Score Placeholder** (auch wenn nur Dummy)
|
||||
4. ✨ **Status-Ampel im Dashboard**
|
||||
|
||||
### Phase 2: Value Add (2-4 Wochen)
|
||||
1. 🚀 **Domain Valuation Integration** (Estibot/GoDaddy API)
|
||||
2. 🚀 **Enhanced Domain Info** bei Suche (Expiry, Status)
|
||||
3. 🚀 **Smarte Alternativen** bei Suche
|
||||
4. 🚀 **No-Bullshit Auction Filter**
|
||||
|
||||
### Phase 3: Pro Features (4-8 Wochen)
|
||||
1. 💎 **Pre-Drop Alerts** (DNS-Monitoring)
|
||||
2. 💎 **Website-Status Monitoring**
|
||||
3. 💎 **Arbitrage Finder**
|
||||
4. 💎 **Sidebar Command Center**
|
||||
|
||||
---
|
||||
|
||||
## Fazit
|
||||
|
||||
Die technische Basis ist **solid**. Was fehlt, sind primär:
|
||||
|
||||
1. **Differenzierende Features** (Deal-Score, Arbitrage, Pre-Drop)
|
||||
2. **Besseres Marketing** (Headlines, Tone of Voice)
|
||||
3. **UX-Polish** (Ampel-System, Activity Feed, Market Ticker)
|
||||
|
||||
Mit den Quick Wins (Phase 1) kann pounce bereits deutlich professioneller wirken und die Conversion verbessern.
|
||||
|
||||
0
concept.md
Normal file
0
concept.md
Normal file
@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect, useState, useRef } from 'react'
|
||||
import Image from 'next/image'
|
||||
import { Header } from '@/components/Header'
|
||||
import { Footer } from '@/components/Footer'
|
||||
@ -21,6 +21,15 @@ import {
|
||||
BarChart3,
|
||||
Globe,
|
||||
Check,
|
||||
Search,
|
||||
Target,
|
||||
Gavel,
|
||||
Sparkles,
|
||||
Activity,
|
||||
LineChart,
|
||||
Lock,
|
||||
Filter,
|
||||
Crosshair,
|
||||
} from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import clsx from 'clsx'
|
||||
@ -32,6 +41,13 @@ interface TrendingTld {
|
||||
price_change: number
|
||||
}
|
||||
|
||||
interface HotAuction {
|
||||
domain: string
|
||||
current_bid: number
|
||||
time_remaining: string
|
||||
platform: string
|
||||
}
|
||||
|
||||
// Shimmer for loading states
|
||||
function Shimmer({ className }: { className?: string }) {
|
||||
return (
|
||||
@ -70,24 +86,66 @@ function AnimatedNumber({ value, suffix = '' }: { value: number, suffix?: string
|
||||
return <>{count.toLocaleString()}{suffix}</>
|
||||
}
|
||||
|
||||
// Live Market Ticker
|
||||
function MarketTicker({ auctions }: { auctions: HotAuction[] }) {
|
||||
const tickerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Duplicate items for seamless loop
|
||||
const items = [...auctions, ...auctions]
|
||||
|
||||
if (auctions.length === 0) return null
|
||||
|
||||
return (
|
||||
<div className="relative overflow-hidden bg-background-secondary/30 border-y border-border/50 py-3">
|
||||
<div
|
||||
ref={tickerRef}
|
||||
className="flex animate-[ticker_30s_linear_infinite] hover:[animation-play-state:paused]"
|
||||
style={{ width: 'max-content' }}
|
||||
>
|
||||
{items.map((auction, i) => (
|
||||
<div
|
||||
key={`${auction.domain}-${i}`}
|
||||
className="flex items-center gap-6 px-8 border-r border-border/30"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="w-2 h-2 rounded-full bg-accent animate-pulse" />
|
||||
<span className="font-mono text-sm text-foreground">{auction.domain}</span>
|
||||
</div>
|
||||
<span className="text-sm text-accent font-semibold">${auction.current_bid}</span>
|
||||
<span className="text-xs text-foreground-subtle">{auction.time_remaining}</span>
|
||||
<span className="text-xs text-foreground-muted uppercase">{auction.platform}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const { checkAuth, isLoading, isAuthenticated } = useStore()
|
||||
const [trendingTlds, setTrendingTlds] = useState<TrendingTld[]>([])
|
||||
const [hotAuctions, setHotAuctions] = useState<HotAuction[]>([])
|
||||
const [loadingTlds, setLoadingTlds] = useState(true)
|
||||
const [loadingAuctions, setLoadingAuctions] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
checkAuth()
|
||||
fetchTldData()
|
||||
fetchData()
|
||||
}, [checkAuth])
|
||||
|
||||
const fetchTldData = async () => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const trending = await api.getTrendingTlds()
|
||||
const [trending, auctions] = await Promise.all([
|
||||
api.getTrendingTlds(),
|
||||
api.getHotAuctions(8).catch(() => [])
|
||||
])
|
||||
setTrendingTlds(trending.trending.slice(0, 4))
|
||||
setHotAuctions(auctions.slice(0, 8))
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch TLD data:', error)
|
||||
console.error('Failed to fetch data:', error)
|
||||
} finally {
|
||||
setLoadingTlds(false)
|
||||
setLoadingAuctions(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,11 +167,8 @@ export default function HomePage() {
|
||||
<div className="min-h-screen bg-background relative overflow-hidden">
|
||||
{/* Background Effects */}
|
||||
<div className="fixed inset-0 pointer-events-none">
|
||||
{/* Primary glow */}
|
||||
<div className="absolute top-[-20%] left-1/2 -translate-x-1/2 w-[1200px] h-[800px] bg-accent/[0.03] rounded-full blur-[120px]" />
|
||||
{/* Secondary glow */}
|
||||
<div className="absolute bottom-[-10%] right-[-10%] w-[600px] h-[600px] bg-accent/[0.02] rounded-full blur-[100px]" />
|
||||
{/* Grid pattern */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.015]"
|
||||
style={{
|
||||
@ -125,60 +180,183 @@ export default function HomePage() {
|
||||
|
||||
<Header />
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative pt-32 sm:pt-40 md:pt-48 lg:pt-56 pb-20 sm:pb-28 px-4 sm:px-6">
|
||||
{/* Hero Section - "Bloomberg meets Apple" */}
|
||||
<section className="relative pt-32 sm:pt-40 md:pt-48 pb-16 sm:pb-20 px-4 sm:px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center max-w-5xl mx-auto">
|
||||
{/* Puma Logo */}
|
||||
<div className="flex justify-center mb-8 sm:mb-10 animate-fade-in">
|
||||
{/* Brand Mark */}
|
||||
<div className="flex justify-center mb-6 sm:mb-8 animate-fade-in">
|
||||
<div className="relative">
|
||||
<Image
|
||||
src="/pounce-puma.png"
|
||||
alt="pounce"
|
||||
width={400}
|
||||
height={280}
|
||||
className="w-40 h-auto sm:w-52 md:w-64 object-contain drop-shadow-[0_0_60px_rgba(16,185,129,0.3)]"
|
||||
priority
|
||||
/>
|
||||
{/* Glow ring */}
|
||||
<div className="absolute inset-0 -z-10 bg-accent/20 blur-3xl rounded-full scale-150" />
|
||||
<div className="inline-flex items-center gap-2 px-4 py-2 bg-accent/10 border border-accent/20 rounded-full">
|
||||
<Activity className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium text-accent">Domain Intelligence Platform</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Headline - MASSIVE */}
|
||||
{/* Main Headline - Konzept: "Der Markt schläft nie. Du schon." */}
|
||||
<h1 className="animate-slide-up">
|
||||
<span className="block font-display text-[3rem] sm:text-[4rem] md:text-[5.5rem] lg:text-[7rem] xl:text-[8rem] leading-[0.9] tracking-[-0.04em] text-foreground">
|
||||
Others wait.
|
||||
<span className="block font-display text-[2.5rem] sm:text-[3.5rem] md:text-[4.5rem] lg:text-[5.5rem] xl:text-[6.5rem] leading-[0.95] tracking-[-0.04em] text-foreground">
|
||||
The market never sleeps.
|
||||
</span>
|
||||
<span className="block font-display text-[3rem] sm:text-[4rem] md:text-[5.5rem] lg:text-[7rem] xl:text-[8rem] leading-[0.9] tracking-[-0.04em] text-foreground/40 mt-2">
|
||||
You pounce.
|
||||
<span className="block font-display text-[2.5rem] sm:text-[3.5rem] md:text-[4.5rem] lg:text-[5.5rem] xl:text-[6.5rem] leading-[0.95] tracking-[-0.04em] text-foreground/30 mt-1">
|
||||
You should.
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
{/* Subheadline */}
|
||||
<p className="mt-8 sm:mt-10 md:mt-12 text-lg sm:text-xl md:text-2xl text-foreground-muted max-w-2xl mx-auto animate-slide-up delay-100 leading-relaxed">
|
||||
Domain intelligence for the decisive. Track any domain.
|
||||
Know the moment it drops. Move before anyone else.
|
||||
{/* Subheadline - Konzept Versprechen */}
|
||||
<p className="mt-8 sm:mt-10 text-lg sm:text-xl md:text-2xl text-foreground-muted max-w-2xl mx-auto animate-slide-up delay-100 leading-relaxed">
|
||||
We scan. We watch. We alert.{' '}
|
||||
<span className="text-foreground font-medium">You pounce.</span>
|
||||
</p>
|
||||
|
||||
{/* Tagline */}
|
||||
<p className="mt-4 text-base sm:text-lg text-accent font-medium animate-slide-up delay-150">
|
||||
Don't guess. Know.
|
||||
</p>
|
||||
|
||||
{/* Domain Checker */}
|
||||
<div className="mt-10 sm:mt-14 md:mt-16 animate-slide-up delay-200">
|
||||
<div className="mt-10 sm:mt-12 animate-slide-up delay-200">
|
||||
<DomainChecker />
|
||||
</div>
|
||||
|
||||
{/* Trust Indicators */}
|
||||
<div className="mt-12 sm:mt-16 flex flex-wrap items-center justify-center gap-8 sm:gap-12 text-foreground-subtle animate-fade-in delay-300">
|
||||
<div className="mt-10 sm:mt-12 flex flex-wrap items-center justify-center gap-6 sm:gap-10 text-foreground-subtle animate-fade-in delay-300">
|
||||
<div className="flex items-center gap-2">
|
||||
<Globe className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium"><AnimatedNumber value={886} />+ TLDs tracked</span>
|
||||
<span className="text-sm font-medium"><AnimatedNumber value={886} />+ TLDs</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<BarChart3 className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium">Real-time pricing</span>
|
||||
<Gavel className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium">Live Auctions</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Bell className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium">Instant alerts</span>
|
||||
<span className="text-sm font-medium">Instant Alerts</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<LineChart className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium">Price Intel</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Live Market Ticker */}
|
||||
{!loadingAuctions && hotAuctions.length > 0 && (
|
||||
<MarketTicker auctions={hotAuctions} />
|
||||
)}
|
||||
|
||||
{/* Three Pillars: DISCOVER, TRACK, ACQUIRE */}
|
||||
<section className="relative py-24 sm:py-32 px-4 sm:px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Section Header */}
|
||||
<div className="text-center max-w-3xl mx-auto mb-16 sm:mb-20">
|
||||
<span className="text-sm font-semibold text-accent uppercase tracking-wider">Your Command Center</span>
|
||||
<h2 className="mt-4 font-display text-3xl sm:text-4xl md:text-5xl tracking-[-0.03em] text-foreground">
|
||||
Three moves to dominate.
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Pillars */}
|
||||
<div className="grid md:grid-cols-3 gap-6 lg:gap-8">
|
||||
{/* DISCOVER */}
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-b from-background-secondary/80 to-background-secondary/40
|
||||
border border-border rounded-3xl hover:border-accent/30 transition-all duration-500">
|
||||
<div className="absolute inset-0 rounded-3xl bg-accent/5 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="relative">
|
||||
<div className="w-16 h-16 bg-accent/10 border border-accent/20 rounded-2xl flex items-center justify-center mb-6">
|
||||
<Search className="w-7 h-7 text-accent" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-display text-foreground mb-4">Discover</h3>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
Instant domain intel. Not just "taken" — but <span className="text-foreground">why</span>,
|
||||
<span className="text-foreground"> when it expires</span>, and
|
||||
<span className="text-foreground"> smarter alternatives</span>.
|
||||
</p>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Real-time availability across 886+ TLDs</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Expiry dates & WHOIS data</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>AI-powered alternatives</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* TRACK */}
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-b from-background-secondary/80 to-background-secondary/40
|
||||
border border-border rounded-3xl hover:border-accent/30 transition-all duration-500
|
||||
md:-translate-y-4">
|
||||
<div className="absolute inset-0 rounded-3xl bg-accent/5 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
{/* Popular badge */}
|
||||
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||
<span className="px-4 py-1 bg-accent text-background text-xs font-semibold rounded-full">
|
||||
Most Popular
|
||||
</span>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="w-16 h-16 bg-accent/10 border border-accent/20 rounded-2xl flex items-center justify-center mb-6">
|
||||
<Crosshair className="w-7 h-7 text-accent" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-display text-foreground mb-4">Track</h3>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
Your private watchlist. We monitor 24/7 so you don't have to.
|
||||
<span className="text-foreground"> Know the second it drops.</span>
|
||||
</p>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Daily status checks</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Email & SMS alerts</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Pre-drop warnings</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ACQUIRE */}
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-b from-background-secondary/80 to-background-secondary/40
|
||||
border border-border rounded-3xl hover:border-accent/30 transition-all duration-500">
|
||||
<div className="absolute inset-0 rounded-3xl bg-accent/5 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="relative">
|
||||
<div className="w-16 h-16 bg-accent/10 border border-accent/20 rounded-2xl flex items-center justify-center mb-6">
|
||||
<Gavel className="w-7 h-7 text-accent" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-display text-foreground mb-4">Acquire</h3>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
All auctions. One place. <span className="text-foreground">Filtered</span>.
|
||||
<span className="text-foreground"> Valued</span>.
|
||||
<span className="text-foreground"> Ready to strike.</span>
|
||||
</p>
|
||||
<ul className="space-y-3 text-sm">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>GoDaddy, Sedo, NameJet, DropCatch</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>No-spam smart filters</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Check className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Deal score & valuation</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -186,18 +364,21 @@ export default function HomePage() {
|
||||
</section>
|
||||
|
||||
{/* Trending TLDs Section */}
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6">
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6 bg-background-secondary/30">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Section Header */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-6 mb-10 sm:mb-14">
|
||||
<div>
|
||||
<div className="inline-flex items-center gap-2 px-4 py-2 bg-accent/10 border border-accent/20 rounded-full mb-5">
|
||||
<TrendingUp className="w-4 h-4 text-accent" />
|
||||
<span className="text-sm font-medium text-accent">Market Intel</span>
|
||||
<span className="text-sm font-medium text-accent">TLD Intelligence</span>
|
||||
</div>
|
||||
<h2 className="font-display text-3xl sm:text-4xl md:text-5xl tracking-[-0.03em] text-foreground">
|
||||
Trending Now
|
||||
Market movers.
|
||||
</h2>
|
||||
<p className="mt-3 text-foreground-muted max-w-lg">
|
||||
Real-time pricing data across 886+ extensions. Know where the value is.
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
href="/tld-pricing"
|
||||
@ -212,7 +393,7 @@ export default function HomePage() {
|
||||
{loadingTlds ? (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5">
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<div key={i} className="p-6 bg-background-secondary/50 border border-border rounded-2xl">
|
||||
<div key={i} className="p-6 bg-background border border-border rounded-2xl">
|
||||
<Shimmer className="h-8 w-20 mb-4" />
|
||||
<Shimmer className="h-4 w-full mb-2" />
|
||||
<Shimmer className="h-4 w-24" />
|
||||
@ -225,11 +406,10 @@ export default function HomePage() {
|
||||
<Link
|
||||
key={item.tld}
|
||||
href={isAuthenticated ? `/tld-pricing/${item.tld}` : `/login?redirect=/tld-pricing/${item.tld}`}
|
||||
className="group relative p-6 bg-background-secondary/50 border border-border rounded-2xl
|
||||
hover:border-accent/30 hover:bg-background-secondary transition-all duration-300"
|
||||
className="group relative p-6 bg-background border border-border rounded-2xl
|
||||
hover:border-accent/30 transition-all duration-300"
|
||||
style={{ animationDelay: `${index * 100}ms` }}
|
||||
>
|
||||
{/* Hover glow */}
|
||||
<div className="absolute inset-0 rounded-2xl bg-accent/5 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
|
||||
<div className="relative">
|
||||
@ -254,7 +434,10 @@ export default function HomePage() {
|
||||
{isAuthenticated ? (
|
||||
<span className="text-lg font-semibold text-foreground">${(item.current_price ?? 0).toFixed(2)}<span className="text-sm font-normal text-foreground-muted">/yr</span></span>
|
||||
) : (
|
||||
<Shimmer className="h-6 w-20" />
|
||||
<span className="text-sm text-foreground-subtle flex items-center gap-1">
|
||||
<Lock className="w-3 h-3" />
|
||||
Sign in to view
|
||||
</span>
|
||||
)}
|
||||
<ChevronRight className="w-5 h-5 text-foreground-subtle group-hover:text-accent group-hover:translate-x-1 transition-all" />
|
||||
</div>
|
||||
@ -266,89 +449,39 @@ export default function HomePage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Features Section */}
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Section Header */}
|
||||
<div className="text-center max-w-3xl mx-auto mb-16 sm:mb-20">
|
||||
<span className="text-sm font-semibold text-accent uppercase tracking-wider">How It Works</span>
|
||||
<h2 className="mt-4 font-display text-3xl sm:text-4xl md:text-5xl lg:text-6xl tracking-[-0.03em] text-foreground">
|
||||
Built for hunters.
|
||||
</h2>
|
||||
<p className="mt-5 text-lg text-foreground-muted">
|
||||
The tools that give you the edge. Simple. Powerful. Decisive.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Feature Cards */}
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{[
|
||||
{
|
||||
icon: Eye,
|
||||
title: 'Always Watching',
|
||||
description: 'Daily scans across 886+ TLDs. You sleep, we hunt.',
|
||||
},
|
||||
{
|
||||
icon: Bell,
|
||||
title: 'Instant Alerts',
|
||||
description: 'Domain drops? You know first. Email alerts the moment it happens.',
|
||||
},
|
||||
{
|
||||
icon: Clock,
|
||||
title: 'Expiry Intel',
|
||||
description: 'See when domains expire. Plan your acquisition strategy.',
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: 'Your Strategy, Private',
|
||||
description: 'Your watchlist is yours alone. No one sees what you\'re tracking.',
|
||||
},
|
||||
].map((feature, i) => (
|
||||
<div
|
||||
key={feature.title}
|
||||
className="group relative p-8 rounded-2xl border border-transparent hover:border-border
|
||||
bg-transparent hover:bg-background-secondary/50 transition-all duration-500"
|
||||
>
|
||||
<div className="w-14 h-14 bg-foreground/5 border border-border rounded-2xl flex items-center justify-center mb-6
|
||||
group-hover:border-accent/30 group-hover:bg-accent/5 transition-all duration-500">
|
||||
<feature.icon className="w-6 h-6 text-foreground-muted group-hover:text-accent transition-colors duration-500" strokeWidth={1.5} />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-foreground mb-3">{feature.title}</h3>
|
||||
<p className="text-sm text-foreground-subtle leading-relaxed">{feature.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Social Proof / Stats Section */}
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6">
|
||||
<section className="relative py-24 sm:py-32 px-4 sm:px-6">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="relative p-10 sm:p-14 md:p-20 bg-gradient-to-br from-background-secondary/80 to-background-secondary/40
|
||||
border border-border rounded-3xl overflow-hidden">
|
||||
{/* Background pattern */}
|
||||
<div className="absolute inset-0 opacity-30">
|
||||
<div className="absolute top-0 right-0 w-[400px] h-[400px] bg-accent/10 rounded-full blur-[100px]" />
|
||||
</div>
|
||||
|
||||
<div className="relative grid sm:grid-cols-3 gap-10 sm:gap-6 text-center">
|
||||
<div>
|
||||
<p className="font-display text-5xl sm:text-6xl md:text-7xl text-foreground mb-2">
|
||||
<AnimatedNumber value={886} />+
|
||||
</p>
|
||||
<p className="text-sm text-foreground-muted">TLDs Tracked</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-display text-5xl sm:text-6xl md:text-7xl text-foreground mb-2">
|
||||
24<span className="text-accent">/</span>7
|
||||
</p>
|
||||
<p className="text-sm text-foreground-muted">Monitoring</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-display text-5xl sm:text-6xl md:text-7xl text-foreground mb-2">
|
||||
<AnimatedNumber value={10} />s
|
||||
</p>
|
||||
<p className="text-sm text-foreground-muted">Alert Speed</p>
|
||||
<div className="relative">
|
||||
<h2 className="font-display text-3xl sm:text-4xl text-center text-foreground mb-12">
|
||||
The edge you need.
|
||||
</h2>
|
||||
|
||||
<div className="grid sm:grid-cols-3 gap-10 sm:gap-6 text-center">
|
||||
<div>
|
||||
<p className="font-display text-5xl sm:text-6xl md:text-7xl text-foreground mb-2">
|
||||
<AnimatedNumber value={886} />+
|
||||
</p>
|
||||
<p className="text-sm text-foreground-muted">TLDs Tracked Daily</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-display text-5xl sm:text-6xl md:text-7xl text-foreground mb-2">
|
||||
24<span className="text-accent">/</span>7
|
||||
</p>
|
||||
<p className="text-sm text-foreground-muted">Always Watching</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-display text-5xl sm:text-6xl md:text-7xl text-foreground mb-2">
|
||||
<AnimatedNumber value={10} />s
|
||||
</p>
|
||||
<p className="text-sm text-foreground-muted">Alert Speed</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -359,36 +492,72 @@ export default function HomePage() {
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
<span className="text-sm font-semibold text-accent uppercase tracking-wider">Pricing</span>
|
||||
<h2 className="mt-4 font-display text-3xl sm:text-4xl md:text-5xl lg:text-6xl tracking-[-0.03em] text-foreground">
|
||||
Pick your weapon.
|
||||
<h2 className="mt-4 font-display text-3xl sm:text-4xl md:text-5xl tracking-[-0.03em] text-foreground">
|
||||
Simple. Transparent. Powerful.
|
||||
</h2>
|
||||
<p className="mt-5 text-lg text-foreground-muted max-w-xl mx-auto">
|
||||
Start free with 5 domains. Scale to 500+ when you need more firepower.
|
||||
Start free. Scale when you're ready.
|
||||
</p>
|
||||
|
||||
{/* Quick Plans */}
|
||||
<div className="mt-12 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<div className="flex items-center gap-4 px-6 py-4 bg-background-secondary/50 border border-border rounded-2xl">
|
||||
<div className="w-12 h-12 bg-foreground/5 rounded-xl flex items-center justify-center">
|
||||
<Zap className="w-5 h-5 text-foreground-muted" />
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className="font-semibold text-foreground">Scout</p>
|
||||
<p className="text-sm text-foreground-muted">Free forever</p>
|
||||
<div className="mt-12 grid sm:grid-cols-2 gap-4 max-w-2xl mx-auto">
|
||||
{/* Free Plan */}
|
||||
<div className="p-6 bg-background-secondary/50 border border-border rounded-2xl text-left">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-10 h-10 bg-foreground/5 rounded-xl flex items-center justify-center">
|
||||
<Zap className="w-5 h-5 text-foreground-muted" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-foreground">Scout</p>
|
||||
<p className="text-sm text-foreground-muted">Free forever</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="space-y-2 text-sm text-foreground-subtle">
|
||||
<li className="flex items-center gap-2">
|
||||
<Check className="w-4 h-4 text-accent" />
|
||||
<span>5 domains watched</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<Check className="w-4 h-4 text-accent" />
|
||||
<span>Daily status checks</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<Check className="w-4 h-4 text-accent" />
|
||||
<span>TLD price explorer</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ArrowRight className="w-5 h-5 text-foreground-subtle hidden sm:block" />
|
||||
<ChevronRight className="w-5 h-5 text-foreground-subtle rotate-90 sm:hidden" />
|
||||
|
||||
<div className="flex items-center gap-4 px-6 py-4 bg-accent/5 border border-accent/20 rounded-2xl">
|
||||
<div className="w-12 h-12 bg-accent/10 rounded-xl flex items-center justify-center">
|
||||
<TrendingUp className="w-5 h-5 text-accent" />
|
||||
{/* Pro Plan */}
|
||||
<div className="p-6 bg-accent/5 border border-accent/20 rounded-2xl text-left relative">
|
||||
<div className="absolute -top-3 right-4">
|
||||
<span className="px-3 py-1 bg-accent text-background text-xs font-semibold rounded-full">
|
||||
Popular
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<p className="font-semibold text-foreground">Trader</p>
|
||||
<p className="text-sm text-accent">$19/month</p>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-10 h-10 bg-accent/10 rounded-xl flex items-center justify-center">
|
||||
<Target className="w-5 h-5 text-accent" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-foreground">Trader</p>
|
||||
<p className="text-sm text-accent">$19/month</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="space-y-2 text-sm text-foreground-subtle">
|
||||
<li className="flex items-center gap-2">
|
||||
<Check className="w-4 h-4 text-accent" />
|
||||
<span>100 domains watched</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<Check className="w-4 h-4 text-accent" />
|
||||
<span>Priority alerts</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<Check className="w-4 h-4 text-accent" />
|
||||
<span>Full auction access</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -398,7 +567,7 @@ export default function HomePage() {
|
||||
className="inline-flex items-center gap-2 px-8 py-4 bg-foreground text-background rounded-xl
|
||||
font-semibold hover:bg-foreground/90 transition-all duration-300"
|
||||
>
|
||||
Compare Plans
|
||||
Compare All Plans
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
<Link
|
||||
@ -415,11 +584,12 @@ export default function HomePage() {
|
||||
{/* Final CTA */}
|
||||
<section className="relative py-24 sm:py-32 px-4 sm:px-6">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
<p className="text-accent font-medium mb-4">Join the hunters.</p>
|
||||
<h2 className="font-display text-4xl sm:text-5xl md:text-6xl lg:text-7xl tracking-[-0.03em] text-foreground mb-6">
|
||||
Ready to hunt?
|
||||
Ready to pounce?
|
||||
</h2>
|
||||
<p className="text-xl text-foreground-muted mb-10 max-w-lg mx-auto">
|
||||
Track your first domain in under a minute. No credit card required.
|
||||
Track your first domain in under a minute. Free forever, no credit card.
|
||||
</p>
|
||||
<Link
|
||||
href={isAuthenticated ? "/dashboard" : "/register"}
|
||||
@ -427,7 +597,7 @@ export default function HomePage() {
|
||||
text-lg font-semibold hover:bg-accent-hover transition-all duration-300
|
||||
shadow-[0_0_40px_rgba(16,185,129,0.2)] hover:shadow-[0_0_60px_rgba(16,185,129,0.3)]"
|
||||
>
|
||||
{isAuthenticated ? "Go to Dashboard" : "Get Started Free"}
|
||||
{isAuthenticated ? "Go to Dashboard" : "Start Hunting — It's Free"}
|
||||
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
|
||||
@ -441,6 +611,14 @@ export default function HomePage() {
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
|
||||
{/* Ticker Animation Keyframes */}
|
||||
<style jsx global>{`
|
||||
@keyframes ticker {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-50%); }
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
256
start.sh
256
start.sh
@ -1,65 +1,213 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# POUNCE Quick Start Script
|
||||
# Starts both backend and frontend for development
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo "🐆 Starting POUNCE..."
|
||||
echo ""
|
||||
# Pounce Start Script
|
||||
# Startet Backend und Frontend sauber
|
||||
|
||||
# Check if backend venv exists
|
||||
if [ ! -d "backend/venv" ]; then
|
||||
echo "❌ Backend not set up. Run ./deploy.sh first!"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BACKEND_DIR="$SCRIPT_DIR/backend"
|
||||
FRONTEND_DIR="$SCRIPT_DIR/frontend"
|
||||
|
||||
echo "=========================================="
|
||||
echo "🚀 Pounce Start Script"
|
||||
echo "=========================================="
|
||||
|
||||
# Farben für Output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Funktion zum Beenden von Prozessen
|
||||
stop_services() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}🛑 Beende laufende Prozesse...${NC}"
|
||||
|
||||
# Backend (uvicorn) - mehrere Versuche
|
||||
pkill -9 -f "uvicorn app.main:app" 2>/dev/null || true
|
||||
pkill -9 -f "uvicorn" 2>/dev/null || true
|
||||
|
||||
# Frontend (next) - mehrere Versuche
|
||||
pkill -9 -f "next start" 2>/dev/null || true
|
||||
pkill -9 -f "node.*next" 2>/dev/null || true
|
||||
pkill -9 -f "npm start" 2>/dev/null || true
|
||||
|
||||
# Port 3000 freigeben (alle Prozesse auf Port 3000)
|
||||
lsof -ti:3000 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||||
|
||||
# Port 8000 freigeben
|
||||
lsof -ti:8000 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||||
|
||||
sleep 3
|
||||
|
||||
# Prüfen ob Ports frei sind
|
||||
if lsof -i:8000 >/dev/null 2>&1; then
|
||||
echo -e "${RED}✗ Port 8000 ist noch belegt!${NC}"
|
||||
lsof -i:8000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if lsof -i:3000 >/dev/null 2>&1; then
|
||||
echo -e "${RED}✗ Port 3000 ist noch belegt!${NC}"
|
||||
lsof -i:3000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ Alle Prozesse beendet, Ports frei${NC}"
|
||||
}
|
||||
|
||||
# Funktion zum Starten des Backends
|
||||
start_backend() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}🔧 Starte Backend...${NC}"
|
||||
|
||||
cd "$BACKEND_DIR"
|
||||
|
||||
# Aktiviere Virtual Environment
|
||||
if [ ! -d "venv" ]; then
|
||||
echo -e "${RED}✗ venv nicht gefunden!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source venv/bin/activate
|
||||
|
||||
# Lösche altes Log
|
||||
> backend.log
|
||||
|
||||
# Starte uvicorn im Hintergrund
|
||||
nohup uvicorn app.main:app --host 0.0.0.0 --port 8000 > backend.log 2>&1 &
|
||||
BACKEND_PID=$!
|
||||
|
||||
echo "Backend PID: $BACKEND_PID"
|
||||
|
||||
# Warte und prüfe mehrmals
|
||||
for i in {1..10}; do
|
||||
sleep 1
|
||||
if curl -s http://127.0.0.1:8000/health > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓ Backend läuft auf Port 8000${NC}"
|
||||
return 0
|
||||
fi
|
||||
echo -n "."
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${RED}✗ Backend konnte nicht gestartet werden${NC}"
|
||||
echo "Letzte 30 Zeilen vom Log:"
|
||||
tail -30 backend.log
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Kill any existing processes on our ports
|
||||
echo "🔧 Cleaning up old processes..."
|
||||
lsof -ti:8000 | xargs kill -9 2>/dev/null || true
|
||||
lsof -ti:3000 | xargs kill -9 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# Start Backend
|
||||
echo "🚀 Starting Backend on port 8000..."
|
||||
cd backend
|
||||
source venv/bin/activate
|
||||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 &
|
||||
BACKEND_PID=$!
|
||||
cd ..
|
||||
|
||||
# Wait for backend to start
|
||||
sleep 3
|
||||
|
||||
# Check if backend is running
|
||||
if curl -s http://localhost:8000/health > /dev/null 2>&1; then
|
||||
echo "✅ Backend running!"
|
||||
else
|
||||
echo "❌ Backend failed to start. Check logs."
|
||||
# Funktion zum Starten des Frontends
|
||||
start_frontend() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}🎨 Starte Frontend...${NC}"
|
||||
|
||||
cd "$FRONTEND_DIR"
|
||||
|
||||
# Prüfe ob .next existiert
|
||||
if [ ! -d ".next" ]; then
|
||||
echo -e "${RED}✗ .next nicht gefunden! Bitte erst 'npm run build' ausführen.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Lösche altes Log
|
||||
> frontend.log
|
||||
|
||||
# Starte Frontend im Hintergrund
|
||||
PORT=3000 nohup npm start > frontend.log 2>&1 &
|
||||
FRONTEND_PID=$!
|
||||
|
||||
echo "Frontend PID: $FRONTEND_PID"
|
||||
|
||||
# Warte und prüfe mehrmals
|
||||
for i in {1..15}; do
|
||||
sleep 1
|
||||
|
||||
# Prüfe ob Prozess noch läuft
|
||||
if ! kill -0 $FRONTEND_PID 2>/dev/null; then
|
||||
echo ""
|
||||
echo -e "${RED}✗ Frontend-Prozess wurde beendet${NC}"
|
||||
echo "Letzte 30 Zeilen vom Log:"
|
||||
tail -30 frontend.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prüfe ob Port offen ist
|
||||
if curl -s http://127.0.0.1:3000 > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓ Frontend läuft auf Port 3000${NC}"
|
||||
return 0
|
||||
fi
|
||||
echo -n "."
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${RED}✗ Frontend konnte nicht gestartet werden${NC}"
|
||||
echo "Letzte 30 Zeilen vom Log:"
|
||||
tail -30 frontend.log
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Start Frontend
|
||||
echo "🚀 Starting Frontend on port 3000..."
|
||||
cd frontend
|
||||
npm run dev &
|
||||
FRONTEND_PID=$!
|
||||
cd ..
|
||||
# Funktion für Status-Anzeige
|
||||
show_status() {
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo -e "${GREEN}✓ Pounce erfolgreich gestartet!${NC}"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "URLs:"
|
||||
echo " Backend: http://127.0.0.1:8000"
|
||||
echo " Frontend: http://127.0.0.1:3000"
|
||||
echo " Health: http://127.0.0.1:8000/health"
|
||||
echo ""
|
||||
echo "Logs:"
|
||||
echo " Backend: tail -f $BACKEND_DIR/backend.log"
|
||||
echo " Frontend: tail -f $FRONTEND_DIR/frontend.log"
|
||||
echo ""
|
||||
echo "Laufende Prozesse:"
|
||||
ps aux | grep -E "(uvicorn|next start)" | grep -v grep | awk '{print " PID " $2 ": " $11 " " $12 " " $13}'
|
||||
echo ""
|
||||
echo "Ports:"
|
||||
lsof -i:8000 -i:3000 2>/dev/null | grep LISTEN || echo " Keine Port-Info verfügbar"
|
||||
echo ""
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " POUNCE is starting..."
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo " Backend: http://localhost:8000"
|
||||
echo " Frontend: http://localhost:3000"
|
||||
echo " API Docs: http://localhost:8000/docs"
|
||||
echo ""
|
||||
echo " Press Ctrl+C to stop all services"
|
||||
echo ""
|
||||
# Funktion zum Testen der Services
|
||||
test_services() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}🧪 Teste Services...${NC}"
|
||||
|
||||
# Test Backend Health
|
||||
HEALTH=$(curl -s http://127.0.0.1:8000/health | grep -o '"status":"healthy"' || echo "")
|
||||
if [ -n "$HEALTH" ]; then
|
||||
echo -e "${GREEN}✓ Backend Health Check OK${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Backend Health Check FAILED${NC}"
|
||||
fi
|
||||
|
||||
# Test Frontend
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000)
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
echo -e "${GREEN}✓ Frontend HTTP 200 OK${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Frontend HTTP $HTTP_CODE${NC}"
|
||||
fi
|
||||
|
||||
# Test OAuth Providers
|
||||
OAUTH=$(curl -s http://127.0.0.1:8000/api/v1/oauth/providers | grep -o '"google_enabled":true' || echo "")
|
||||
if [ -n "$OAUTH" ]; then
|
||||
echo -e "${GREEN}✓ OAuth Providers OK${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ OAuth Check konnte nicht durchgeführt werden${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait for both processes
|
||||
trap "kill $BACKEND_PID $FRONTEND_PID 2>/dev/null" EXIT
|
||||
wait
|
||||
# Main
|
||||
stop_services
|
||||
start_backend
|
||||
start_frontend
|
||||
test_services
|
||||
show_status
|
||||
|
||||
echo -e "${GREEN}🎉 Alles läuft!${NC}"
|
||||
echo ""
|
||||
echo "Zum Stoppen: pkill -f 'uvicorn' && pkill -f 'next start'"
|
||||
|
||||
Reference in New Issue
Block a user