8.4 KiB
Launch Plan – dgray.io
Release-Phasen
| Phase | Preis pro Anzeige | Dauer | Zugang |
|---|---|---|---|
| Closed Alpha | 0,01 € / 0,01 USD / 0,01 CHF | 4–6 Wochen | Nur mit Invite-Code |
| Open Beta | 0,10 € / 0,10 USD / 0,10 CHF | 3 Monate | Öffentlich, Beta-Banner |
| Launch | 1 € / 1 USD / 1 CHF | Dauerhaft | Öffentlich |
Pricing-Philosophie: Die Zahl 1 als magische Zahl — einfach, einprägsam, international gleich.
1 listing = 1 month = 1
Phase 1: Closed Alpha
Ziel
- Feedback von Crypto/Privacy-Enthusiasten
- Payment-Flow testen (1 Cent = echte Transaktion, minimale Kosten)
- Bugs finden, UX validieren
Invite-Code System
Directus: Collection invite_codes
| Feld | Typ | Hinweise |
|---|---|---|
id |
UUID (auto) | Primary Key |
code |
String, unique | z.B. ALPHA-XMR-2026 |
max_uses |
Integer | Max. Einlösungen (0 = unbegrenzt) |
used_count |
Integer, default 0 | Aktuelle Einlösungen |
expires_at |
DateTime, nullable | Optional: Ablaufdatum |
status |
String, default active |
active / disabled |
date_created |
Timestamp (auto) |
Directus: Permissions für invite_codes
| Rolle | Read | Create | Update |
|---|---|---|---|
| Public | Nein | Nein | Nein |
| Admin | Ja | Ja | Ja |
Die Validierung passiert serverseitig im PoW-Server (PHP), nicht im Frontend.
PHP: Invite-Code Validierung
Neuer Endpoint: POST /invite/validate
// pow.dgray.io/invite/validate.php
<?php
require __DIR__ . '/config.php';
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://dgray.io');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { exit; }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$code = trim($input['code'] ?? '');
if (!$code) {
http_response_code(400);
echo json_encode(['valid' => false, 'error' => 'Missing invite code']);
exit;
}
// Query Directus for invite code
$url = DIRECTUS_URL . '/items/invite_codes?filter[code][_eq]=' . urlencode($code)
. '&filter[status][_eq]=active&limit=1';
$context = stream_context_create([
'http' => [
'header' => "Authorization: Bearer " . DIRECTUS_TOKEN . "\r\n",
'ignore_errors' => true,
],
]);
$response = file_get_contents($url, false, $context);
$data = json_decode($response, true);
$invite = $data['data'][0] ?? null;
if (!$invite) {
echo json_encode(['valid' => false, 'error' => 'Invalid or expired invite code']);
exit;
}
// Check max uses
if ($invite['max_uses'] > 0 && $invite['used_count'] >= $invite['max_uses']) {
echo json_encode(['valid' => false, 'error' => 'Invite code fully redeemed']);
exit;
}
// Check expiry
if ($invite['expires_at'] && strtotime($invite['expires_at']) < time()) {
echo json_encode(['valid' => false, 'error' => 'Invite code expired']);
exit;
}
// Increment used_count
$updateUrl = DIRECTUS_URL . '/items/invite_codes/' . $invite['id'];
$updateContext = stream_context_create([
'http' => [
'method' => 'PATCH',
'header' => "Content-Type: application/json\r\nAuthorization: Bearer " . DIRECTUS_TOKEN . "\r\n",
'content' => json_encode(['used_count' => $invite['used_count'] + 1]),
'ignore_errors' => true,
],
]);
file_get_contents($updateUrl, false, $updateContext);
echo json_encode(['valid' => true]);
Frontend: Invite-Code bei Registrierung
In js/components/auth-modal.js — im Registrierungs-Flow ein Textfeld hinzufügen:
[Invite Code: _________ ] ← nur in Alpha-Phase sichtbar
[UUID generieren]
Vor createAccount() den Code serverseitig validieren:
const res = await fetch('https://pow.dgray.io/invite/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code: inviteCode })
})
const { valid, error } = await res.json()
if (!valid) { /* Fehlermeldung anzeigen */ return }
Feature-Flag
In config.php ein Flag, um Alpha-Modus zu steuern:
define('REQUIRE_INVITE_CODE', true); // false für Open Beta / Launch
Im Invoice-Endpoint kann optional der Invite-Code mitgesendet werden, um Alpha-User zu tracken.
Pricing-Änderung für Alpha
In docs/pow-server/config.php:
// Alpha: 1 Cent
define('LISTING_FEE', ['EUR' => 0.01, 'USD' => 0.01, 'CHF' => 0.01, 'GBP' => 0.01, 'JPY' => 2]);
Verteilung der Invite-Codes
- Manuell in Directus erstellen (Admin-Panel)
- Verteilen über:
- r/Monero, r/privacy
- Monero Matrix/IRC Channels
- Persönliche Kontakte
- 10–20 Codes mit je 5–10 max_uses → 50–200 Alpha-Tester
Phase 2: Open Beta
Änderungen
- Pricing:
config.php→LISTING_FEEauf 0,10 setzen - Invite-Code:
REQUIRE_INVITE_CODE→false - Beta-Banner: Hinweis auf der Seite ("Beta — Feedback willkommen")
- Feedback-Kanal: Link zu Matrix-Raum oder einfaches Kontaktformular
Marketing
- Show HN Post auf Hacker News
- r/Monero, r/privacy, r/degoogle — organische Posts
- Privacy-Newsletter (PrivacyGuides, Techlore)
- Monero-Community (Matrix, IRC)
Metriken tracken
- Anzahl Registrierungen
- Anzahl veröffentlichter Anzeigen
- Payment Completion Rate
- Chat-Nutzung (nur Anzahl, nicht Inhalt)
Phase 3: Launch
Änderungen
- Pricing:
config.php→LISTING_FEEauf 1 setzen (bereits Standard) - Beta-Banner entfernen
- Invite-Code-System kann aktiv bleiben (für spätere Promo-Codes nutzbar)
Kommunikation
"1 listing = 1 month = 1" — so simpel wie möglich.
Meta-Tags (pro Sprache)
Die statischen Meta-Tags in index.html sind deutsch (Fallback).
Der OG-Proxy (pow.dgray.io/og-proxy.php) liefert Listing-spezifische Tags.
Umgesetzte Texte
Title: dgray.io – [Sprache]
| Sprache | Title | Description |
|---|---|---|
| de | dgray.io – Anonyme Kleinanzeigen | Kaufen und verkaufen ohne Konto, ohne E-Mail. Bezahlung mit Monero. Ende-zu-Ende verschlüsselter Chat. |
| en | dgray.io – Private Classifieds | Buy and sell without an account, without email. Pay with Monero. End-to-end encrypted chat. |
| fr | dgray.io – Petites annonces anonymes | Achetez et vendez sans compte, sans e-mail. Paiement en Monero. Chat chiffré de bout en bout. |
| it | dgray.io – Annunci anonimi | Compra e vendi senza account, senza email. Pagamento in Monero. Chat crittografata end-to-end. |
| es | dgray.io – Clasificados anónimos | Compra y vende sin cuenta, sin email. Pago con Monero. Chat cifrado de extremo a extremo. |
| pt | dgray.io – Classificados anônimos | Compre e venda sem conta, sem email. Pagamento com Monero. Chat criptografado ponta a ponta. |
| ru | dgray.io – Анонимные объявления | Покупайте и продавайте без аккаунта, без email. Оплата Monero. Сквозное шифрование чата. |
Umsetzung
Die index.html enthält die Standard-Meta-Tags (de).
Für sprachspezifische OG-Tags bei Social-Media-Shares:
Der OG-Proxy kann um einen ?lang= Parameter erweitert werden.
Die i18n.js updateDOM() Methode aktualisiert document.title, og:title/description
und twitter:title/description dynamisch bei jedem Sprachwechsel (i18n-Keys meta.title, meta.description).
Checkliste vor Alpha-Start
- Directus: Collection
invite_codesanlegen (Schema siehe oben) - PHP:
invite/validate.phpdeployen aufpow.dgray.io - PHP:
config.php→LISTING_FEEauf 0.01 setzen - PHP:
config.php→REQUIRE_INVITE_CODE = true - Frontend: Invite-Code-Feld in
auth-modal.jseinbauen - Frontend: Meta-Description i18n-Keys in alle 7 Sprachen
- Frontend: Impressum-Seite (Entwurf, alle 7 Sprachen, Platzhalter für Adressdaten)
- Frontend: Datenschutz, AGB, Über uns — alle 7 Sprachen
- Rechtliches: Impressum-Platzhalter ausfüllen (Name, Adresse, UID)
- Rechtliches: AGB + Datenschutz durch Fachperson prüfen lassen
- Rechtliches: Gewerbeanmeldung / Einzelunternehmen
- 10–20 Invite-Codes in Directus erstellen
- Codes verteilen (r/Monero, Matrix, persönlich)
- Feedback-Kanal einrichten (Matrix-Raum)