From dee72641a69851e89078f8c47941a6628a3cbfa8 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 21 Jul 2026 00:00:35 +0000 Subject: [PATCH] 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. --- README.md | 119 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index e215bc4..553cfaf 100644 --- a/README.md +++ b/README.md @@ -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