389 lines
15 KiB
Markdown
389 lines
15 KiB
Markdown
# 💋 sexy.pivoine.art
|
||
|
||
<div align="center">
|
||
|
||

|
||
|
||
_"Lust und Liebe gehören zusammen - wer das eine verteufelt, zerstört auch das andere."_
|
||
— **Beate Uhse**, Pionierin der sexuellen Befreiung ✈️
|
||
|
||
---
|
||
|
||
### 🍆 An Intimate Platform for Liberation & Pleasure 🍆
|
||
|
||
Built with passion, technology, and the fearless spirit of sexual empowerment
|
||
|
||
[](https://dev.pivoine.art/valknar/sexy/actions)
|
||
[](https://dev.pivoine.art/valknar/sexy/actions)
|
||
[](LICENSE)
|
||
[](https://sexy.pivoine.art)
|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
## 👅 What Is This Delicious Creation?
|
||
|
||
Welcome, dear pleasure-seeker! This is **sexy.pivoine.art** — a modern, sensual platform built from the ground up with full control over every intimate detail. A **SvelteKit** frontend caresses a purpose-built **Fastify + GraphQL** backend, while **Buttplug.io** hardware integration brings the experience into the physical world.
|
||
|
||
Like Beate Uhse breaking barriers in post-war Germany, we believe in the freedom to explore, create, and celebrate sexuality without shame. This platform is built for **models**, **creators**, and **connoisseurs** of adult content who deserve technology as sophisticated as their desires.
|
||
|
||
### ♉ Features That'll Make You Blush ♊
|
||
|
||
- 💖 **Sensual SvelteKit Frontend** with Tailwind CSS 4 styling
|
||
- ⚡ **Purpose-built GraphQL Backend** — lean, fast, no CMS overhead
|
||
- 🔐 **Session-based Auth** with Redis & Argon2 — discretion guaranteed
|
||
- 🖼️ **Smart Image Transforms** via Sharp (WebP, multiple presets, cached)
|
||
- 🎮 **Hardware Integration** via Buttplug.io (yes, really!)
|
||
- 📱 **Responsive Design** that looks sexy on any device
|
||
- 🌍 **Internationalization** — pleasure speaks all languages
|
||
- 🏆 **Gamification** — achievements, leaderboards, and reward points
|
||
- 💬 **Comments & Social** — build your community
|
||
- 📊 **Analytics Integration** (Umami) — know your admirers
|
||
- 🐳 **Self-hosted CI/CD** via Gitea Actions on `dev.pivoine.art`
|
||
|
||
<div align="center">
|
||
|
||
### 🍑 Technology Stack 🍑
|
||
|
||
</div>
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 💋 Frontend Layer │
|
||
│ ├─ SvelteKit 2 → Smooth as silk │
|
||
│ ├─ Tailwind CSS 4 → Styled to seduce │
|
||
│ ├─ bits-ui Components → Building blocks of pleasure │
|
||
│ ├─ graphql-request v7 → Whispering to the backend │
|
||
│ └─ Vite → Fast and furious │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 🍷 Backend Layer │
|
||
│ ├─ Fastify v5 → The fastest penetration │
|
||
│ ├─ GraphQL Yoga v5 → Flexible positions │
|
||
│ ├─ Pothos (code-first) → Schema with intention │
|
||
│ ├─ Drizzle ORM → Data with grace │
|
||
│ ├─ PostgreSQL 16 → Deep and persistent │
|
||
│ ├─ Redis → Sessions that never forget │
|
||
│ ├─ Sharp → Images transformed beautifully │
|
||
│ └─ Argon2 → Passwords hashed with passion │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 🎀 Hardware Layer │
|
||
│ ├─ Buttplug.io → Real connections │
|
||
│ ├─ TypeScript + Rust → Power and precision │
|
||
│ └─ WebBluetooth API → Wireless intimacy │
|
||
├─────────────────────────────────────────────────────────────┤
|
||
│ 🌸 DevOps Layer │
|
||
│ ├─ Docker → Containerized ecstasy │
|
||
│ ├─ Gitea Actions → Self-hosted seduction │
|
||
│ └─ dev.pivoine.art → Our own pleasure palace │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 🔥 Quick Start — Get Intimate Fast
|
||
|
||
### 💕 Option 1: Using Docker Compose (Recommended)
|
||
|
||
```bash
|
||
# Clone the repository
|
||
git clone https://dev.pivoine.art/valknar/sexy.git
|
||
cd sexy.pivoine.art
|
||
|
||
# Configure your secrets
|
||
cp .env.example .env
|
||
# Edit .env with your intimate details
|
||
|
||
# Awaken all services (postgres, redis, backend, frontend)
|
||
docker compose up -d
|
||
|
||
# Visit your creation at http://localhost:3000 💋
|
||
```
|
||
|
||
### 💜 Option 2: Local Development
|
||
|
||
**Prerequisites:**
|
||
|
||
1. Node.js 20.19.1 — _the foundation_
|
||
2. `corepack enable` — _unlock the tools_
|
||
3. `pnpm install` — _gather your ingredients_
|
||
4. PostgreSQL 16 + Redis — _the data lovers_
|
||
|
||
**Start your pleasure journey:**
|
||
|
||
```bash
|
||
# Awaken data services
|
||
pnpm dev:data
|
||
|
||
# Start the backend (port 4000)
|
||
pnpm dev:backend
|
||
|
||
# Start the frontend (port 3000, proxied to :4000)
|
||
pnpm --filter @sexy.pivoine.art/frontend dev
|
||
```
|
||
|
||
Visit `http://localhost:3000` and let the experience begin... 💋
|
||
|
||
GraphQL playground is available at `http://localhost:4000/graphql` — explore every query.
|
||
|
||
---
|
||
|
||
## 🌹 Project Structure
|
||
|
||
This monorepo contains three packages, each serving its purpose:
|
||
|
||
```
|
||
sexy.pivoine.art/
|
||
├─ 💄 packages/frontend/ → SvelteKit app (the seduction)
|
||
├─ ⚡ packages/backend/ → Fastify + GraphQL API (the engine)
|
||
└─ 🎮 packages/buttplug/ → Hardware control (the connection)
|
||
```
|
||
|
||
### 💄 Frontend (`packages/frontend/`)
|
||
|
||
SvelteKit 2 application with server-side rendering, i18n, and a clean component library.
|
||
Communicates with the backend exclusively via GraphQL using `graphql-request`.
|
||
Assets served via `/api/assets/:id?transform=<preset>` — no CDN, no Directus, just raw power.
|
||
|
||
### ⚡ Backend (`packages/backend/`)
|
||
|
||
Purpose-built Fastify v5 + GraphQL Yoga server. All business logic lives here:
|
||
auth, file uploads, video processing, comments, gamification, and analytics.
|
||
Files stored as `<UPLOAD_DIR>/<uuid>/<filename>` with on-demand WebP transforms cached on disk.
|
||
|
||
### 🎮 Buttplug (`packages/buttplug/`)
|
||
|
||
Hybrid TypeScript/Rust package for intimate hardware control via WebBluetooth.
|
||
Compiled to WebAssembly for browser-based Bluetooth device communication.
|
||
|
||
---
|
||
|
||
## 🗃️ Database Schema
|
||
|
||
Built with Drizzle ORM — clean tables, no `directus_` prefix, full control:
|
||
|
||
```
|
||
users → profiles, roles (model/viewer/admin), auth tokens
|
||
files → uploaded assets with metadata and duration
|
||
videos → content with model junctions, likes, plays
|
||
articles → magazine / editorial content
|
||
recordings → user-created content with play tracking
|
||
comments → threaded by collection + item_id
|
||
achievements → gamification goals
|
||
user_points → points ledger
|
||
user_stats → cached leaderboard data
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 Authentication Flow
|
||
|
||
```
|
||
POST /graphql (login mutation)
|
||
→ verify argon2 password hash
|
||
→ nanoid(32) session token
|
||
→ SET session:<token> <user JSON> EX 86400 in Redis
|
||
→ set httpOnly cookie: session_token
|
||
→ return CurrentUser
|
||
|
||
Every request:
|
||
→ read session_token cookie
|
||
→ GET session:<token> from Redis
|
||
→ inject currentUser into GraphQL context
|
||
```
|
||
|
||
---
|
||
|
||
## 🖼️ Image Transforms
|
||
|
||
Assets are transformed on first request and cached as WebP:
|
||
|
||
| Preset | Size | Fit | Use |
|
||
| ----------- | ----------- | ------ | ---------------- |
|
||
| `mini` | 80×80 | cover | Avatars in lists |
|
||
| `thumbnail` | 300×300 | cover | Profile photos |
|
||
| `preview` | 800px wide | inside | Video teasers |
|
||
| `medium` | 1400px wide | inside | Full-size images |
|
||
| `banner` | 1600×480 | cover | Profile banners |
|
||
|
||
---
|
||
|
||
## 🚀 Deployment
|
||
|
||
### Production with Docker Compose
|
||
|
||
```bash
|
||
# Configure your secrets
|
||
cp .env.example .env.production
|
||
# Edit .env.production — set DB credentials, SMTP, cookie secret, CORS origin
|
||
|
||
# Deploy
|
||
docker compose --env-file .env.production up -d
|
||
```
|
||
|
||
Key environment variables for the backend:
|
||
|
||
```env
|
||
DATABASE_URL=postgresql://sexy:sexy@postgres:5432/sexy
|
||
REDIS_URL=redis://redis:6379
|
||
COOKIE_SECRET=your-very-secret-key
|
||
CORS_ORIGIN=https://sexy.pivoine.art
|
||
UPLOAD_DIR=/data/uploads
|
||
SMTP_HOST=your.smtp.host
|
||
SMTP_PORT=587
|
||
EMAIL_FROM=noreply@sexy.pivoine.art
|
||
PUBLIC_URL=https://sexy.pivoine.art
|
||
```
|
||
|
||
### 🎬 CI/CD — Self-Hosted Seduction
|
||
|
||
Automated builds run on **[dev.pivoine.art](https://dev.pivoine.art/valknar/sexy)** via Gitea Actions:
|
||
|
||
- ✅ Frontend image → `dev.pivoine.art/valknar/sexy:latest`
|
||
- ✅ Backend image → `dev.pivoine.art/valknar/sexy-backend:latest`
|
||
- ✅ Triggers on push to `main`, `develop`, or version tags (`v*.*.*`)
|
||
- ✅ Build cache via registry for fast successive builds
|
||
|
||
Images are pulled on the production server via Watchtower or manual `docker compose pull && docker compose up -d`.
|
||
|
||
---
|
||
|
||
## 🎭 Development Workflow
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[💡 Idea] --> B[💻 Code]
|
||
B --> C[🧪 Test Locally]
|
||
C --> D[🌿 Feature Branch]
|
||
D --> E[📤 Push to dev.pivoine.art]
|
||
E --> F{✅ Build Pass?}
|
||
F -->|Yes| G[🔀 Merge to Main]
|
||
F -->|No| B
|
||
G --> H[🚀 Images Built & Pushed]
|
||
H --> I[🎉 Deploy to Production]
|
||
```
|
||
|
||
1. Create → `git checkout -b feature/my-sexy-feature`
|
||
2. Develop → Write beautiful code
|
||
3. Test → `pnpm dev:data && pnpm dev:backend && pnpm dev`
|
||
4. Push → `git push` to `dev.pivoine.art` (triggers CI build)
|
||
5. Merge → Images published, deploy to production
|
||
6. Release → `git tag v1.0.0 && git push origin v1.0.0`
|
||
|
||
---
|
||
|
||
## 🌈 Environment Variables
|
||
|
||
### Backend (required)
|
||
|
||
| Variable | Description |
|
||
| --------------- | ----------------------------- |
|
||
| `DATABASE_URL` | PostgreSQL connection string |
|
||
| `REDIS_URL` | Redis connection string |
|
||
| `COOKIE_SECRET` | Session cookie signing secret |
|
||
| `CORS_ORIGIN` | Allowed frontend origin |
|
||
| `UPLOAD_DIR` | Path for uploaded files |
|
||
|
||
### Backend (optional)
|
||
|
||
| Variable | Default | Description |
|
||
| ------------ | ------- | ------------------------------ |
|
||
| `PORT` | `4000` | Backend listen port |
|
||
| `LOG_LEVEL` | `info` | Fastify log level |
|
||
| `SMTP_HOST` | — | Email server for auth flows |
|
||
| `SMTP_PORT` | `587` | Email server port |
|
||
| `EMAIL_FROM` | — | Sender address |
|
||
| `PUBLIC_URL` | — | Frontend URL (for email links) |
|
||
|
||
### Frontend
|
||
|
||
| Variable | Description |
|
||
| --------------------- | --------------------------------------------- |
|
||
| `PUBLIC_API_URL` | Backend URL (e.g. `http://sexy_backend:4000`) |
|
||
| `PUBLIC_URL` | Frontend public URL |
|
||
| `PUBLIC_UMAMI_ID` | Umami analytics site ID (optional) |
|
||
| `PUBLIC_UMAMI_SCRIPT` | Umami script URL (optional) |
|
||
|
||
---
|
||
|
||
## 💌 Credits & Acknowledgments
|
||
|
||
<div align="center">
|
||
|
||
### 🌸 Created with Love by 🌸
|
||
|
||
**[Palina](https://sexy.pivoine.art) & [Valknar](https://sexy.pivoine.art)**
|
||
|
||
_Für die Mäuse..._ 🐭💕
|
||
|
||
---
|
||
|
||
### 🙏 Built With
|
||
|
||
| Technology | Purpose |
|
||
| --------------------------------------------------------- | -------------------- |
|
||
| [SvelteKit](https://kit.svelte.dev/) | Frontend framework |
|
||
| [Fastify](https://fastify.dev/) | HTTP server |
|
||
| [GraphQL Yoga](https://the-guild.dev/graphql/yoga-server) | GraphQL server |
|
||
| [Pothos](https://pothos-graphql.dev/) | Code-first schema |
|
||
| [Drizzle ORM](https://orm.drizzle.team/) | Database |
|
||
| [Sharp](https://sharp.pixelplumbing.com/) | Image transforms |
|
||
| [Buttplug.io](https://buttplug.io/) | Hardware |
|
||
| [bits-ui](https://www.bits-ui.com/) | UI components |
|
||
| [Gitea](https://dev.pivoine.art) | Self-hosted VCS & CI |
|
||
|
||
---
|
||
|
||
### 💐 Inspired by Beate Uhse
|
||
|
||
Pioneer of sexual liberation (1919-2001)
|
||
Pilot, Entrepreneur, Freedom Fighter
|
||
|
||
_"Eine Frau, die ihre Sexualität selbstbestimmt lebt, ist eine freie Frau."_
|
||
|
||

|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
## ⚖️ License & Legal
|
||
|
||
- 📜 See [LICENSE](LICENSE) file for details
|
||
- 🔞 **18+ Only** — This platform is for adults
|
||
- 🌍 Users must be of legal age in their jurisdiction
|
||
- ⚖️ We support equality, freedom, and consensual pleasure
|
||
|
||
---
|
||
|
||
## 💬 Support & Community
|
||
|
||
<div align="center">
|
||
|
||
[](https://dev.pivoine.art/valknar/sexy)
|
||
[](https://dev.pivoine.art/valknar/sexy/issues)
|
||
[](https://sexy.pivoine.art)
|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
<div align="center">
|
||
|
||
### 🍑 Made with 💜 for Freedom, Pleasure & Technology 🍑
|
||
|
||
<pre>
|
||
██████╗ ███████╗██╗ ██╗██╗ ██╗
|
||
██╔════╝ ██╔════╝╚██╗██╔╝╚██╗ ██╔╝
|
||
╚█████╗ █████╗ ╚███╔╝ ╚████╔╝
|
||
╚═══██╗ ██╔══╝ ██╔██╗ ╚██╔╝
|
||
██████╔╝ ███████╗██╔╝╚██╗ ██║
|
||
╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝
|
||
</pre>
|
||
|
||
_Pleasure is a human right. Technology is freedom. Together, they are power._
|
||
|
||
**[sexy.pivoine.art](https://sexy.pivoine.art)** | © 2025 Palina & Valknar
|
||
|
||
</div>
|