<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Documentation on Strichliste ‒ The Tally Sheet Replacement for Your Organization</title>
		<link>https://www.strichliste.org/docs/</link>
		<description>Recent content in Documentation on Strichliste ‒ The Tally Sheet Replacement for Your Organization</description>
		<generator>Hugo</generator>
		<language>en-us</language>
		
		
		
		
			<lastBuildDate>Fri, 12 Jun 2026 09:00:00 +0200</lastBuildDate>
		
			<atom:link href="https://www.strichliste.org/docs/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Configuration</title>
				<link>https://www.strichliste.org/docs/configuration/</link>
				<pubDate>Fri, 12 Jun 2026 09:00:00 +0200</pubDate>
				<guid>https://www.strichliste.org/docs/configuration/</guid>
				<description>&lt;p&gt;All application-level behavior is configured in &lt;strong&gt;one file&lt;/strong&gt;,&#xA;&lt;code&gt;config/strichliste.yaml&lt;/code&gt;, under the &lt;code&gt;parameters.strichliste&lt;/code&gt; key. The same&#xA;values drive the web UI &lt;strong&gt;and&lt;/strong&gt; are exposed verbatim to API clients via&#xA;&lt;code&gt;GET /api/settings&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Applying changes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Bare metal&lt;/strong&gt;: edit the file, then &lt;code&gt;php bin/console cache:clear&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Docker&lt;/strong&gt;: bind-mount your copy into the &lt;code&gt;app&lt;/code&gt; service — the entrypoint&#xA;recompiles the cache on every boot, so a restart applies it. See the&#xA;README section &lt;em&gt;&amp;ldquo;Settings without rebuilding&amp;rdquo;&lt;/em&gt; for the exact snippet.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Two recurring datatypes:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Console commands</title>
				<link>https://www.strichliste.org/docs/commands/</link>
				<pubDate>Fri, 12 Jun 2026 09:00:00 +0200</pubDate>
				<guid>https://www.strichliste.org/docs/commands/</guid>
				<description>&lt;p&gt;Run with &lt;code&gt;php bin/console …&lt;/code&gt; — inside Docker:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose &lt;span style=&#34;color:#6639ba&#34;&gt;exec&lt;/span&gt; app php bin/console …&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Command&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Purpose&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;app:import &amp;lt;file&amp;gt;&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Import a strichliste 1 &lt;code&gt;database.sqlite&lt;/code&gt;. &lt;strong&gt;Wipes the target database first.&lt;/strong&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;app:user:status &amp;lt;user&amp;gt; &amp;lt;true|false&amp;gt;&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Enable/disable an account by name or id.&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;app:user:cleanup&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Bulk-disable accounts inactive for longer than an interval.&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;app:retire-data&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;strong&gt;Delete&lt;/strong&gt; transactions older than an interval — the data-privacy tool.&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;app:ldapimport&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Create/update users from an LDAP directory (cron-able).&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;cache:clear&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Apply &lt;code&gt;strichliste.yaml&lt;/code&gt; changes (bare metal; the Docker entrypoint does this on boot).&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;doctrine:migrations:migrate&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Apply schema migrations (automatic in Docker).&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;import-a-strichliste-1-database&#34;&gt;Import a strichliste 1 database&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php bin/console app:import database.sqlite&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This wipes the target database first&lt;/strong&gt; — all existing users, transactions&#xA;&lt;em&gt;and&lt;/em&gt; articles are deleted — so only run it on a fresh install. It imports&#xA;users and transactions; the product list is entered by hand afterwards.&#xA;After the import the terminal outputs &amp;ldquo;Import done!&amp;rdquo;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>REST API</title>
				<link>https://www.strichliste.org/docs/api/</link>
				<pubDate>Fri, 12 Jun 2026 09:00:00 +0200</pubDate>
				<guid>https://www.strichliste.org/docs/api/</guid>
				<description>&lt;p&gt;The &lt;code&gt;/api/*&lt;/code&gt; endpoints are &lt;strong&gt;stable&lt;/strong&gt; — existing clients keep working&#xA;unchanged. The API is documented as an OpenAPI 3 specification served by&#xA;the application itself:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;/api/doc&lt;/code&gt;&lt;/strong&gt; — interactive Swagger UI on your own instance (browse&#xA;endpoints, try requests — mind that &amp;ldquo;Try it out&amp;rdquo; executes &lt;em&gt;real&lt;/em&gt;&#xA;bookings).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;/api/doc.json&lt;/code&gt;&lt;/strong&gt; — the raw OpenAPI document, ready for code generators&#xA;or Postman/Insomnia import.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;essentials&#34;&gt;Essentials&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Amounts are &lt;strong&gt;integer cents&lt;/strong&gt;; timestamps are &lt;code&gt;YYYY-MM-DD HH:MM:SS&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Request bodies may be JSON or form-encoded. &lt;strong&gt;JSON bodies require&#xA;&lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/strong&gt; — without it the body is silently&#xA;ignored and you get a confusing &amp;ldquo;parameter missing&amp;rdquo; error.&lt;/li&gt;&#xA;&lt;li&gt;Errors use one envelope, where &lt;code&gt;class&lt;/code&gt; is the PHP exception class name&#xA;clients switch on:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;#34;class&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;App\\Exception\\TransactionBoundaryException&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;400&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Transaction boundary reached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Pagination is uneven (kept for compatibility):&lt;/strong&gt; &lt;code&gt;/api/transaction&lt;/code&gt;,&#xA;&lt;code&gt;/api/user/{id}/transaction&lt;/code&gt; and &lt;code&gt;/api/article&lt;/code&gt; accept&#xA;&lt;code&gt;?limit=…&amp;amp;offset=…&lt;/code&gt; with a &lt;strong&gt;default limit of 25&lt;/strong&gt; — forget &lt;code&gt;limit&lt;/code&gt; and&#xA;you silently see only 25 rows. &lt;code&gt;GET /api/user&lt;/code&gt; ignores both and always&#xA;returns &lt;strong&gt;all&lt;/strong&gt; users. The &lt;code&gt;/search&lt;/code&gt; endpoints accept &lt;code&gt;limit&lt;/code&gt; only.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;No idempotency mechanism&lt;/strong&gt;: retrying a timed-out &lt;code&gt;POST …/transaction&lt;/code&gt;&#xA;books twice. Reconcile via &lt;code&gt;GET /api/user/{id}/transaction&lt;/code&gt; after network&#xA;errors.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;No webhooks/push&lt;/strong&gt;: to watch for new bookings, poll&#xA;&lt;code&gt;GET /api/transaction&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;User routes accept a numeric id &lt;strong&gt;or the exact name&lt;/strong&gt;&#xA;(&lt;code&gt;GET /api/user/alice&lt;/code&gt;); the transaction routes take numeric ids only.&lt;/li&gt;&#xA;&lt;li&gt;There is &lt;strong&gt;no authentication&lt;/strong&gt; — the API trusts the network like the&#xA;kiosk trusts the room. CORS is deliberately wide open and there are no&#xA;rate limits. Both are consistent with the trusted-network model — and more&#xA;reasons not to expose it publicly.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;the-two-calls-every-integration-makes&#34;&gt;The two calls every integration makes&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# deposit 1.00 € with a comment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -X POST http://server/api/user/4/transaction &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -d &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#39;{&amp;#34;amount&amp;#34;: 100, &amp;#34;comment&amp;#34;: &amp;#34;cash box&amp;#34;}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# buy an article (server computes the price; amount must be omitted&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# or negative — sending a positive amount with articleId is rejected)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -X POST http://server/api/user/4/transaction &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -d &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#39;{&amp;#34;articleId&amp;#34;: 3, &amp;#34;quantity&amp;#34;: 1}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# → {&amp;#34;transaction&amp;#34;: {&amp;#34;id&amp;#34;: …, &amp;#34;amount&amp;#34;: -150, &amp;#34;article&amp;#34;: {…}, …}}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The scanner-script recipe (e.g. for a serial scanner or vending machine):&#xA;&lt;code&gt;GET /api/article?barcode=&amp;lt;scan&amp;gt;&lt;/code&gt; → take &lt;code&gt;articles[0].id&lt;/code&gt; →&#xA;&lt;code&gt;POST /api/user/{id}/transaction&lt;/code&gt; with &lt;code&gt;{&amp;quot;articleId&amp;quot;: …}&lt;/code&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>The screen by the fridge</title>
				<link>https://www.strichliste.org/docs/screen/</link>
				<pubDate>Fri, 12 Jun 2026 09:00:00 +0200</pubDate>
				<guid>https://www.strichliste.org/docs/screen/</guid>
				<description>&lt;p&gt;The server is half the job — the other half is the screen by the fridge.&#xA;strichliste&amp;rsquo;s part is ready: big touch buttons, works without JavaScript on&#xA;weak hardware, a dark theme that follows the device, and a screen that&#xA;returns to the user list when idle. Setting up the device itself is up to&#xA;you.&lt;/p&gt;&#xA;&lt;h2 id=&#34;hardware&#34;&gt;Hardware&lt;/h2&gt;&#xA;&lt;p&gt;A Raspberry Pi 4/5 with a 64-bit OS runs server &lt;em&gt;and&lt;/em&gt; fullscreen browser at&#xA;once (4 GB RAM comfortably; 2 GB if the server runs elsewhere). Older&#xA;32-bit Pis: run the server elsewhere and use the Pi only as a browser&#xA;terminal. Any old tablet pointed at the server works too — the UI works&#xA;without JavaScript, so even ancient browsers hold up.&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
