Digitale Lösungen mit System

Wir bauen Systeme, die rund um die Uhr arbeiten. KI-gestützte Content-Pipelines, Suchmaschinen mit Millionen Datensätzen und E-Commerce-Portale mit eigenem Chatbot – alles auf eigener Infrastruktur.

KDP-Publikationen

Prozedurale Publikations-Architektur

Wir produzieren keine Zufallsprodukte, sondern konstruierte Unikate. Unsere Bücher entstehen in einer autarken Pipeline, die höchsten algorithmischen Standards folgt. Jedes Rätsel durchläuft eine mathematische Validierung und erhält einen kryptografischen Hash-Fingerabdruck. Dieser wird in Echtzeit gegen unsere Datenbank auf Kollisionen geprüft: Existiert der Hash bereits, wird das Element sofort verworfen. Diese strikte Logik garantiert absolute Redundanzfreiheit über alle Serien hinweg. Unsere Architektur akzeptiert zudem nur Strukturen mit exakt einer beweisbaren Lösung. Das Ergebnis ist prozessuale Perfektion statt einfacher Automatisierung.

9+
Publikationen
200+
Seiten/Buch
100%
Automatisiert
Das Rätselbuch für echte Angler & Team Schneider
Auftrennen ist auch Stricken
Kakuro Expert 15x15 Großdruck
KI und Machine Learning Visualisierung
Rabotal Rabe
Amazon
eBay
Elektronik
Enterprise-Grade Eigenentwicklung

Vollautomatisierte Deal-Aggregation

rabotal.de

Eine Suchmaschine, die wir von Grund auf selbst entwickelt haben. Über 4,6 Millionen Deals von mehr als 14.500 Shops – durchsuchbar in unter 50 Millisekunden. Drei parallele Import-Pipelines ziehen täglich frische Daten von AWIN, eBay und weiteren Netzwerken. 852 selbst definierte Mapping-Regeln sorgen dafür, dass jedes Produkt in der richtigen Kategorie landet. Das Backend läuft auf Express 5.2 mit Prisma 7 und Postgres 16, die Suche auf OpenSearch 3.5.

4.6M+
Indexierte Deals
14.586
Shops integriert
852
Mapping-Regeln
<50ms
Suchlatenz
OpenSearch Cluster
Postgres + Prisma
JWT + Google OAuth
3 Import-Pipelines
Next.js
Frontend
Express
Backend
Postgres
Database
OpenSearch
Search
Prisma
ORM
TypeScript
Language
AWIN
Affiliate
eBay
Partner
Semantische Suche und Datenverarbeitung
import { PrismaClient, Deal, Shop, PriceAlert } from "@prisma/client";
import express, { Request, Response, NextFunction, Router } from "express";
import { Client, RequestParams } from "@opensearch-project/opensearch";
import { createHash, randomUUID } from "crypto";
import { z } from "zod";

const prisma = new PrismaClient();
const router = Router();

interface SearchResult {
  hits: Deal[];
  total: number;
  aggregations: Record<string, unknown>;
  page: number;
  totalPages: number;
}

interface CategoryMapping {
  pattern: RegExp;
  targetPath: string[];
  priority: number;
}

const SearchQuerySchema = z.object({
  q: z.string().min(1).max(200),
  category: z.string().optional(),
  brand: z.string().optional(),
  minPrice: z.coerce.number().min(0).optional(),
  maxPrice: z.coerce.number().max(100000).optional(),
  sort: z.enum(["price", "discount", "relevance"]).default("relevance"),
  page: z.coerce.number().min(1).default(1),
  limit: z.coerce.number().min(1).max(100).default(24)
});

const searchClient = new Client({
  node: process.env.OPENSEARCH_NODE,
  auth: {
    username: process.env.OPENSEARCH_USER,
    password: process.env.OPENSEARCH_PASSWORD
  },
  ssl: { rejectUnauthorized: true }
});

class DealAggregationService {
  private mappingCache = new Map<string, CategoryMapping[]>();

  async processFeeds(shop: Shop): Promise<number> {
    const feeds = await this.downloadFeeds(shop.feedUrl);
    const products = await this.parseProducts(feeds);
    const mappings = await this.loadMappings(shop.id);

    const deals = products.map(product => ({
      id: randomUUID(),
      shopId: shop.id,
      title: this.sanitizeText(product.title),
      description: this.sanitizeText(product.description),
      price: this.parsePrice(product.price),
      originalPrice: this.parsePrice(product.originalPrice),
      discount: this.calculateDiscount(product),
      category: this.applyMapping(product, mappings),
      brand: product.brand || null,
      imageUrl: product.imageUrl,
      productUrl: product.deepLink,
      ean: product.ean || null,
      isActive: true,
      hash: this.generateHash(product),
      createdAt: new Date(),
      updatedAt: new Date()
    }));

    await this.upsertDeals(shop.id, deals);
    await this.syncToSearchIndex(deals);

    return deals.length;
  }

  private async downloadFeeds(url: string): Promise<Buffer> {
    const response = await fetch(url, {
      headers: { "Accept-Encoding": "gzip" }
    });
    return Buffer.from(await response.arrayBuffer());
  }

  private async parseProducts(buffer: Buffer): Promise<RawProduct[]> {
    const content = buffer.toString("utf-8");
    const lines = content.split("\n").filter(Boolean);
    const headers = lines[0].split(";");

    return lines.slice(1).map(line => {
      const values = line.split(";");
      return headers.reduce((obj, header, i) => {
        obj[header.trim()] = values[i]?.trim() || "";
        return obj;
      }, {} as Record<string, string>);
    });
  }

  private async loadMappings(shopId: string): Promise<CategoryMapping[]> {
    if (this.mappingCache.has(shopId)) {
      return this.mappingCache.get(shopId)!;
    }

    const rules = await prisma.mappingRule.findMany({
      where: { shopId },
      orderBy: { priority: "desc" }
    });

    const compiled = rules.map(rule => ({
      pattern: new RegExp(rule.sourcePattern, "i"),
      targetPath: rule.targetPath as string[],
      priority: rule.priority
    }));

    this.mappingCache.set(shopId, compiled);
    return compiled;
  }

  private applyMapping(product: RawProduct, mappings: CategoryMapping[]): string[] {
    const sourcePath = product.categoryPath || product.category || "";

    for (const mapping of mappings) {
      if (mapping.pattern.test(sourcePath)) {
        return mapping.targetPath;
      }
    }

    return this.inferCategory(product);
  }

  private inferCategory(product: RawProduct): string[] {
    const title = product.title.toLowerCase();
    const categories = [
      { keywords: ["laptop", "notebook", "computer"], path: ["Elektronik", "Computer"] },
      { keywords: ["smartphone", "handy", "iphone"], path: ["Elektronik", "Smartphones"] },
      { keywords: ["fernseher", "tv", "monitor"], path: ["Elektronik", "TV & Audio"] },
      { keywords: ["kopfhörer", "headphone", "earbuds"], path: ["Elektronik", "Audio"] },
      { keywords: ["jacke", "mantel", "coat"], path: ["Mode", "Oberbekleidung"] },
      { keywords: ["schuh", "sneaker", "boot"], path: ["Mode", "Schuhe"] },
      { keywords: ["sofa", "couch", "sessel"], path: ["Wohnen", "Möbel"] }
    ];

    for (const cat of categories) {
      if (cat.keywords.some(kw => title.includes(kw))) {
        return cat.path;
      }
    }

    return ["Allgemein"];
  }

  private generateHash(product: RawProduct): string {
    const data = [product.ean, product.title, product.price].join("|");
    return createHash("sha256").update(data).digest("hex").slice(0, 32);
  }

  private calculateDiscount(product: RawProduct): number {
    const price = this.parsePrice(product.price);
    const original = this.parsePrice(product.originalPrice);

    if (!original || original <= price) return 0;
    return Math.round(((original - price) / original) * 100);
  }

  private parsePrice(value: string | number): number {
    if (typeof value === "number") return value;
    const cleaned = value.replace(/[^\d.,]/g, "").replace(",", ".");
    return parseFloat(cleaned) || 0;
  }

  private sanitizeText(text: string): string {
    return text
      .replace(/<[^>]*>/g, "")
      .replace(/\s+/g, " ")
      .trim()
      .slice(0, 2000);
  }

  private async upsertDeals(shopId: string, deals: Deal[]): Promise<void> {
    await prisma.$transaction([
      prisma.deal.updateMany({
        where: { shopId },
        data: { isActive: false }
      }),
      ...deals.map(deal =>
        prisma.deal.upsert({
          where: { hash: deal.hash },
          create: deal,
          update: {
            price: deal.price,
            originalPrice: deal.originalPrice,
            discount: deal.discount,
            isActive: true,
            updatedAt: new Date()
          }
        })
      )
    ]);
  }

  private async syncToSearchIndex(deals: Deal[]): Promise<void> {
    const operations = deals.flatMap(deal => [
      { index: { _index: "deals", _id: deal.id } },
      {
        id: deal.id,
        title: deal.title,
        description: deal.description,
        price: deal.price,
        originalPrice: deal.originalPrice,
        discount: deal.discount,
        category: deal.category,
        brand: deal.brand,
        imageUrl: deal.imageUrl,
        shopId: deal.shopId,
        isActive: deal.isActive,
        createdAt: deal.createdAt,
        suggest: { input: [deal.title, deal.brand].filter(Boolean) }
      }
    ]);

    await searchClient.bulk({ body: operations, refresh: true });
  }
}

class SearchService {
  async search(query: z.infer<typeof SearchQuerySchema>): Promise<SearchResult> {
    const { q, category, brand, minPrice, maxPrice, sort, page, limit } = query;

    const must: RequestParams.Search["body"]["query"]["bool"]["must"] = [
      {
        multi_match: {
          query: q,
          fields: ["title^3", "description", "brand^2"],
          type: "best_fields",
          fuzziness: "AUTO"
        }
      }
    ];

    const filter: RequestParams.Search["body"]["query"]["bool"]["filter"] = [
      { term: { isActive: true } }
    ];

    if (category) {
      filter.push({ term: { "category.keyword": category } });
    }

    if (brand) {
      filter.push({ term: { "brand.keyword": brand } });
    }

    if (minPrice !== undefined || maxPrice !== undefined) {
      filter.push({
        range: {
          price: {
            ...(minPrice !== undefined && { gte: minPrice }),
            ...(maxPrice !== undefined && { lte: maxPrice })
          }
        }
      });
    }

    const sortConfig = {
      price: [{ price: { order: "asc" } }],
      discount: [{ discount: { order: "desc" } }],
      relevance: [{ _score: { order: "desc" } }]
    };

    const response = await searchClient.search({
      index: "deals",
      body: {
        from: (page - 1) * limit,
        size: limit,
        query: { bool: { must, filter } },
        sort: sortConfig[sort],
        aggs: {
          categories: {
            terms: { field: "category.keyword", size: 50 }
          },
          brands: {
            terms: { field: "brand.keyword", size: 30 }
          },
          priceStats: {
            stats: { field: "price" }
          },
          discountRanges: {
            range: {
              field: "discount",
              ranges: [
                { key: "10-25%", from: 10, to: 25 },
                { key: "25-50%", from: 25, to: 50 },
                { key: "50%+", from: 50 }
              ]
            }
          }
        },
        highlight: {
          fields: {
            title: { number_of_fragments: 0 },
            description: { fragment_size: 150, number_of_fragments: 3 }
          }
        }
      }
    });

    const { hits, aggregations } = response.body;

    return {
      hits: hits.hits.map((hit: any) => ({
        ...hit._source,
        score: hit._score,
        highlight: hit.highlight
      })),
      total: hits.total.value,
      aggregations,
      page,
      totalPages: Math.ceil(hits.total.value / limit)
    };
  }

  async suggest(prefix: string): Promise<string[]> {
    const response = await searchClient.search({
      index: "deals",
      body: {
        suggest: {
          titleSuggest: {
            prefix,
            completion: {
              field: "suggest",
              size: 10,
              skip_duplicates: true
            }
          }
        }
      }
    });

    return response.body.suggest.titleSuggest[0].options.map(
      (opt: any) => opt.text
    );
  }
}

class PriceAlertService {
  async checkAlerts(): Promise<number> {
    const alerts = await prisma.priceAlert.findMany({
      where: {
        isActive: true,
        deal: { isActive: true }
      },
      include: {
        deal: true,
        user: { select: { email: true, name: true } }
      }
    });

    let triggered = 0;

    for (const alert of alerts) {
      if (alert.deal.price <= alert.targetPrice) {
        await this.sendNotification(alert);
        await prisma.priceAlert.update({
          where: { id: alert.id },
          data: { isActive: false, triggeredAt: new Date() }
        });
        triggered++;
      }
    }

    return triggered;
  }

  private async sendNotification(alert: PriceAlert & { deal: Deal; user: { email: string; name: string } }): Promise<void> {
    const discount = Math.round(((alert.targetPrice - alert.deal.price) / alert.targetPrice) * 100);

    await sendEmail({
      to: alert.user.email,
      subject: `Preisalarm: ${alert.deal.title}`,
      template: "price-alert",
      data: {
        userName: alert.user.name,
        dealTitle: alert.deal.title,
        currentPrice: alert.deal.price,
        targetPrice: alert.targetPrice,
        discount,
        dealUrl: `${process.env.BASE_URL}/deal/${alert.deal.id}`
      }
    });
  }
}

router.get("/search", async (req: Request, res: Response, next: NextFunction) => {
  try {
    const query = SearchQuerySchema.parse(req.query);
    const searchService = new SearchService();
    const results = await searchService.search(query);
    res.json(results);
  } catch (error) {
    next(error);
  }
});

router.get("/suggest", async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { q } = req.query;
    if (typeof q !== "string" || q.length < 2) {
      return res.json([]);
    }
    const searchService = new SearchService();
    const suggestions = await searchService.suggest(q);
    res.json(suggestions);
  } catch (error) {
    next(error);
  }
});

router.get("/deal/:id", async (req: Request, res: Response, next: NextFunction) => {
  try {
    const deal = await prisma.deal.findUnique({
      where: { id: req.params.id },
      include: {
        shop: { select: { name: true, logoUrl: true } },
        priceHistory: {
          orderBy: { recordedAt: "desc" },
          take: 30
        }
      }
    });

    if (!deal) {
      return res.status(404).json({ error: "Deal not found" });
    }

    res.json(deal);
  } catch (error) {
    next(error);
  }
});

router.post("/alerts", async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { dealId, targetPrice } = req.body;
    const userId = req.user?.id;

    if (!userId) {
      return res.status(401).json({ error: "Authentication required" });
    }

    const alert = await prisma.priceAlert.create({
      data: {
        userId,
        dealId,
        targetPrice,
        isActive: true
      }
    });

    res.status(201).json(alert);
  } catch (error) {
    next(error);
  }
});

export { router, DealAggregationService, SearchService, PriceAlertService };
Full-Stack Entwicklung

Web Development & Server-Infrastruktur

Eigene Hetzner-Infrastruktur mit 61 GB RAM und 16 CPU-Kernen. Drei produktive Systeme im Dauerbetrieb, überwacht von automatischen Watchdogs mit Telegram-Alerting.

Frontend

Next.js 14 React 18 TailwindCSS TypeScript

Backend

Express 5.2 Node.js 24 LTS Prisma ORM TypeScript

Datenbank

Postgres 16 OpenSearch 3.5 Redis Cache

Infrastruktur

Hetzner Dedicated Ubuntu 22.04 Docker Apache 2.4

Server-Sicherheit

Gehärteter Dedicated Server mit WAF, VPN-Tunnel und automatischer Angriffserkennung.

UFW Firewall Fail2Ban WireGuard VPN ModSecurity

SSL & Verschlüsselung

Automatische Zertifikatsverwaltung und sichere Verbindungen.

Let's Encrypt Auto-Renewal HTTPS-Only

Prozess-Management

PM2 steuert drei Backends, 20+ Cron-Jobs orchestrieren alle Pipelines mit Lock-Files.

PM2 Cluster Log Rotation 20+ Cron Jobs Lock-Files

KI & Machine Learning

Eigener KI-Chatbot mit lokalem LLM, intelligente Content-Systeme und KI-gestützte Bildgenerierung.

Ollama LLM OpenAI GPT Replicate

API-Integrationen

AWIN, eBay Partner Network, OpenAI, Replicate, Telegram Bot API – alles angebunden.

AWIN eBay Partner OpenAI Replicate Telegram Bot

Vollautomatisierung

Wiki-Artikel, Creator-Videos, Gutscheine und Newsletters – alles vollautomatisch.

Content Machine IMAP Parser Auto-Sync

Monitoring & Alerting

Drei Watchdogs prüfen alle 5 Minuten. Bei Ausfällen: sofortiger Telegram-Alert.

Service Watchdog Load Watchdog Telegram Bot IPv4/IPv6 Check

DSGVO & Datenschutz

Keine Google-Dienste. Matomo läuft selbst gehostet, Schriften lokal, Consent sauber gelöst.

Matomo Analytics Consent Center Lokale Fonts 2-Klick Videos

E-Mail & DNS

Professionelle Mail-Zustellung mit Postfix-Relay und vollständiger DNS-Authentifizierung.

SPF DKIM DMARC Postfix Relay
3D-Druck Technologie
26.559
3D-Druck Produkte
118
Kategorien
12
Autonome Subsysteme
487
Wiki-Fachartikel
system-architecture.ts
const stack = {
  ai: ["Ollama", "OpenAI", "Replicate"],
  backend: "Express 5.2 + Prisma 7",
  database: "Postgres + SQLite",
  search: "OpenSearch",
  apis: ["AWIN", "eBay", "Telegram"],
  content: "KI-gestützte Redaktion",
  chatbot: "Ollama llama3.2",
  creators: 74,
  wiki: 487
};
Multi-System Architektur

Vollautomatisiertes 3D-Druck Portal

3dausdu.de

So sieht es aus, wenn wir ein Fachportal von Null aufbauen: Über 26.000 Produkte in 118 Kategorien, ein eigener KI-Chatbot, der Produkte empfiehlt und gleichzeitig auf ein Wiki mit 487 Fachartikeln zugreift, ein Creator Hub, der YouTube-Videos von 74 Creatorn automatisch mit passenden Produkten verknüpft, und exklusive Gutschein-Codes für die Community. Drei Affiliate-Pipelines halten alles aktuell – ohne manuellen Eingriff. Das ist die Art System, die wir bauen.

KI-Chatbot (Ollama)
487 Fachartikel im Wiki
Creator Hub (74 YouTuber)
Gutschein-System
3 Affiliate-Pipelines
Newsletter per IMAP
Node.js Express 5.2 Prisma ORM OpenSearch PHP + Tailwind AWIN API
Affiliate Marketing Daten Dashboard
Unsere Kernkompetenz

Affiliate-Systeme auf Enterprise-Level

Die meisten Affiliate-Seiten sind WordPress-Installationen mit ein paar Plugins. Wir bauen maßgeschneiderte Plattformen mit Suchtechnologie, KI-Integration und Echtzeit-Daten – ausgelegt für Millionen von Produkten.

VERALTET

Typisches Affiliate-Setup

WordPress + Plugins, ein Affiliate-Netzwerk
MySQL-Suche mit starren Keywords, keine Relevanz-Sortierung
Statische Preise, kein Tracking, keine Preisverlaufsdaten
Manuelles Einpflegen von Produkten und Gutscheinen
Ab 5.000 Produkten wird alles langsam
Plugin-Abhängigkeiten, Ladezeiten 3–5 Sekunden
UNSER LEVEL

Was wir stattdessen bauen

Custom-Stack mit drei parallelen Netzwerk-Pipelines
Semantische Suche mit OpenSearch 3.5 – versteht Absichten, nicht nur Wörter
Historische Preischarts auf jeder Deal-Karte
KI-Chatbot mit Produktwissen und Fachartikeln im Hintergrund
Über 4,6 Millionen Produkte, unter 50ms Antwortzeit
Null Plugin-Schulden, null Abhängigkeiten, volle Kontrolle

Semantische Produktsuche

OpenSearch 3.5 mit Neural Search versteht, was Nutzer meinen – nicht nur was sie tippen. Wer „leiser Einsteiger-Drucker“ sucht, bekommt relevante Ergebnisse. Über 4,6 Millionen Produkte in unter 50 Millisekunden.

Echtzeit-Preisintelligenz

Historische Preischarts zeigen Nutzern sofort, ob ein Angebot wirklich gut ist. Das schafft Vertrauen – und Vertrauen konvertiert. Kein WordPress-Plugin trackt Preise über Millionen von Produkten.

Drei Netzwerke, null Abhängigkeit

AWIN, eBay und Custom Feeds laufen parallel. 14.500+ Shops, 852 Mapping-Regeln für präzise Kategorisierung. Kürzt ein Netzwerk die Provisionen, läuft das System trotzdem weiter.

KI-Chatbot mit Fachwissen

Kein generisches Chat-Fenster. Unser Chatbot kennt jedes Produkt und jeden Fachartikel im System – und berät Nutzer so, wie es ein erfahrener Fachverkäufer tun würde. Rund um die Uhr, ohne Warteschleife.

Creator-zu-Produkt-Matching

YouTube-Videos werden automatisch mit passenden Produkten verknüpft. Creator liefern authentische Reviews, das System matcht sie – Nutzer finden Content und Produkt an einem Ort.

DSGVO als Architekturprinzip

Kein WordPress, keine Plugin-Schulden. Selbst gehostetes Tracking, lokale Schriften, granulares Consent-Center. Datenschutz ist kein nachträglicher Patch – sondern Fundament.

Das ist der Unterschied zwischen einer Nischenseite und einer Produktdaten-Plattform.

Wenn Sie ein Affiliate-System brauchen, das über WordPress hinausgeht – sprechen Sie mit uns.

Projekt besprechen

Interesse an Zusammenarbeit?

Komplexe Systeme, die einfach funktionieren. Lassen Sie uns über Ihr Projekt sprechen.

Kontakt aufnehmen