Files
VITEC-website/packages/vitec/README.md
2026-07-09 10:19:45 +02:00

235 lines
9.6 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div align="center">
# VITEC
### Headless TYPO3 extension powering the VITEC website
The editorial backend of a decoupled platform: TYPO3 v14 authors the content,
this extension turns every content element into clean **JSON** for a React front end.
<br>
![TYPO3](https://img.shields.io/badge/TYPO3-14.3-FF8700?logo=typo3&logoColor=white)
![PHP](https://img.shields.io/badge/PHP-8.x-777BB4?logo=php&logoColor=white)
![Mode](https://img.shields.io/badge/mode-headless_JSON-0A3D62)
![Content Blocks](https://img.shields.io/badge/Content_Blocks-v2-2ea44f)
![License](https://img.shields.io/badge/license-GPL--2.0--or--later-blue)
![Status](https://img.shields.io/badge/status-active_development-yellow)
</div>
---
> **What is this?**
> `evomedien/vitec` is the custom TYPO3 extension behind the VITEC relaunch. The site
> runs **headless**: TYPO3 does not render HTML — it emits a JSON document per page that
> a separate React front end consumes. This extension provides the domain models,
> content elements, layout containers and the renderers that produce that JSON, plus
> schema.org structured data for SEO.
## Table of contents
- [Highlights](#highlights)
- [Architecture at a glance](#architecture-at-a-glance)
- [Content elements &amp; plugins](#content-elements--plugins)
- [Content Blocks](#content-blocks)
- [Layout containers](#layout-containers)
- [Structured data (JSONLD)](#structured-data-json-ld)
- [Requirements](#requirements)
- [Installation](#installation)
- [Adding a new headless plugin](#adding-a-new-headless-plugin)
- [Project structure](#project-structure)
- [Documentation](#documentation)
- [License](#license)
## Highlights
- 🧩 **One JSON envelope for everything** — every content element, plugin, container and
Content Block is exposed with the same predictable outer shape.
-**Pure JSON output** — domain payloads are built in PHP, fully decoupled from
TypoScript and templates, so the logic is testable and versionable.
- 🏗️ **Nestable by design** — plugins render both as toplevel page content and as
children inside layout containers.
- 🎛️ **Editorfriendly Content Blocks** — hero, cards, CTA, FAQ, video, intro and a
twocolumn layout block, all with a unified header section.
- 🔎 **SEO built in** — a schema.org `@graph` (Organization, Product, FAQ, Events,
News …) is emitted per page.
- 🛡️ **Failsoft** — a failing element yields empty output, never a broken page.
## Architecture at a glance
```
HTTP request (headless: 1)
[L1] Page renderer friendsoftypo3/headless → { meta, content[], jsonLd }
[L2] Content-element envelope lib.contentElement(WithHeader) → id, type, appearance, content{header…}
[L3] Payload injection Classes/UserFunc/*JsonRenderer → content.<key> (products, news, …)
[L4] Layout containers vitec_cols_* = JSON → items[].contentElements[]
[L5] Normalisation & nesting ContentElementResolver / ContainerChildrenProcessor
[L6] Structured data PageJsonLdRenderer + StructuredDataService → @graph
```
Each renderer follows one pattern — an `#[AsAllowedCallable] render()` for toplevel use
plus a `renderForRecord(array $row)` for reuse inside containers — and delegates
serialisation to a service (see [`UsecaseSerializer`](Classes/Service/UsecaseSerializer.php)
as the reference).
> 📖 The full, normative architecture &amp; interface specification lives in
> **[`Documentation/Headless-JSON-Architecture.md`](Documentation/Headless-JSON-Architecture.md)**.
## Content elements &amp; plugins
| Domain | CType | Renderer | JSON key |
|---|---|---|---|
| Products | `vitec_productlist` / `vitec_productshow` | `ProductList/ProductShowJsonRenderer` | `products` / `product` |
| Success Stories | `vitec_usecaselist` / `vitec_usecaseshow` | `UsecaseList/ShowJsonRenderer``UsecaseSerializer` | `usecases` / `usecase` |
| Markets | `vitec_marketshow` | `MarketShowJsonRenderer` | `market` |
| Solutions | `vitec_solutionshow` | `SolutionShowJsonRenderer` | `solution` |
| Downloads | `vitec_downloadcard` / `vitec_downloadcardcollection` | `Downloadcard*JsonRenderer` | `downloadcard` / `downloadcardcollection` |
| Datasheets | `vitec_datasheets` | `DatasheetsJsonRenderer` | `datasheets` |
| Events | `vitec_eventlist` | `EventlistJsonRenderer` | `eventlist` |
| News | `news_pi1` (+ variants) | `NewsJsonRenderer` | `news` |
## Content Blocks
Declarative content elements (`friendsoftypo3/content-blocks`), serialised to JSON by
`nb-headless-content-blocks`. All share the unified **header section**.
| Block | Purpose |
|---|---|
| `hero-section` | Fullwidth hero with background image/video, overlays and CTA |
| `card` | Flexible card (image/icon, CTAs, many layout variants) |
| `cta-banner` | Calltoaction banner |
| `intro-paragraph` | Rich intro text with optional media |
| `video` | YouTube or uploaded video with poster |
| `faq` | Accordion; also feeds the `FAQPage` structured data |
| `columns` | Twocolumn layout (50/50 · 66/33 · 33/66) with peritem content |
## Layout containers
Nested column grids (`b13/container`) that own child content elements and emit them as
`items`, with percolumn flex (`align`/`justify`) and a wholegrid `gap`.
| CType | Layout |
|---|---|
| `vitec_cols_50_50` | Two equal columns |
| `vitec_cols_66_33` / `vitec_cols_33_66` | Asymmetric two columns |
| `vitec_cols_33_33_33` | Three columns |
| `vitec_cols_25_25_25_25` | Four columns |
| `vitec_container` | Single column with a custom CSS class |
| `vitec_cards_carousel` | Carousel of card elements |
## Structured data (JSONLD)
`PageJsonLdRenderer` + `StructuredDataService` assemble a schema.org `@graph` per page:
`Organization`, `WebSite` (root only), `BreadcrumbList`, `Product`, `VideoObject`,
`FAQPage`, `ExhibitionEvent` and `NewsArticle`.
## Requirements
| Component | Version |
|---|---|
| TYPO3 CMS | `^14.3` |
| PHP | `8.x` |
| `friendsoftypo3/headless` | `^5.0` |
| `friendsoftypo3/content-blocks` | `^2.4` |
| `netzbewegung/nb-headless-content-blocks` | `^0.0.23` |
| `b13/container` | `^3.1` |
| `georgringer/news` | `^14.0` |
## Installation
```bash
composer require evomedien/vitec
# apply database schema and clear caches
vendor/bin/typo3 database:updateschema "*.add,*.change"
vendor/bin/typo3 cache:flush
```
Enable headless mode in the site configuration (`config/sites/<site>/config.yaml`):
```yaml
headless: 1
dependencies:
- friendsoftypo3/headless
- friendsoftypo3/headless-mixed
- nb-headless-content-blocks/headless-content-blocks
- georgringer/news
```
## Adding a new headless plugin
The short version (full normative rules in the architecture spec, Clause 9 &amp; Annex A):
1. **Model / TCA / SQL** — create the domain table; declare table &amp; field names as constants.
2. **Serializer**`Classes/Service/<Domain>Serializer` with `serializeListItem()` / `serializeDetail()`.
3. **Renderer**`Classes/UserFunc/<Domain><Kind>JsonRenderer` with
`#[AsAllowedCallable] render()` + `renderForRecord()`, delegating to the serializer.
4. **TypoScript** — in `Configuration/Sets/Vitecset/setup.typoscript`:
```typoscript
tt_content.<ctype> < lib.contentElementWithHeader
tt_content.<ctype>.fields.content.fields.<key> = USER
tt_content.<ctype>.fields.content.fields.<key>.userFunc = Evomedien\Vitec\UserFunc\<Class>->render
```
5. **Nesting** — if it may sit inside a container, register it in `PLUGIN_RENDERERS`
(in both `ContentElementResolver` and `ContainerChildrenProcessor`).
6. **Deploy** — `database:updateschema "*.add,*.change"` &amp; `cache:flush`.
> **Conventions:** list keys are plural, detail keys singular; pageid via the
> `frontend.page.information` request attribute; container CTypes derive with `<` (copy),
> never `=<`.
## Project structure
<details>
<summary><strong>packages/vitec/</strong> — click to expand</summary>
```
packages/vitec/
├── Classes/
│ ├── UserFunc/ # JSON renderers (one per plugin) — headless entry points
│ ├── Service/ # Serializers, ContentElementResolver, StructuredDataService
│ ├── DataProcessing/ # ContainerChildrenProcessor (container → items)
│ ├── Domain/Model|Repository/
│ ├── Controller/ # Extbase controllers (non-headless / backend)
│ └── Backend/ · View/ · Hook/ · EventListener/
├── ContentBlocks/
│ └── ContentElements/ # card, cta-banner, columns, faq, hero-section, intro-paragraph, video
├── Configuration/
│ ├── Sets/Vitecset/ # setup.typoscript — the single headless entry point
│ ├── TypoScript/Headless/ # containers, menus, news JSON definitions
│ ├── TCA/ · FlexForms/ · Services.yaml
├── Documentation/
│ ├── Headless-JSON-Architecture.md # normative spec (start here)
│ └── HeadlessIntegration.md # informal how-to
├── Resources/
└── ext_tables.sql · ext_localconf.php · composer.json
```
</details>
## Documentation
| Document | Purpose |
|---|---|
| [`Documentation/Headless-JSON-Architecture.md`](Documentation/Headless-JSON-Architecture.md) | **Authoritative** architecture &amp; JSON interface specification (ISOstyle) |
| [`Documentation/HeadlessIntegration.md`](Documentation/HeadlessIntegration.md) | Informal stepbystep howto |
## License
[GPL2.0orlater](https://www.gnu.org/licenses/gpl-2.0.html) — © evomedien.
<div align="center"><sub>Built for the VITEC relaunch · TYPO3 headless + React</sub></div>