TLDR version
We (webcloud7) launched our first big customer with Plone 6 classic as the backend and an independent Frontend developed by another company back in October. The frontend uses the RestAPI to get all its data.
URL: https://www.baselland.ch a Swiss canton.
The site has, on average 500K to 1M (peaked at 2Mio) hits per 24h and approx. 100k to 350k API (Plone) requests per 24h. 300 Users are creating content on it.
The backend and frontend runs behind Cloudflare, which we use for caching, WAF, etc.
Tech-Stack:
- Kubernetes
- Docker
- Plone 6.0.13 (Will be 6.1 next week)
- ZEO setup with longhorn
- Elasticsearch
- Redis / python-rq
- Keycloak
- Grafana/Loki (Dashboards / Alerts)
- CircleCI
On top of Plone 6, we developed some Add-ons and customizations to suit the needs of our new product and the customers.
We will launch more customers on the new platform this year
If you are interested, you can keep reading for more detailed information
Kubernetes Cluster:
This was built with the help of Six Feet Up and is optimized for Exoscale. The Helm charts can be applied to any other platform as well. We installed clusters on AWS, DigitalOcean, and Google for testing purposes.
Some features developed for our Backend):
- wcs.samlauth: State-of-the-art SAML2 Auth plugin with detailed documentation. GitHub - webcloud7/wcs.samlauth
- wcs.adminauth CAS 3 Version based auth services for admins: GitHub - webcloud7/wcs.adminauth
- Contributed Async/Redis/RQ-Python integration for collective.elasticsearch
- Configurable ReferenceWidget (from my old Plone days) made Plone 6/6.1 compatible
- We have our own Page Builder GitHub - webcloud7/wcs.simplelayout - No official release
- Further, not yet publicly available features (Ping me if there is an interest):
- Optimizations for Plone Classic UI, so it is only accessible with a valid session. The Plone Classic UI is only there for authors. No anonymous access is possible.
- Plone Classic MapWidget based on leaflet.js and OpenStreetMap. Stores GEOJson, which can be easily indexed in Elasticsearch. Support for plone.supermodel (Import/Export). Single/Multi Value. Points/Polygons/etc.
- Generic Widget based on a JSONField’s schema (Only supports a minimal number of types so far.
- Support importing JSONField with schema for plone.supermodel
- Opening Hours Widget, which generates openingHours - Schema.org Property output
- Internal Task/Review System
- Cache invalidation Client for Cloudflare (Async / RQ Python / Redis)
- Our own WorkingCopy/Staging Implementation.
- Trash/Bin Implementation - Retains deleted items for 30 days
- RestAPI Performance improvements.
- Custom Workflows
- RQ Python Jobs dashboard for Plone
- Generic Async jobs and scheduled jobs with rq python
- Custom Rules to make certain fields contain a value, or a certain value.
- Minimal Matomo stats integration.
- Tons of small tweaks to meet our customers demands.
Other interesting points:
- End2End Tests with Testcafe Studio
- All JS parts are written with VueJS
We cache everything with Cloudflare, and invalidate only necessary parts if there are changes. This results in being able to Cache over 90% of all requests.
Due to the nature that Cloudflare no longer caches content that did not get access for a certain period, and we install frequent frontend/backend updates, in which cases we have to clear the entire cache. Something above the 90% mark is realistic.
This also means we need significantly fewer resources to serve the same number of requests.
API optimizations:
For performance reasons, We had to implement several improvements to the RestAPI. One reason is that Exoscale single core compute power is quite a bit slower than AWS, Google, etc. by a factor of 1.5 to 2, and another reason is that the Frontend team was able to construct slow queries accidentally.
Those are typical 24h on our System - The 95 percentile is about 200 to 250ms - Those are only RestAPI requests, including images and files almost always with fullobjects and include_items. The API is not cached on Cloudflare for the frontend.