Freemium vs Pro¶
PerfShop applies a freemium model: part of the platform is accessible without a license to allow discovery and onboarding, and the rest is unlocked by activating a commercial license. This page describes precisely the boundary between the two.
Sources
backend/src/main/java/com/perfshop/service/LicenseService.java, chaos/LicenseInterceptor.java, controller/ChaosStudentController.java, controller/ChaosScriptingPublicController.java
Philosophy¶
A student should be able to get started with PerfShop immediately, without formality. They should be able to navigate the shop, run a first performance chaos, try a first scripting level, and start the first two levels of the pedagogical journey (BAC1 and BAC2). This is more than enough for a convincing demonstration in class or in an assessment.
What constitutes intensive use in continuing education or in enterprise — the full business chaos, OWASP security flaws, advanced scenarios, the expert pedagogical journey — requires a license.
The commercial license also includes access to a turnkey lab library hosted separately, which is not distributed with the PerfShop source code and is not documented here.
Summary table¶
| Chaos family | Without license (freemium) | With license |
|---|---|---|
| Backend performance | Level 0 + Level 1 (freemium N1) | Levels 0 to 4 + 20 weather scenarios |
| Scripting | Level 0 + Level 1 (Junior) | Levels 0 to 4 (up to Maestro) |
| Frontend | Level 0 only | Levels 0 to 4 |
| Business | Level 0 only | Levels 0 to 4 (16 anomalies A1-A16) |
| Functional | Level 0 only | Levels 0 to 4 (F1-F4) |
| Security | Level 0 only | Levels 0 to 4 (S1-S12, admin portal S10-S12 at Master level) |
| Pedagogical | BAC1, BAC2 | BAC1 to BAC5 |
| Instructor interface | Without license | With license |
|---|---|---|
chaos-admin (instructor panel) |
❌ Blocked | ✅ Accessible |
scripts-ui (web script editor) |
❌ Blocked | ✅ Accessible (plan functional+) |
jmeter-ui (JMeter launcher) |
❌ Blocked | ✅ Accessible (plan performance+) |
monitoring (admin login) |
❌ Blocked | ✅ Accessible |
Admin backoffice /api/admin/* |
❌ Blocked | ✅ Accessible |
| Student interface | Without license | With license |
|---|---|---|
Student page chaos-admin/public/ |
✅ Accessible | ✅ Accessible |
| E-commerce shop | ✅ Accessible | ✅ Accessible |
| Read-only HTML monitoring dashboard | ✅ Accessible | ✅ Accessible |
| MkDocs documentation | ✅ Accessible | ✅ Accessible |
What is always accessible¶
These resources are never blocked by the LicenseInterceptor, regardless of the license:
/api/license/*— activation, status, revocation (otherwise deadlock)/api/chaos/student/*— the freemium student page/api/chaos/public/*— read-only pedagogical monitoring/api/products/*— shop catalog/api/auth/*— shop authentication/api/cart/*— cart/api/checkout/*— checkout funnel/api/orders/*— orders/api/countries— country reference data/actuator/*— Prometheus scraping/images/*— product assets
See License system for the exhaustive list and the interception logic.
HTTP 402 Payment Required¶
When a protected endpoint is called without a valid license, the backend responds:
HTTP/1.1 402 Payment Required
Content-Type: application/json;charset=UTF-8
X-License-Required: true
{
"error": "LICENSE_REQUIRED",
"message": "License required to access chaos-admin",
"path": "/api/chaos/backend",
"activateUrl": "/api/license/activate",
"statusUrl": "/api/license/status",
"portalUrl": "https://perfshop.io"
}
The HTTP code 402 is deliberately chosen — it means exactly "payment required". The HTTP spec reserved it for future use related to micropayments; it is rarely used in practice, which makes it a clear and unambiguous signal. The PerfShop frontends (chaos-admin, scripts-ui, jmeter-ui) detect this code and display a redirect message to the activation portal rather than a generic error.
The additional X-License-Required: true header allows programmatic clients (curl, CI scripts) to detect the case without parsing the JSON.
Freemium enforcement in code¶
The LicenseInterceptor handles URL-based authorization. For finer freemium endpoints (Scripting level 1 allowed, levels 2+ blocked), enforcement goes through the controllers themselves which consult licenseService.isLicenseValid() and limit the maxLevel returned in the /status payloads.
For example, ChaosStudentController returns for each chaos family an object { level, maxLevel }. Without a license, maxLevel is 1 for scripting (Junior freemium) and 0 for business, functional, security. With a license, maxLevel becomes 4 for all families.
The frontend uses this value to visually lock the sliders: slider.max = maxLevel and slider.disabled = (maxLevel === 0). See Student chaos page.
Master level (cumulative level 4)¶
Level 4 of each family is nicknamed "Master" in the interfaces. It requires an active license but is also qualitatively different:
- Business Master (A12-A16) — 5 silent anomalies with high financial impact, invisible without inspecting the JSON payloads
- Security Master (S10-S12) — chained scenario on the vulnerable admin portal (see Admin portal and Security Chaos)
- Functional Master (F4) — silent corruption: no crash, green Tempo, HTTP 200, but corrupted payload
- Scripting Master — HMAC key derived per session (more demanding in reverse engineering)
- Performance Master — N4 weather scenarios combining several simultaneous chaos types
- Pedagogical Master (BAC5) — longest journey, passwords built with XOR + Pi computation
The Master level is the target of the most advanced training sessions. It is included in all plans (functional, performance, enterprise).
Activation from the student page¶
An important detail: the student page remains accessible without a license, and it includes a "🔑 Activate a license" button in the header that calls POST /api/license/activate. This endpoint is itself public (see License system).
Practical consequence in a classroom: the instructor can give a key to a test student, who activates it from their workstation — and all other students immediately benefit from the unlocked levels, because the license is shared at the server level, not at the browser session level. This property is a direct consequence of the model: one license per PerfShop instance, not per user.
What happens when the license expires?¶
On every call, isLicenseValid() checks the current date against expiresAt:
public boolean isLicenseValid() {
LicenseInfo info = cachedLicense.get();
if (info == null) return false;
if (info.expiresAt == null) return true;
return !LocalDate.now().isAfter(info.expiresAt);
}
The switch is immediate: starting the day after expiration, all calls to protected endpoints return 402. The shop, the student page and the HTML monitoring remain accessible — meaning that students can continue to see what they have already launched but can no longer start new chaos. Historical Grafana dashboards remain browsable.
To extend, simply activate a new key via POST /api/license/activate — no restart is necessary.
Purchasing a license¶
PerfShop commercial licenses are distributed by perfshop.io. The terms (number of instances, duration, training, support) are negotiated directly. Contact contact@perfshop.io to obtain a quote.
The license purchase also includes access to the turnkey lab library, which is hosted separately and is not documented in this technical reference.