<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>@mteu · posts</title>
	<subtitle>Being me is full time job and I&#x27;ve never missed a day</subtitle>
	<link rel="self" type="application/atom+xml" href="https://mteu.cc/posts/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://mteu.cc/posts/"/>
  
	<updated>2026-07-16T00:00:00+00:00</updated>
	
	<id>https://mteu.cc/posts/feed.xml</id>
	<entry xml:lang="en">
		<title>Notice Before Your Client Does — Exposing health state of custom components in your TYPO3 instance</title>
		<published>2026-07-16T00:00:00+00:00</published>
		<updated>2026-07-16T00:00:00+00:00</updated>
		<link rel="alternate" type="text/html" href="https://mteu.cc/posts/2026-07-16-exposing-health-state-of-custom-components-in-your-typo3-instance/"/>
		<id>https://mteu.cc/posts/2026-07-16-exposing-health-state-of-custom-components-in-your-typo3-instance/</id>
    
		<content type="html" xml:base="https://mteu.cc/posts/2026-07-16-exposing-health-state-of-custom-components-in-your-typo3-instance/">&lt;p&gt;Some TYPO3 installations have no reliable way to tell whether they&#x27;re actually
working. A scheduler task can stop running. A queue can back up. A
third-party API a custom extension depends on can go down. None of that shows
up in a standard uptime check, because the page still renders fine — it just
quietly stops doing its job.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;EXT:monitoring&lt;&#x2F;code&gt; tries to close that gap. It aggregates checks on the
components you care about into a single status, exposed through a backend
dashboard, an HTTP endpoint, and a CLI command.&lt;&#x2F;p&gt;
&lt;p&gt;The project started from a scheduler that had silently stopped running for
several days before anyone noticed. What began as one check for that case
grew into a small architecture — authorization, caching, push notifications
— as more cases came up that needed the same kind of visibility.&lt;&#x2F;p&gt;
&lt;p&gt;Earlier versions secretly matured into what I was finally ready to release as
stable today. So here&#x27;s a look at what it does and what it gives you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-status-three-ways-to-read-it&quot;&gt;One status, three ways to read it&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-status-three-ways-to-read-it&quot; aria-label=&quot;Anchor link for: one-status-three-ways-to-read-it&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The extension collects results from monitoring providers — small classes that
each check one thing — and aggregates them into a single status: &lt;code&gt;healthy&lt;&#x2F;code&gt;,
&lt;code&gt;degraded&lt;&#x2F;code&gt;, or &lt;code&gt;unhealthy&lt;&#x2F;code&gt;. That status is available through:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;An HTTP endpoint (&lt;code&gt;&#x2F;monitor&#x2F;health&lt;&#x2F;code&gt; by default), returning structured
JSON for polling by Nagios, Icinga, Uptime Kuma, or similar tools.&lt;&#x2F;li&gt;
&lt;li&gt;A CLI command, for cron jobs, deploy scripts, or manual checks.&lt;&#x2F;li&gt;
&lt;li&gt;A backend dashboard, showing the same status with a wee more verbosity inside TYPO3, and&lt;&#x2F;li&gt;
&lt;li&gt;optional push notifications, for setups where nothing polls the endpoint.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All three read from the same source, so the dashboard, the endpoint, and any
notification stay consistent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;response-format&quot;&gt;Response format&lt;a class=&quot;zola-anchor&quot; href=&quot;#response-format&quot; aria-label=&quot;Anchor link for: response-format&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;H&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;X-TYPO3-MONITORING-AUTH: &amp;lt;token&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; https:&#x2F;&#x2F;example.com&#x2F;monitor&#x2F;health&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;healthy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;services&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Scheduler&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;healthy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;subResults&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;                &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Scheduler Execution&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;healthy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;                &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Overdue Tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;healthy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support&quot;&gt;                &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Failed Tasks&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;healthy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The overall status is the worst status of anything underneath it. &lt;code&gt;unhealthy&lt;&#x2F;code&gt;
returns HTTP 503; &lt;code&gt;healthy&lt;&#x2F;code&gt; and &lt;code&gt;degraded&lt;&#x2F;code&gt; both return 200 — &lt;code&gt;degraded&lt;&#x2F;code&gt; means
&quot;operational, but worth a look,&quot; not &quot;down.&quot; This distinction lets you page on
outages without paging on minor issues.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;providers&quot;&gt;Providers&lt;a class=&quot;zola-anchor&quot; href=&quot;#providers&quot; aria-label=&quot;Anchor link for: providers&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A provider is a small, focused class:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; readonly&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; MyServiceProvider&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity&quot;&gt; MonitoringProvider&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; getName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;MyService&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; getDescription&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Monitors my custom service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; isEnabled&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; isActive&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;isEnabled&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; execute&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; Result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        try&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;            &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; do the check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; MonitoringResult&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;getName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; Status&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;Healthy&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;\&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; MonitoringResult&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;getName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; Status&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt;Unhealthy&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;getMessage&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Providers are auto-discovered via a PHP attribute on the interface — no
manual registration. A provider can report multiple sub-results under one
name, and expensive checks can implement &lt;code&gt;CacheableMonitoringProvider&lt;&#x2F;code&gt; to
avoid hitting a downstream system on every request.&lt;&#x2F;p&gt;
&lt;p&gt;The extension ships one built-in provider: a Scheduler Provider that checks
the Scheduler as a whole — heartbeat, overdue tasks, and failed tasks
together — rather than trusting individual task status, since a cron job
that stops firing doesn&#x27;t make any single task &quot;fail.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;authorization&quot;&gt;Authorization&lt;a class=&quot;zola-anchor&quot; href=&quot;#authorization&quot; aria-label=&quot;Anchor link for: authorization&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Two authorizers ship by default:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Token authorization — an HMAC of the endpoint path, generated with
TYPO3&#x27;s &lt;code&gt;HashService&lt;&#x2F;code&gt;, sent as a header. The &lt;em&gt;Monitoring → Authorizers&lt;&#x2F;em&gt;
backend module shows the ready-to-use token.&lt;&#x2F;li&gt;
&lt;li&gt;Admin session authorization — anyone logged into the TYPO3 backend as
an administrator can open the endpoint directly.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Both are evaluated in priority order. Custom authorizers use the same
attribute-based discovery as providers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;push-notifications&quot;&gt;Push notifications&lt;a class=&quot;zola-anchor&quot; href=&quot;#push-notifications&quot; aria-label=&quot;Anchor link for: push-notifications&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;For setups without external polling, the extension can push status through
reporters — a built-in &lt;code&gt;EmailReporter&lt;&#x2F;code&gt;, with the same extension point for
Slack, Teams, or other channels. Reporters run on demand, typically from a
scheduler task, via a &lt;code&gt;monitoring:report&lt;&#x2F;code&gt; CLI command.&lt;&#x2F;p&gt;
&lt;p&gt;A small state machine tracks whether an outage is new, a reminder is due, or
the system has recovered, and dispatches to reporters based on their
configured threshold. This produces one notification when something breaks,
periodic reminders while it stays broken, and one &quot;all clear&quot; when it&#x27;s
fixed, rather than an alert on every cron run.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;command-line&quot;&gt;Command line&lt;a class=&quot;zola-anchor&quot; href=&quot;#command-line&quot; aria-label=&quot;Anchor link for: command-line&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;.&#x2F;vendor&#x2F;bin&#x2F;typo3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; monitoring:run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Checking&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Monitoring&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; ✅&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Scheduler&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; ✅&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Solr&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Cores&lt;&#x2F;span&gt;&lt;span&gt; (cached&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; ✅&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Redis&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; 🚨&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; FancyExternalApiService&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; ✅&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; LDAP&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Import&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; ✅&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; SSO&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Roundtrip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;Monitoring&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; status:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; FAILED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Standard exit codes (&lt;code&gt;0&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;1&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;2&lt;&#x2F;code&gt;) make it straightforward to wire into deploy
pipelines or health-gate scripts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-started&quot; aria-label=&quot;Anchor link for: getting-started&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;composer&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; require&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mteu&#x2F;typo3-monitoring&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; config&#x2F;system&#x2F;settings.php&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;EXTENSIONS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;        &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;monitoring&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;            &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;api&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;                &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;monitor&#x2F;health&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;                &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;enforceHttps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;            &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;authorizer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;                &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;mteu\Monitoring\Authorization\TokenAuthorizer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;                    &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;enabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;                    &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;secret&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;your-secure-secret&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;                    &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;authHeaderName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;X-TYPO3-MONITORING-AUTH&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s enough for a working endpoint. From there, the extension point is
open: write a provider for whatever a project depends on — a search index,
an external api fetch,a payment gateway, a queue, a filesystem mount —
and it slots into the same status, dashboard, and alerting path as everything else.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;MonitoringProvider&lt;&#x2F;code&gt;, &lt;code&gt;Authorizer&lt;&#x2F;code&gt;, and &lt;code&gt;Reporter&lt;&#x2F;code&gt; are the whole surface area
of the package. They&#x27;ve been in use in production for about a year, and the
interfaces are now considered stable.&lt;&#x2F;p&gt;
&lt;p&gt;The first stable version of &lt;code&gt;EXT:monitoring&lt;&#x2F;code&gt; was release today. It supports TYPO3 v13 and v14 LTS. Full documentation with advanced examples is available on GitHub: &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mteu&#x2F;typo3-monitoring&quot;&gt;&lt;code&gt;mteu&#x2F;typo3-monitoring&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Type-Safe Extension Configuration in TYPO3</title>
		<published>2025-11-25T00:00:00+00:00</published>
		<updated>2025-11-25T00:00:00+00:00</updated>
		<link rel="alternate" type="text/html" href="https://mteu.cc/posts/2025-11-25-announcing-typed-ext-conf/"/>
		<id>https://mteu.cc/posts/2025-11-25-announcing-typed-ext-conf/</id>
    
		<content type="html" xml:base="https://mteu.cc/posts/2025-11-25-announcing-typed-ext-conf/">&lt;p&gt;If you&#x27;ve spent any time building TYPO3 extensions, you&#x27;ve almost certainly bumped into the same frustration: extension configuration values are stored as strings. All of them. When a site administrator sets &lt;code&gt;maxItems&lt;&#x2F;code&gt; to &lt;code&gt;25&lt;&#x2F;code&gt; in the backend, your extension receives the string &lt;code&gt;&quot;25&quot;&lt;&#x2F;code&gt;. Need a boolean? You get &lt;code&gt;&quot;1&quot;&lt;&#x2F;code&gt; or &lt;code&gt;&quot;0&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But the string problem is only half of it. Nothing stops a development team from overriding extension configuration values directly in &lt;code&gt;config&#x2F;system&#x2F;additional.php&lt;&#x2F;code&gt; — or anywhere else that writes into &lt;code&gt;$GLOBALS[&#x27;TYPO3_CONF_VARS&#x27;]&lt;&#x2F;code&gt;. When that happens, all bets are off. That &lt;code&gt;maxItems&lt;&#x2F;code&gt; value could now be an actual &lt;code&gt;int&lt;&#x2F;code&gt;, a &lt;code&gt;bool&lt;&#x2F;code&gt;, &lt;code&gt;null&lt;&#x2F;code&gt;, or something else entirely, depending on who wrote the override and when. Your extension is suddenly dealing with a mixed-type runtime reality it never agreed to.&lt;&#x2F;p&gt;
&lt;p&gt;The usual workarounds — custom wrapper classes, on-the-fly casting, &lt;code&gt;is_*&lt;&#x2F;code&gt; guards scattered across your codebase — are repetitive, error-prone, and still don&#x27;t protect you from unexpected types sneaking in through overrides.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s why I choose to offer a cleaner way to access extension configuration. So here&#x27;s me shamelessly advertising the TYPO3 extension &lt;strong&gt;Typed Extension Configuration&lt;&#x2F;strong&gt; v1.0 release:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;extensions.typo3.org&#x2F;extension&#x2F;typed_extconf&quot;&gt;&lt;code&gt;EXT:typed_extconf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; provides a somewhat type-safe extension configuration layer for TYPO3. You define your configuration as a plain PHP class with typed constructor parameters and a couple of attributes — the library handles reading, converting, and validating everything automagically:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtensionConfig&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;extensionKey&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;my_extension&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; readonly&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; MyExtensionConfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; __construct&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtConfProperty&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        public&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;maxItems&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtConfProperty&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        public&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;enableFeature&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        #[&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt;ExtConfProperty&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;api.endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        public&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;apiEndpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;api&#x2F;v1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then just type-hint the configuration class in your constructor — TYPO3&#x27;s DI container takes care of the rest:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; Foo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; __construct&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;        private&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage&quot;&gt; readonly&lt;&#x2F;span&gt;&lt;span class=&quot;z-support&quot;&gt; MyExtensionConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name&quot;&gt; doSomething&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; void&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;maxItems&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;enabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;enableFeature&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;        $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;apiEndpoint&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No casting, no manual parsing, no surprises — just clean, typed PHP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;features&quot;&gt;Features&lt;a class=&quot;zola-anchor&quot; href=&quot;#features&quot; aria-label=&quot;Anchor link for: features&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Attribute-Based Schema: Define your configuration contract with &lt;code&gt;#[ExtensionConfig]&lt;&#x2F;code&gt; and &lt;code&gt;#[ExtConfProperty]&lt;&#x2F;code&gt;. Declarative, readable, and IDE-friendly.&lt;&#x2F;li&gt;
&lt;li&gt;Path Mapping: Map nested configuration keys with ease, e.g. &lt;code&gt;api.endpoint&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Configuration Generation: Run &lt;code&gt;.&#x2F;vendor&#x2F;bin&#x2F;typo3 typed-extconf:generate&lt;&#x2F;code&gt; to scaffold a configuration class from your existing &lt;code&gt;ext_conf_template.txt&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Dependency Injection: Configuration classes are auto-registered as services.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Under the hood, the library is powered by the amazing &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;CuyZ&#x2F;Valinor&quot;&gt;CuyZ&#x2F;Valinor&lt;&#x2F;a&gt; for type-safe object mapping and validation — ensuring invalid or unexpected values are caught early, not deep inside your business logic.&lt;&#x2F;p&gt;
&lt;p&gt;The extension supports TYPO3 v12, v13, and v14 LTS. Full documentation, advanced examples, and a developer guide are available on &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mteu&#x2F;typo3-typed-extconf&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>TYPO3 Developer Days 2025</title>
		<published>2025-08-10T00:00:00+00:00</published>
		<updated>2025-08-10T00:00:00+00:00</updated>
		<link rel="alternate" type="text/html" href="https://mteu.cc/posts/2025-08-10-t3dd25/"/>
		<id>https://mteu.cc/posts/2025-08-10-t3dd25/</id>
    
		<content type="html" xml:base="https://mteu.cc/posts/2025-08-10-t3dd25/">&lt;p&gt;I&#x27;ve just returned from Karlsruhe to resume my summer vacation after having attended this year&#x27;s &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;t3dd25.typo3.com&#x2F;&quot;&gt;TYPO3 Developer Days&lt;&#x2F;a&gt;, and what an incredible experience it was yet again!&lt;&#x2F;p&gt;
&lt;p&gt;From exploring TYPO3&#x27;s development future to understanding how emerging technologies will reshape content management, the sessions provided a vision of where we&#x27;re heading. It wasn&#x27;t just about current best practices, but about preparing for the next generation of web development challenges and opportunities.&lt;&#x2F;p&gt;
&lt;p&gt;What struck me most was how the community has evolved - I might be wrong but the conference felt noticeably younger and more diverse, with significantly more women participating than in previous years. This shift is fantastic to see and brings fresh perspectives and energy to our ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;The true spirit of open source was alive and thriving. People genuinely inspired each other to share knowledge, contribute code, and push the boundaries of what&#x27;s possible with TYPO3 and PHP. The contribution night and several water-cooler discussions embodied the very best of community-driven development, with core developers being incredibly approachable and eager to share their insights as well as listen to new ideas.&lt;&#x2F;p&gt;
&lt;p&gt;While many attendees represented agencies and commercial interests, what shone through was the incredible amount of passion and volunteer spirit driving this community. People dedicate countless hours not for profit, but for the love of building something meaningful together.&lt;&#x2F;p&gt;
&lt;p&gt;The motivation for this volunteer work can be challenging to sustain. Often, you feel like you&#x27;re working in isolation, questioning whether your contributions truly matter. But events like &lt;a rel=&quot;nofollow noreferrer external&quot; href=&quot;https:&#x2F;&#x2F;t3dd25.typo3.com&#x2F;&quot;&gt;T3DD25&lt;&#x2F;a&gt; or the many barcamps throughout the year remind you exactly why you do this work - you&#x27;re not alone. You&#x27;re part of a global community of people who believe in the power of open source to create something greater than the sum of its parts.&lt;&#x2F;p&gt;
&lt;p&gt;A heartfelt thank you to the organizers who made this event possible, to the sponsors who give back to the open source community that supports their businesses, and to every single participant who took time from their lives to be there. Without dedicated developers, contributors, and community members like these, events like this wouldn&#x27;t exist - and neither would the open source ecosystem we all depend on.&lt;&#x2F;p&gt;
&lt;p&gt;I genuinely hope to return next year for T3DD26.&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
