Replace create-next-app boilerplate README with real project docs

Covers stack, pages, Payload CMS collections used by this tenant (with
field-level detail), cart/checkout demo-status caveats, and deployment.
This commit is contained in:
Marco
2026-07-21 00:00:35 +00:00
parent 3bde1d61ff
commit dee72641a6
+99 -20
View File
@@ -1,36 +1,115 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# einfach-produktiv — Frontend
## Getting Started
Next.js frontend for [einfach-produktiv.mk360.de](https://einfach-produktiv.mk360.de),
Coolify-managed and deployed from this repo (`git.mk360.de/Marco/einfach-produktiv`).
For the VPS-wide infrastructure this app runs on (Caddy, Coolify, Gitea, the
shared Payload instance), see `~/dev/README.md` — this file only covers what's
specific to this project.
First, run the development server:
## Stack
- **Next.js 16.2.9** (App Router, `output: "standalone"` for a small Docker
image — see `AGENTS.md` before touching anything version-specific, this
Next.js release differs from older training-data conventions)
- **React 19.2.4**, **Tailwind CSS 4**, **Motion** for animation
- No local database, no auth — all editable content comes from the shared
Payload CMS at `payload.mk360.de` (see below)
## Getting started
```bash
npm install
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Open [http://localhost:3000](http://localhost:3000). `npm run build && npm run
start` reproduces the production build locally — do this before pushing,
since Coolify builds with `--no-cache` and a failed build only surfaces there
otherwise.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
**Environment variables:** `PAYLOAD_URL` (defaults to `https://payload.mk360.de`
if unset, see `app/lib/payload.ts`). Set in Coolify's app settings for
production, not in a committed `.env` — this app has no other secrets.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Pages
## Learn More
| Route | Purpose |
|---|---|
| `/` | Home — hero, product spotlight, tools grid, trust row |
| `/shop` | Product grid (all active products for this tenant) |
| `/blog`, `/blog/[slug]` | Blog overview + post detail |
| `/cart` | Cart (localStorage-backed, see below) |
| `/checkout` | Shipping + payment method selection, order summary |
| `/bestellbestaetigung` | Order confirmation — reads the one-time snapshot `/checkout` wrote |
| `/challenge` | "Mini-Challenge" tool |
| `/todo-cards` | "Todo-Karten" tool |
| `/newsletter` | Newsletter signup |
| `/versand` | Shipping policy (timeframes, costs) |
| `/impressum`, `/datenschutz`, `/agb`, `/widerruf` | Legal pages (from Payload, see `legal-pages` below) |
To learn more about Next.js, take a look at the following resources:
## Content backend: Payload CMS
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
This app is one **tenant** in a shared, multi-tenant Payload instance also
used by other projects on the same VPS (see `docker/payload/` in the infra
repo). All content queries go through `app/lib/payload.ts`, which hardcodes
`TENANT_SLUG = "einfach-produktiv"` and filters every request with
`where[tenant.slug][equals]=einfach-produktiv` — the tenant field itself is
injected automatically into every collection below by Payload's
`multiTenantPlugin`, not defined in this app.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
`/api/products` is this app's own same-origin proxy route (`app/api/products/route.ts`)
in front of `getProducts()` — used by client components (cart, related
products) that need the catalog reactively, so they don't talk to Payload's
API directly and reuse Next.js's fetch cache instead of an extra round trip.
## Deploy on Vercel
### Collections used by this tenant
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
All reads are public (`access.read: () => true`); only writes are
admin-gated in the Payload admin UI at `payload.mk360.de/admin`.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
| Collection (slug) | Used for | Key fields |
|---|---|---|
| `products` | `/shop` grid, homepage spotlight, cart, checkout | `name`, `slug` (cart item id — **not** Payload's numeric id, so existing localStorage carts survive catalog changes), `description`, `price`, `compareAtPrice` (optional strikethrough), `image`, `detailHref`, `sortOrder`, `spotlight` + `spotlightEyebrow`/`spotlightHeadline`/`spotlightText`/`spotlightImage` (homepage "Neu im Shop" section — falls back to `image` if no dedicated spotlight image is set) |
| `posts` | `/blog`, `/blog/[slug]` | `title`, `slug`, `category` (relation to `categories`), `excerpt`, `thumbnail`, `content` (richText), `readTime` (auto-calculated on save from word count), `featured` (shown as the `/blog` hero post; most-recently-published wins if several are marked), `publishedAt` |
| `categories` | Blog post categorization | `name`, `slug` (unique per tenant, not globally) |
| `legal-pages` | `/impressum`, `/datenschutz`, `/agb`, `/widerruf` | `type` (`impressum`/`datenschutz`/`agb`/`widerruf`, one doc per type per tenant), `title`, `content` (richText), `attachment` (optional file, e.g. the Muster-Widerrufsformular PDF) |
| `trust-badges` | Horizontal "Schneller Versand / Versandkostenfrei / Mit Liebe verpackt" row — shown on `/shop`, `/cart`, `/checkout`, `/widerruf`, `/agb`, 404 | `title`, `description`, `icon`, `sortOrder` |
| `cart-trust-badges` | Sidebar bullets on `/cart` (title only) and `/checkout` (title + description) — deliberately a separate collection from `trust-badges` so the two pages can't drift into showing different claims | `title`, `description`, `icon`, `sortOrder` |
| `shipping-methods` | `/checkout` shipping selection | `title`, `description`, `price`, `freeShippingThreshold` (per-method, optional — leave empty for a method that should never be free, e.g. Express), `active` (inactive methods are hidden, not shown disabled), `sortOrder` |
| `payment-methods` | `/checkout` payment selection | `title`, `icons` (array — e.g. 3 logos for "Kreditkarte"), `active`, `sortOrder` |
| `werkzeuge-cards` | Homepage "Meine Werkzeuge" 3-card grid | `title`, `description`, `icon`, `ctaLabel`, `ctaHref`, `sortOrder` |
| `media` | Shared upload collection (not tenant-scoped) backing every `image`/`icon`/`thumbnail`/`attachment` field above | `alt` (required for images), `title` (optional display name for download links) |
Editorial changes (prices, copy, images, toggling a shipping/payment method
on or off) all happen in the Payload admin UI — no code deploy needed. Adding
a *new field* to any collection above requires editing the collection file in
`docker/payload/src/collections/` and a migration, which does need a deploy
of the Payload service.
## Cart & checkout — demo status
- **Cart** (`app/lib/cart.ts`) is entirely client-side, stored in
`localStorage` under `ep_cart`, keyed by each product's `slug`.
- **Checkout has no real backend.** `/checkout`'s "Jetzt kaufen" click writes
a one-time snapshot (chosen shipping/payment method, cart contents) to
`sessionStorage` (`app/lib/order.ts`), which `/bestellbestaetigung` reads
once and displays — that snapshot *is* the order record. There is no
payment processing, no persisted order in Payload or anywhere else, and no
confirmation email yet. Treat this as a frontend/demo checkout flow, not a
functioning store.
## Deployment
- **Dockerfile**: 3-stage build (`deps``builder``runner`) with
BuildKit cache mounts, producing a ~100 MB standalone image. This is the
reference `Dockerfile` copied when scaffolding new projects on this VPS
(see the infra repo's new-project workflow).
- Deploys via `git push` → Gitea webhook → Caddy `/deploy/einfach-produktiv`
bridge → Coolify API → rebuild + restart. Full mechanics in
`~/dev/README.md`.
## Related design source
- `~/dev/einfach-produktiv/mockups/` — Figma-stage mockup PNGs
- `~/dev/einfach-produktiv/styleguide.md` — design tokens (colors, type, spacing)
- `~/dev/einfach-produktiv/einfachproduktiv_figma_prompt_guide_v3.md` — Figma rebuild prompt guide