Initial commit: spreewaldzeit + Dockerfile for Coolify (Next.js + Prisma/SQLite)
This commit is contained in:
191
README.md
Normal file
191
README.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Spreewaldzeit — MVP
|
||||
|
||||
Private Ferienwohnungs-Website mit zwei Wohnungen. Ruhig, editorial, wartungsarm.
|
||||
Technik-Stack bewusst schlank gehalten — kein Hotel-PMS-Overhead, aber vorbereitet
|
||||
für spätere Erweiterungen (iCal-Sync, Direktbuchung, Zahlungsabwicklung).
|
||||
|
||||
## Tech-Stack
|
||||
|
||||
- **Next.js 14** (App Router, Server Components)
|
||||
- **TypeScript**, strict
|
||||
- **Prisma** + **SQLite** (einfach portierbar nach Postgres/MySQL)
|
||||
- **Tailwind CSS** mit eigener Naturpalette
|
||||
- **React Hook Form** + **Zod** für Formulare & Validierung
|
||||
- **jose** für signierte Session-Cookies (kein NextAuth-Overhead)
|
||||
- **nodemailer** für Mailversand (mit Dev-Fallback ins Terminal)
|
||||
- **react-day-picker** für den Verfügbarkeitskalender
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
spreewaldzeit/
|
||||
├── app/
|
||||
│ ├── layout.tsx # Root-Layout + Google Fonts
|
||||
│ ├── globals.css # Tailwind-Layer + globale Styles
|
||||
│ ├── page.tsx # Startseite
|
||||
│ ├── not-found.tsx
|
||||
│ ├── wohnungen/[slug]/
|
||||
│ │ └── page.tsx # Wohnungsdetail
|
||||
│ ├── anfrage/
|
||||
│ │ └── page.tsx # Anfrageformular
|
||||
│ ├── datenschutz/page.tsx
|
||||
│ ├── impressum/page.tsx
|
||||
│ ├── admin/
|
||||
│ │ ├── layout.tsx
|
||||
│ │ ├── page.tsx # Redirect → Anfragen
|
||||
│ │ ├── login/page.tsx
|
||||
│ │ ├── anfragen/page.tsx # Anfragen-Liste
|
||||
│ │ ├── kalender/page.tsx # Blocks sperren/freigeben
|
||||
│ │ └── wohnungen/page.tsx # Wohnungen pflegen
|
||||
│ └── api/
|
||||
│ ├── inquiries/route.ts # POST (öffentlich)
|
||||
│ ├── availability/[slug]/route.ts # GET (öffentlich)
|
||||
│ └── admin/
|
||||
│ ├── login/route.ts
|
||||
│ ├── logout/route.ts
|
||||
│ ├── inquiries/[id]/route.ts # PATCH, DELETE
|
||||
│ ├── blocks/route.ts # POST
|
||||
│ ├── blocks/[id]/route.ts # DELETE
|
||||
│ └── apartments/[id]/route.ts # PATCH
|
||||
├── components/
|
||||
│ ├── layout/ (Header, Footer)
|
||||
│ ├── home/ (Hero, About, ApartmentPreview, Location)
|
||||
│ ├── apartment/ (Gallery, Features, AvailabilityCalendar)
|
||||
│ ├── inquiry/ (InquiryForm)
|
||||
│ ├── admin/ (AdminNav, InquiryRow, CalendarManager, ApartmentEditor)
|
||||
│ └── ui/ (Button, Input, Label, Textarea, FieldError)
|
||||
├── lib/
|
||||
│ ├── db.ts # Prisma-Singleton
|
||||
│ ├── auth.ts # JWT-Session via jose
|
||||
│ ├── email.ts # Nodemailer + Mail-Templates
|
||||
│ ├── validations.ts # Zod-Schemas
|
||||
│ └── utils.ts # Preis-/Datumsformatierung
|
||||
├── prisma/
|
||||
│ ├── schema.prisma # Apartment, Inquiry, Block, Admin
|
||||
│ └── seed.ts # 2 Wohnungen + Admin + 1 Beispiel-Block
|
||||
├── types/
|
||||
├── middleware.ts # schützt /admin und /api/admin
|
||||
├── tailwind.config.ts
|
||||
├── next.config.js
|
||||
├── tsconfig.json
|
||||
├── .env.example
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Abhängigkeiten installieren
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. Environment vorbereiten
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Dann `.env` öffnen und **mindestens** setzen:
|
||||
|
||||
- `AUTH_SECRET` — zufällige, mind. 32 Zeichen lange Zeichenkette
|
||||
(z. B. `openssl rand -base64 48`)
|
||||
- `ADMIN_EMAIL` und `ADMIN_PASSWORD` — initialer Admin-Account
|
||||
- `OWNER_EMAIL` — wohin sollen neue Anfragen gehen?
|
||||
|
||||
Die SMTP-Variablen sind **optional**. Ohne sie werden Mails ins Terminal geloggt
|
||||
(praktisch fürs lokale Entwickeln).
|
||||
|
||||
### 3. Datenbank + Seed
|
||||
|
||||
```bash
|
||||
npm run setup
|
||||
```
|
||||
|
||||
Das führt die Prisma-Migration aus und legt die zwei Beispiel-Wohnungen samt
|
||||
Admin-Account an.
|
||||
|
||||
### 4. Dev-Server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
→ [http://localhost:3000](http://localhost:3000)
|
||||
→ Admin: [http://localhost:3000/admin/login](http://localhost:3000/admin/login)
|
||||
|
||||
## Nützliche Scripts
|
||||
|
||||
| Script | Zweck |
|
||||
|---------------------|----------------------------------------------------|
|
||||
| `npm run dev` | Dev-Server mit Hot-Reload |
|
||||
| `npm run build` | Production-Build (inkl. `prisma generate + migrate`)|
|
||||
| `npm run start` | Production-Server |
|
||||
| `npm run db:push` | Schema ohne Migration in DB pushen (prototyping) |
|
||||
| `npm run db:migrate`| Neue Migration erzeugen |
|
||||
| `npm run db:seed` | Seed erneut laufen lassen |
|
||||
| `npm run db:studio` | Prisma Studio öffnen (DB-Browser) |
|
||||
|
||||
## Design-System
|
||||
|
||||
- **Farben:** `parchment` (Hintergrund), `ink` (Text), `moss` & `sand` (Akzente)
|
||||
- **Typografie:** *Fraunces* (Display) + *Figtree* (Body), geladen via `next/font`
|
||||
- **Layout:** Container mit großzügigem Whitespace, asymmetrische Grids
|
||||
- **Bildsprache:** Große Bilder, ruhige Kompositionen, dezente Hover-Zooms
|
||||
|
||||
Alle Tokens in `tailwind.config.ts`.
|
||||
|
||||
## Wichtige Designentscheidungen
|
||||
|
||||
### Warum SQLite?
|
||||
Ein Reiseobjekt mit zwei Wohnungen erzeugt wenig Schreiblast. SQLite ist schnell,
|
||||
wartungsarm und das Schema ist 1:1 auf Postgres/MySQL portierbar, sobald gebraucht.
|
||||
|
||||
### Warum JWT-Cookie statt NextAuth?
|
||||
Für einen Admin-User + zwei Gastgeber ist NextAuth Overkill. `jose` liefert
|
||||
signierte Cookies in ~80 Zeilen Code, die Middleware-kompatibel (Edge) funktionieren.
|
||||
|
||||
### Warum `Block.source` trotz MVP?
|
||||
Damit der spätere iCal-Importer einfach zusätzliche Einträge mit
|
||||
`source: "airbnb"` / `source: "booking"` schreiben kann — ohne Schema-Änderung.
|
||||
|
||||
### Honeypot statt Captcha
|
||||
Das Anfrageformular hat ein verstecktes `website`-Feld als Bot-Falle.
|
||||
Für den MVP ausreichend; falls Spam zunimmt, lässt sich hCaptcha o. ä. ergänzen.
|
||||
|
||||
## Erweiterungspfad
|
||||
|
||||
Der Code ist bewusst so strukturiert, dass die folgenden Features **additiv**
|
||||
eingebaut werden können — ohne Refactoring:
|
||||
|
||||
### iCal-Sync (Airbnb / Booking.com)
|
||||
- Cron-Job (z. B. via Vercel Cron oder externer Scheduler), der pro Wohnung
|
||||
eine `ics_import_url` lädt, parst und Blocks mit `source: "airbnb"` /
|
||||
`source: "booking"` anlegt. Schema muss ggf. um `Apartment.icalUrls` erweitert werden.
|
||||
- Umgekehrt: GET-Endpoint `/api/ical/[slug].ics`, der alle Blocks als ICS ausliefert,
|
||||
damit Airbnb/Booking wiederum eure Belegung sehen.
|
||||
|
||||
### Direktbuchung
|
||||
- Stripe/Mollie-Integration im `/api/bookings/route.ts`.
|
||||
- `Booking`-Tabelle einführen; erfolgreiche Zahlungen legen automatisch einen
|
||||
`Block` mit `source: "direct"` an.
|
||||
|
||||
### Mehr Inhalte
|
||||
- Tagespreise / Saisonpreise (neues `PriceRule`-Modell).
|
||||
- Blog/Storys (neues `Post`-Modell + `/journal`-Route).
|
||||
|
||||
### Bildupload
|
||||
- Aktuell pflegt der Editor Bilder als URLs. Für echtes Hochladen:
|
||||
S3/R2/Cloudinary-Adapter in `lib/storage.ts` und Drag-and-Drop-Komponente
|
||||
im `ApartmentEditor`.
|
||||
|
||||
## DSGVO-Notizen
|
||||
|
||||
- Keine Marketing-Cookies, kein Tracking.
|
||||
- Nur technisch notwendige Session-Cookies (httpOnly, SameSite=Lax, Secure in Prod).
|
||||
- Anfragen werden mit ausdrücklicher Einwilligung verarbeitet (Checkbox im Formular).
|
||||
- Datenschutz- und Impressums-Seite als Platzhalter angelegt — **vor Go-Live rechtlich prüfen lassen**.
|
||||
|
||||
## Lizenz
|
||||
|
||||
Privat / intern. Anpassen wie benötigt.
|
||||
Reference in New Issue
Block a user